雙十一來了,別讓你的mongodb當機了

一線碼農發表於2015-10-12

 

        好久沒過來吹牛了,前段時間一直趕專案,沒有時間來更新部落格,專案也終於趕完了,接下來就要面臨雙十一這場驚心動魄的處女秀考驗,

我們專案中會有一個wcf叢集,而叢集地址則放在mongodb中,所以mongodb的核心地位可想而知,如果mongodb掛掉,整個專案也就陷入

癱瘓,想讓mongodb不當機,最簡單的方法就是要做雙機熱備,跟傳統的關係型資料庫的雙機熱備模式一樣,一個主伺服器,一個備份伺服器,

一個仲裁伺服器。如果熱備叢集中的主伺服器宕掉,會有仲裁伺服器參與投票來選出一臺作為主伺服器,我想這個大家都比較清楚,下面我們來

實戰一下,最後會奉獻原始碼。

 

一:搭建mongodb熱備叢集

1. 準備工作

  為了做到最簡化搭建,我就做一個主,一個備,一個仲裁就好了,然後最簡化配置資訊都放在mongodb.conf檔案中,如下圖:

 

從上圖中可以看到,三個mongodb,我建立了對應的三個資料夾來存放對應的三個db,其中“主伺服器”的埠為27000,“備伺服器“的埠為

27001,”仲裁伺服器“埠為27002。 具體mongodb.conf內容如下:

 

2. 開啟 “主伺服器” 【27000】

  

 

3.  開啟 “備伺服器” 【27001】

 

4.  開啟 “仲裁伺服器” 【27002】

 

現在三臺伺服器都開啟起來了,細心的你會發現,三個控制檯都有這麼一段英文單詞” replSet info you may need to run replSetInitiate“。。。

既然都這麼說了,我現在就去run這個func。

 

db.runCommand({
    "replSetInitiate":{
        "_id":"datamip",
        "members":[
            {
                "_id":1,
                "host":"127.0.0.1:27000"
            },
            {
                "_id":2,
                "host":"127.0.0.1:27001"
            }
        ]
    }
}) 

 

配置完了之後,然後我們把“仲裁伺服器【27002】”加入到“datamip”這個雙機熱備分叢集中。

 

rs.addArb( { host: "127.0.0.1:27002"} )

 

這個命令可以參考下官網的介紹:https://docs.mongodb.com/manual/reference/command/replSetInitiate/   好了,現在大致配置好了,接下

來我們用rs.Status()來檢視下當前“主,備,仲裁”的分佈情況。

 

從圖中你應該看到了【27000】成為了主伺服器,【27001】成為了備伺服器,【27002】成為了仲裁伺服器,到目前為止,搭建完成,是不是有

一個很爽的感覺呢???

 

三:使用驅動

  既然mongodb的雙機熱備已經做好了,我們驅動也必須支援,這樣我們才能夠嗨,對伐???其實在配置中使用也很簡單,裡面有一個

MongoClientSettings,你需要配置一下”ReplicaSetName“和”Servers“列表即可,核心程式碼如下:

 1         static MongoDBHelper()
 2         {
 3             var ips = connectionString.Split(';');
 4 
 5             var servicesList = new List<MongoServerAddress>();
 6 
 7             foreach (var ip in ips)
 8             {
 9                 var host = ip.Split(':')[0];
10                 var port = Convert.ToInt32(ip.Split(':')[1]);
11 
12                 servicesList.Add(new MongoServerAddress(host, port));
13             }
14 
15             setting = new MongoClientSettings();
16             setting.ReplicaSetName = "datamip";
17 
18             //叢集中的伺服器列表
19             setting.Servers = servicesList;
20         }

 

其中ips的資訊是配置在app.config中。

 <appSettings>
    <add key="mongodbServerList" value="127.0.0.1:27000;127.0.0.1:27001;127.0.0.1:27002"/>
  </appSettings>

 

然後我簡單的封裝了下mongodb。

  1 namespace DataMipCRM.Common
  2 {
  3     public class MongoDBHelper<T>
  4     {
  5         private static readonly string connectionString = ConfigurationManager.AppSettings["mongodbServerList"];
  6 
  7         static MongoClientSettings setting = null;
  8         MongoServer server = null;
  9 
 10         public string tableName = "person";
 11 
 12         public string databaseName = "test";
 13 
 14         static MongoDBHelper()
 15         {
 16             var ips = connectionString.Split(';');
 17 
 18             var servicesList = new List<MongoServerAddress>();
 19 
 20             foreach (var ip in ips)
 21             {
 22                 var host = ip.Split(':')[0];
 23                 var port = Convert.ToInt32(ip.Split(':')[1]);
 24 
 25                 servicesList.Add(new MongoServerAddress(host, port));
 26             }
 27 
 28             setting = new MongoClientSettings();
 29             setting.ReplicaSetName = "datamip";
 30 
 31             //叢集中的伺服器列表
 32             setting.Servers = servicesList;
 33         }
 34 
 35         public MongoDBHelper(string databaseName, string tableName)
 36         {
 37             this.databaseName = databaseName;
 38             this.tableName = tableName;
 39 
 40             server = new MongoClient(setting).GetServer();
 41         }
 42 
 43         public bool Remove(Expression<Func<T, bool>> func)
 44         {
 45             try
 46             {
 47                 var database = server.GetDatabase(databaseName);
 48 
 49                 var collection = database.GetCollection<T>(tableName);
 50 
 51                 var query = Query<T>.Where(func);
 52 
 53                 var result = collection.Remove(query);
 54 
 55                 return result.Response["ok"].AsInt32 > 0 ? true : false;
 56             }
 57             catch (Exception ex)
 58             {
 59                 return false;
 60             }
 61         }
 62 
 63         public bool RemoveAll()
 64         {
 65             try
 66             {
 67                 var database = server.GetDatabase(databaseName);   //mongodb中的資料庫
 68 
 69                 var collection = database.GetCollection<T>(tableName);
 70 
 71                 var result = collection.RemoveAll();
 72 
 73                 return result.Response["ok"].AsInt32 > 0 ? true : false;
 74             }
 75             catch (Exception ex)
 76             {
 77                 return false;
 78             }
 79         }
 80 
 81         #region 單條插入
 82         /// <summary>
 83         /// 單條插入
 84         /// </summary>
 85         /// <typeparam name="T"></typeparam>
 86         /// <param name="t"></param>
 87         public bool Insert(T t)
 88         {
 89             try
 90             {
 91                 var database = server.GetDatabase(databaseName);   //mongodb中的資料庫
 92 
 93                 var collection = database.GetCollection<T>(tableName);
 94 
 95                 var result = collection.Insert(t);
 96                 return result.DocumentsAffected > 0;
 97             }
 98             catch (Exception ex)
 99             {
100                 return false;
101             }
102         }
103         #endregion
104 
105         #region 單條覆蓋,如果不存在插入,如果存在覆蓋
106         /// <summary>
107         /// 單條覆蓋,如果不存在插入,如果存在覆蓋
108         /// </summary>
109         /// <typeparam name="T"></typeparam>
110         /// <param name="t"></param>
111         public bool Save(T t)
112         {
113             try
114             {
115                 var database = server.GetDatabase(databaseName);   //mongodb中的資料庫
116 
117                 var collection = database.GetCollection<T>(tableName);
118                 var result = collection.Save(t);
119                 return result.DocumentsAffected > 0;
120             }
121             catch (Exception ex)
122             {
123                 return false;
124             }
125         }
126         #endregion
127 
128         #region 批量插入
129         /// <summary>
130         /// 批量插入
131         /// </summary>
132         /// <typeparam name="T"></typeparam>
133         /// <param name="t"></param>
134         public bool Insert(IEnumerable<T> t)
135         {
136             try
137             {
138                 var database = server.GetDatabase(databaseName);   //mongodb中的資料庫
139 
140                 var collection = database.GetCollection<T>(tableName);
141 
142                 collection.InsertBatch(t);
143 
144                 return true;
145             }
146             catch (Exception ex)
147             {
148                 return false;
149             }
150         }
151         #endregion
152 
153         #region 批量查詢
154 
155         public List<T> Search(Expression<Func<T, bool>> func, bool forcemaster = false)
156         {
157             var list = new List<T>();
158 
159             try
160             {
161                 //是否強制使用 “主伺服器”
162                 if (forcemaster)
163                 {
164                     var database = server.GetDatabase(databaseName);   //mongodb中的資料庫
165 
166                     var collection = database.GetCollection<T>(tableName);
167                     list = collection.Find(Query<T>.Where(func)).ToList();
168                 }
169                 else
170                 {
171                     var database = server.GetDatabase(databaseName);    //mongodb中的資料庫
172 
173                     var collection = database.GetCollection<T>(tableName);
174 
175                     list = collection.Find(Query<T>.Where(func)).ToList();
176                 }
177             }
178             catch (Exception ex)
179             {
180                 throw;
181             }
182 
183             return list;
184         }
185 
186         #endregion
187 
188         #region 單條查詢
189         /// <summary>
190         /// 單條查詢
191         /// </summary>
192         public T SearchOne(Expression<Func<T, bool>> func, bool forcemaster = false)
193         {
194             T t = default(T);
195 
196             try
197             {
198                 if (forcemaster)
199                 {
200                     var database = server.GetDatabase(databaseName);   //mongodb中的資料庫
201 
202                     var collection = database.GetCollection<T>(tableName);
203 
204                     t = collection.FindOne(Query<T>.Where(func));
205                 }
206                 else
207                 {
208                     var database = server.GetDatabase(databaseName);   //mongodb中的資料庫
209 
210                     var collection = database.GetCollection<T>(tableName);
211 
212                     t = collection.FindOne(Query<T>.Where(func));
213                 }
214 
215                 return t;
216             }
217             catch (Exception ex)
218             {
219                 return t;
220             }
221         }
222         #endregion
223 
224         /// <summary>
225         /// 查詢所有資料
226         /// </summary>
227         /// <returns></returns>
228         public List<T> SearchAll()
229         {
230             var list = new List<T>();
231 
232             try
233             {
234                 var database = server.GetDatabase(databaseName);    //mongodb中的資料庫
235 
236                 var collection = database.GetCollection<T>(tableName);
237 
238                 list = collection.FindAll().ToList();
239 
240                 return list;
241             }
242             catch (Exception ex)
243             {
244                 return list;
245             }
246         }
247     }
248 }
View Code

 

四:測試一下

1. 首先向mongodb中插入一條記錄,dbname=mydb, tablename=test,插入後我們用mongodUVE看一下資料:

 1 namespace ConsoleApplication2
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             MongoDBHelper<MongodbCustomerModel> helper = new MongoDBHelper<MongodbCustomerModel>("mydb", "test");
 8 
 9             helper.Save(new MongodbCustomerModel()
10             {
11                 SendLastTime = DateTime.Now,
12                 ShopID = 1
13             });
14         }
15     }
16 
17     public class MongodbCustomerModel
18     {
19         public ObjectId _id { get; set; }
20 
21         public int ShopID { get; set; }
22 
23         public DateTime SendLastTime { get; set; }
24     }
25 }

 

2. 然後我把【27000】 這個primary關閉掉,通過rs.Status看看“主備情況”。

 

3. 接下來,我們繼續用mongodbHelper執行一下search,看是否能撈取到資料,如果可以,說明一臺機器掛了沒關係,這個“主備叢集”還是活的。

 

是不是很牛逼的感覺,雖然掛了一臺,我的客戶端程式還是可以繼續從mognodb中獲取到剛才插入的資料,好了,大概就說這麼多,洗洗睡了,

 

最後祝頂著雙十一壓力的兄弟們,一路平安。

 

--檔案下載--

相關文章