好久沒過來吹牛了,前段時間一直趕專案,沒有時間來更新部落格,專案也終於趕完了,接下來就要面臨雙十一這場驚心動魄的處女秀考驗,
我們專案中會有一個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 }
四:測試一下
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中獲取到剛才插入的資料,好了,大概就說這麼多,洗洗睡了,
最後祝頂著雙十一壓力的兄弟們,一路平安。