双十一来了,别让你的mongodb宕机了 - 一线码农 - 博客园

来源: 双十一来了,别让你的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。

 

复制代码
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中获取到刚才插入的数据,好了,大概就说这么多,洗洗睡了,

 

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏