加载中...

双十一来了,别让你的mongodb宕机了


好久没过来吹牛了,前段时间一直赶项目,没有时间来更新博客,项目也终于赶完了,接下来就要面临双十一这场惊心动魄的处女秀考验,

我们项目中会有一个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。

配置完了之后,然后我们把“仲裁服务器【27002】”加入到“datamip”这个双机热备分集群中。

这个命令可以参考下官网的介绍: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中。
  1. <appSettings>
  2. <add key="mongodbServerList" value="127.0.0.1:27000;127.0.0.1:27001;127.0.0.1:27002"/>
  3. </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中获取到刚才插入的数据,好了,大概就说这么多,洗洗睡了,

最后祝顶着双十一压力的兄弟们,一路平安。

--文件下载--


还没有评论.