加载中...

双十一来了,别让你的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“列表即可,核心代码如下:

static MongoDBHelper()
        {
            var ips = connectionString.Split(';');

            var servicesList = new List<MongoServerAddress>();

            foreach (var ip in ips)
            {
                var host = ip.Split(':')[0];
                var port = Convert.ToInt32(ip.Split(':')[1]);

                servicesList.Add(new MongoServerAddress(host, port));
            }

            setting = new MongoClientSettings();
            setting.ReplicaSetName = "datamip";

            //集群中的服务器列表
            setting.Servers = servicesList;
        }
其中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。

namespace DataMipCRM.Common
{
    public class MongoDBHelper<T>
    {
        private static readonly string connectionString = ConfigurationManager.AppSettings["mongodbServerList"];

        static MongoClientSettings setting = null;
        MongoServer server = null;

        public string tableName = "person";

        public string databaseName = "test";

        static MongoDBHelper()
        {
            var ips = connectionString.Split(';');

            var servicesList = new List<MongoServerAddress>();

            foreach (var ip in ips)
            {
                var host = ip.Split(':')[0];
                var port = Convert.ToInt32(ip.Split(':')[1]);

                servicesList.Add(new MongoServerAddress(host, port));
            }

            setting = new MongoClientSettings();
            setting.ReplicaSetName = "datamip";

            //集群中的服务器列表
            setting.Servers = servicesList;
        }

        public MongoDBHelper(string databaseName, string tableName)
        {
            this.databaseName = databaseName;
            this.tableName = tableName;

            server = new MongoClient(setting).GetServer();
        }

        public bool Remove(Expression<Func<T, bool>> func)
        {
            try
            {
                var database = server.GetDatabase(databaseName);

                var collection = database.GetCollection<T>(tableName);

                var query = Query<T>.Where(func);

                var result = collection.Remove(query);

                return result.Response["ok"].AsInt32 > 0 ? true : false;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public bool RemoveAll()
        {
            try
            {
                var database = server.GetDatabase(databaseName);   //mongodb中的数据库

                var collection = database.GetCollection<T>(tableName);

                var result = collection.RemoveAll();

                return result.Response["ok"].AsInt32 > 0 ? true : false;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        #region 单条插入
        /// <summary>
        /// 单条插入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public bool Insert(T t)
        {
            try
            {
                var database = server.GetDatabase(databaseName);   //mongodb中的数据库

                var collection = database.GetCollection<T>(tableName);

                var result = collection.Insert(t);
                return result.DocumentsAffected > 0;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        #endregion

        #region 单条覆盖,如果不存在插入,如果存在覆盖
        /// <summary>
        /// 单条覆盖,如果不存在插入,如果存在覆盖
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public bool Save(T t)
        {
            try
            {
                var database = server.GetDatabase(databaseName);   //mongodb中的数据库

                var collection = database.GetCollection<T>(tableName);
                var result = collection.Save(t);
                return result.DocumentsAffected > 0;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        #endregion

        #region 批量插入
        /// <summary>
        /// 批量插入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public bool Insert(IEnumerable<T> t)
        {
            try
            {
                var database = server.GetDatabase(databaseName);   //mongodb中的数据库

                var collection = database.GetCollection<T>(tableName);

                collection.InsertBatch(t);

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        #endregion

        #region 批量查询

        public List<T> Search(Expression<Func<T, bool>> func, bool forcemaster = false)
        {
            var list = new List<T>();

            try
            {
                //是否强制使用 “主服务器”
                if (forcemaster)
                {
                    var database = server.GetDatabase(databaseName);   //mongodb中的数据库

                    var collection = database.GetCollection<T>(tableName);
                    list = collection.Find(Query<T>.Where(func)).ToList();
                }
                else
                {
                    var database = server.GetDatabase(databaseName);    //mongodb中的数据库

                    var collection = database.GetCollection<T>(tableName);

                    list = collection.Find(Query<T>.Where(func)).ToList();
                }
            }
            catch (Exception ex)
            {
                throw;
            }

            return list;
        }

        #endregion

        #region 单条查询
        /// <summary>
        /// 单条查询
        /// </summary>
        public T SearchOne(Expression<Func<T, bool>> func, bool forcemaster = false)
        {
            T t = default(T);

            try
            {
                if (forcemaster)
                {
                    var database = server.GetDatabase(databaseName);   //mongodb中的数据库

                    var collection = database.GetCollection<T>(tableName);

                    t = collection.FindOne(Query<T>.Where(func));
                }
                else
                {
                    var database = server.GetDatabase(databaseName);   //mongodb中的数据库

                    var collection = database.GetCollection<T>(tableName);

                    t = collection.FindOne(Query<T>.Where(func));
                }

                return t;
            }
            catch (Exception ex)
            {
                return t;
            }
        }
        #endregion

        /// <summary>
        /// 查询所有数据
        /// </summary>
        /// <returns></returns>
        public List<T> SearchAll()
        {
            var list = new List<T>();

            try
            {
                var database = server.GetDatabase(databaseName);    //mongodb中的数据库

                var collection = database.GetCollection<T>(tableName);

                list = collection.FindAll().ToList();

                return list;
            }
            catch (Exception ex)
            {
                return list;
            }
        }
    }
}

四:测试一下

1. 首先向mongodb中插入一条记录,dbname=mydb, tablename=test,插入后我们用mongodUVE看一下数据:

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            MongoDBHelper<MongodbCustomerModel> helper = new MongoDBHelper<MongodbCustomerModel>("mydb", "test");

            helper.Save(new MongodbCustomerModel()
            {
                SendLastTime = DateTime.Now,
                ShopID = 1
            });
        }
    }

    public class MongodbCustomerModel
    {
        public ObjectId _id { get; set; }

        public int ShopID { get; set; }

        public DateTime SendLastTime { get; set; }
    }
}

2. 然后我把【27000】 这个primary关闭掉,通过rs.Status看看“主备情况”。

3. 接下来,我们继续用mongodbHelper执行一下search,看是否能捞取到数据,如果可以,说明一台机器挂了没关系,这个“主备集群”还是活的。

是不是很牛逼的感觉,虽然挂了一台,我的客户端程序还是可以继续从mognodb中获取到刚才插入的数据,好了,大概就说这么多,洗洗睡了,

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

--文件下载--


还没有评论.