浅解.Net分布式锁的兑现

序言

清风万里的时节,周末应有和亲人朋友齐声消遣那多姿多彩的花花草草,或是懒洋洋的晒个太阳听听风声鸟鸣。无奈工作使然,理想使然,我回去啦公司,敲起啦键盘,撸起啦代码,程序狗的社会风气一片懊丧,一片低沉,愿天下所有努力的程序狗都梦想成真吧!!

归来正题,为啥搭建rabbitmq集群?rabbitmq集群有那么些方式?怎么着搭建Rabbitmq集群?rabbitmq镜像高可用策略有这个?

1、首先那款产品自己的助益众多,我们最看好的便是她的异步化提升系统抗峰值能力,然后便是系统及效果结构解耦,那么照此两点以来,他的在全部种类中的功能照旧重点的,那么如此紧要,当然要考虑他的高可用性,那么便有啊第二个难点的解答。

2、rabbitmq有3种方式,但集群格局是2种。详细如下:

  • 纯净格局:即单机处境不做集群,就独自运行一个rabbitmq而已。
  • 日常情势:默许方式,以四个节点(rabbit01、rabbit02)为例来拓展求证。对于Queue来说,音讯实体只设有于其中一个节点rabbit01(或者rabbit02),rabbit01和rabbit02八个节点仅有一样的元数据,即队列的构造。当音讯进入rabbit01节点的Queue后,consumer从rabbit02节点消费时,RabbitMQ会临时在rabbit01、rabbit02间展开音信传输,把A中的信息实体取出并通过B发送给consumer。所以consumer应尽可能连接每一个节点,从中取音讯。即对于同一个逻辑队列,要在几个节点建立物理Queue。否则无论consumer连rabbit01或rabbit02,出口总在rabbit01,会暴发瓶颈。当rabbit01节点故障后,rabbit02节点不可能取到rabbit01节点中还未消费的讯息实体。如果做了音信持久化,那么得等rabbit01节点恢复生机,然后才可被消费;倘使没有持久化的话,就会时有暴发音信丢失的气象。
  • 镜像情势:把必要的队列做成镜像队列,存在与多个节点属于RabbitMQ的HA方案该格局解决了一般形式中的难点,其实质和一般性形式差别之处在于,音信实体会再接再砺在镜像节点间共同,而不是在客户端取数据时临时拉取。该情势带来的副作用也很显著,除了下降系统性能外,尽管镜像队列数量过多,加之多量的音讯进入,集群内部的网络带宽将会被那种联合电视发表大大消耗掉。所以在对可靠性需要较高的场馆中适用。

序言 

本身早上有在铺子多呆会儿的习惯,所以广大夜晚本人都是最终一个离开公司的。当然也有一对同事,跟我同样喜欢在店堂多搞会儿。那篇小说就要从,二〇一八年年末一个多搞会的夜间说起,那是一个夜黑风高的夜幕,集团相应没有几人在啊,我司一技术男悠悠的走到我的私下,突然一句:“还没走啊?”!“我日,吓死我啦,你也没走啊”。此同事现在已被裁员,走呀,当晚他问我啊一个标题,至此时也不曾机会告知,前日我就在那里就大致描述下她随即的题材,其实达成起来几乎的无所谓,不过任何一个简练的难点往往都会有诸多中化解方案,探索找到最佳的化解方案,然后把细节做好,那就是技巧的精彩与乐趣所在。我那里只抛砖一下,希望能给自身老同事一个思路。

未雨绸缪集群环境安装RabbitMQ

自我的条件如下:

1、两台Centos7的机器,hostname分别为:F , G .

2、IP地址分别为:F—172.18.8.229 , G—172.18.8.224。

3、修改hosts文件如下,下边是G那台机械的hosts文件内容,F也急需如下配置:

[root@G bin]# cat /etc/hosts
127.0.0.1 G  localhost localhost.localdomain localhost4 localhost4.localdomain4 
::1       G  localhost localhost.localdomain localhost6 localhost6.localdomain6 

172.18.8.224 G
172.18.8.229 F

4、保障两台机械都可以互为ping通,如下图:

图片 1

好啊,环境到此就就能知足啦,接下去大家把rabbitmq装在2台机器上。

学学不看官方文档,那就别学呀,地址如下:http://www.rabbitmq.com/install-rpm.html

安装rabbitmq重视erlang环境,所以我们要先安装erlang环境。

图片 2

设置到位之后,下载rabbitmq的rpm包ivh即可。即使实在不会设置,Linux系统(二)软件的装置与卸载 里面有安装rabbitmq的实例,看官笑纳,实在不会装那参预左上方群,或者点击网页右上方的X吧,一定要相信不是您的错,是你与rabbitmq缘分不到。

安装启动进程中一旦现身error,那可参考上面多少个方案试试:

  • vim /etc/rabbitmq/enable_plugins :删除文件中的内容。
  • 翻开hosts文件是不是配备完善,互相是或不是足以ping通
  • 查六柱预测关端口是不是被占用,即便占用kill掉
  • 若果已经集群,那么要查阅所有集群中的/var/lib/rabbitmq/.erlang.cookie是还是不是同样。
  • 就算不设有上述文件,echo $HOME
    ,打开此文件夹,查看cookie文件是不是同样。
  • 重启电脑,幸免缓存数据配置未更新过来。

那边设置启动成功将来,来多少个常用的操作。

[root@G bin]# ./rabbitmq-server -deched  --后台启动服务
[root@G bin]# ./rabbitmqctl start_app  --启动服务
[root@G bin]# ./rabbitmqctl stop_app  --关闭服务
[root@G bin]# ./rabbitmq-plugins enable rabbitmq_management --启动web管理插件
[root@G bin]# ./rabbitmqctl add_user zlh zlh  --添加用户,密码
[root@G bin]# ./rabbitmqctl set_user_tags zlh administrator --设置zlh为administrator权限

比方您看到如下操作,即注脚启动成功啦,并且web管理页面的插件也启动成功,即使下边的6为0,则需求启动web管理插件

图片 3

那具体rabbitmqctl
的指令详细还要看官网文档:http://www.rabbitmq.com/man/rabbitmqctl.1.man.html

回来难点

先是有如下二张表,字段有IsBuyed(0:未利用,1:已利用),ProductNo:产品编号,Count:使用次数。

图片 4图片 5 

就是针对这张表做要求扩展的。

1、每一趟请求过来,都随意获得一个未使用过的产品编号

       public int GetNo()
        {
            using (IDbConnection conn = GetConn())
            {
                return conn.ExecuteScalar<int>("select top 1 ProductNo from  AStore where isBuyed=0 order by newid()");
            }
        }

2、每一次请求过来,即为使用产品四次,使用未选拔过的出品一遍需产品的IsBuyed=1
, Count=Count+1 。

 public bool UsingStore(int no)
        {
            using (IDbConnection conn = GetConn())
            {
                return conn.Execute("update AStore set isBuyed=1  where  and productNo=" + no) > 0;
            }
        }
        public bool MinusStore(int no)
        {
            using (IDbConnection conn = GetConn())
            {
                return conn.Execute("update BStore set [count]=[count]+1 where  and productNo=" + no) > 0;
            }
        }

3、写一个接口,布署在集群环境中,模拟请求3秒内一万个请求,来消费表中唯有10个的出品,最后结果为产品无法被频仍施用,如若存在很多次运用则产品的count将不止1,即为失利。同学要是您看看啊,难题自己给你回复的跟你说的没多少出入吧?

搭建rabbitmq的形似形式集群

 在上述的两台机器上安装rabbitmq落成未来,你可以见到您的机械中有如下1个文件。路径在$HOME中或者在/var/lib/rabbitmq中,文件名称为.erlang.cookie,他是一个隐藏文件。那么那文件存储的始末是什么,是做什么样用的啊?

这么说啊:RabbitMQ的集群是爱抚erlang集群,而erlang集群是通过那么些cookie进行通讯认证的,因而我们做集群的首先步就是干cookie。怎么干?

1、必须使集群中也就是F,G那两台机器的.erlang.cookie文件中cookie值一致,且权限为owner只读。

机器G中的Cookie:图片 6 机器F中的Cookie:图片 7

修改文件权限如下:

[root@F ~]# chmod 600 .erlang.cookie

2、查看集群状态,我的是曾经做好的。

[root@F bin]# ./rabbitmqctl cluster_status
Cluster status of node rabbit@F ...
[{nodes,[{disc,[rabbit@G]},{ram,[rabbit@F]}]},
 {running_nodes,[rabbit@G,rabbit@F]},
 {cluster_name,<<"rabbit@F">>},
 {partitions,[]},
 {alarms,[{rabbit@G,[]},{rabbit@F,[]}]}]

3、为止当前机械中rabbitmq的劳动

[root@F bin]# ./rabbitmqctl stop_app

4、把G中的rabbitmq插足到集群中来

[root@F bin]# ./rabbitmqctl join_cluster --ram rabbit@G

5、开启当前机械的rabbitmq服务

[root@F bin]# ./rabbitmqctl start_app

6、打开网页管理页面查看nodes

图片 8

那般便可以啊,你可以做下测试,验证下大家序言中说的常备方式的注明,那必须是杠杠对的。

.Net贯彻分布式锁

解决难题本身就一步步来推进,逐步深切,直至痛苦!!首先自己把同事操作数据方面的2个措施先贴出来。

public bool UsingStore(int no)
        {
            using (IDbConnection conn = GetConn())
            {
                return conn.Execute("update AStore set isBuyed=1  where productNo=" + no) > 0;
            }
        }
        public bool MinusStore(int no)
        {
            using (IDbConnection conn = GetConn())
            {
                return conn.Execute("update BStore set [count]=[count]+1 where  productNo=" + no) > 0;
            }
        }
        public int GetNo()
        {
            using (IDbConnection conn = GetConn())
            {
                return conn.ExecuteScalar<int>("select top 1 ProductNo from  AStore where isBuyed=0 order by newid()");
            }
        }

初涉茅庐的同窗也许会那样写接口。 

 public JsonResult Using1()
        {
            //获取未使用的产品编号
            var no = data.GetNo();
            if (no != 0)
            {
                //使用此产品
                data.MinusStore(no);
                data.UsingStore(no);
                return Json(new { success = true, ip = Request.ServerVariables.Get("Local_Addr").ToString() + " : " + HttpContext.Request.Url.Port }, JsonRequestBehavior.AllowGet);
            }
            else
            {
                //无产品可使用
                return Json(new { success = false, ip = Request.ServerVariables.Get("Local_Addr").ToString() + " : " + HttpContext.Request.Url.Port }, JsonRequestBehavior.AllowGet);
            }
        }

单机安排,1万个请求过来下啊。下边大家看看数据库的结果是什么?下边是3次已毕结果。每执行三次,执行一下底下的台本。

select * from [dbo].[AStore]
update AStore set isbuyed=0,count=0

表:astore 图片 9表:bstore图片 10 

由结果可以看出,单机安顿接口的情事下,还使有些出品被频仍开支,那很引人注目不相符同学的渴求。

那么大家越来越校正这一个接口,使用单机锁,锁此格局,来落实此接口,如下。

 public JsonResult Using()
        {
            string key = "%……¥%¥%77123吗,bnjhg%……%……&+orderno";
            //锁此操作          
            lock (key)
            {
                //获取未使用的产品编号
                var no = data.GetNo();
                if (no != 0)
                {
                    //使用此产品
                    data.MinusStore(no);
                    data.UsingStore(no);
                    return Json(new { success = true, ip = Request.ServerVariables.Get("Local_Addr").ToString() + " : " + HttpContext.Request.Url.Port }, JsonRequestBehavior.AllowGet);
                }
                else
                {
                    //此产品已使用过
                    return Json(new { success = false, ip = Request.ServerVariables.Get("Local_Addr").ToString() + " : " + HttpContext.Request.Url.Port }, JsonRequestBehavior.AllowGet);
                }
            }
        }

单机安顿此接口,1000个请求来测试此接口

图片 11

结果如下:

表:astore图片 12表:bstore图片 13 

哇塞,貌似同事的题材解决啦,哈哈,同事不急,那只是单机安插下的结果,即使把那个接口集群计划的话是哪些结果吗?

采用nginx做集群安插,搞5个站点做测试,对得起呢,同事?

 upstream servers{
       server 192.168.10.150:9000 weight=1; 
       server 172.18.11.79:1112 weight=1;
       server 192.168.10.150:1114 weight=1;
       server 192.168.10.150:1115 weight=1;
       server 192.168.10.150:1116 weight=1;  
 }
 server{
      keepalive_requests 1200;
      listen 8080;
      server_name abc.nginx3.com;
      location ~*^.+$ { 
          proxy_pass http://servers;
        }
}

再来看此接口运行的结果。结果如下:

表:astore图片 14表:bstore图片 15 

由图可以寓目,站点布局的集群对的住你,结果可令大家不如意啊,鲜明一个成品或者存在很多次开支的气象,那种锁对集群布署无用,并且还要排队,性能也跟不上来。大家来一发改写那几个接口。如下:

 public JsonResult Using3()
        {
            //锁此操作
            string key = "%……¥%¥%77123吗,bnjhg%……%……&+orderno";
            lock (key)
            {
                //获取未使用的产品编号
                var no = data.GetNo();
                //单号做为key插入memcached,值为true。
                var getResult = AMemcached.cache.Add("Miaodan_ProNo:" + no, true);
                if (getResult)
                {
                    //使用此产品
                    data.MinusStore(no);
                    data.UsingStore(no);
                    return Json(new { success = true, ip = Request.ServerVariables.Get("Local_Addr").ToString() + " : " + HttpContext.Request.Url.Port }, JsonRequestBehavior.AllowGet);
                }
                else
                {
                    //此产品已使用过
                    return Json(new { success = false, ip = Request.ServerVariables.Get("Local_Addr").ToString() + " : " + HttpContext.Request.Url.Port }, JsonRequestBehavior.AllowGet);
                }               
            }
        }

在集群下跑此接口看结果,结果如下。

表:astore图片 16表:bstore图片 17 

效果完成,同事可以安息啦。不过那里还有许多优化,和分布式锁带来的弊病,比如一单被分布式锁,锁住业务就是后续算法没有动用该产品,怎么优雅的释放锁,怎么化解碰着已经采取过的产品后再此分配新资源等等,当然也有其余部分贯彻方案,比如根据redis,zookeeper落成的分布式锁,我那边就不表明啦。同事,你好自尊崇,祝多生孩子,多挣钱啊。

搭建rabbitmq的镜像高可用形式集群

写到那里,接下去,有情侣要请我吃饭啊,我就兵贵神速赴会去啊,即使如此该有的也会都有的。go,go,go。

这一节要参考的文档是:http://www.rabbitmq.com/ha.html

率先镜像情势要借助policy模块,那个模块是做哪些用的吧?

policy华语来说是政策,策略的情致,那么她就是要设置,那么些Exchanges或者queue的数目须求复制,同步,怎样复制同步?对就是做这么些的。

此间有点内容的,我先上例子逐渐说:

[root@G ~]# ./rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'

参数意思为:

ha-all:为政策名称。

^:为匹配符,只有一个^代表匹配所有,^zlh为匹配名称为zlh的exchanges或者queue。

ha-mode:为匹配类型,他分为3种情势:all-所有(所有的queue),exctly-部分(需布置ha-params参数,此参数为int类型比如3,众多集群中的随机3台机械),nodes-指定(需配备ha-params参数,此参数为数组类型比如[“3rabbit@F”,”rabbit@G”]诸如此类指定为F与G那2台机械。)。

参考示例如下

图片 18

当然在web管理界面也能配置:

图片 19

布置完看队列如下,其中代表ha-haall的证实用自家的ha-haall策略啦,属于镜像格局,没有表示的就是平日情势:

图片 20 

总结

接下去是我们最喜爱的总计内容啦,内容有二,如下:

1、希望能关切自我其余的篇章。

2、博客里面有没有很驾驭的说通晓,或者你有更好的法门,那么欢迎参加左上方的2个交换群,大家共同学学商讨。

总结

接下去是豪门最快乐的下结论内容啦,内容有二,如下:

1、希望能关切自己任何的稿子。

2、博客里面有没有很了解的说通晓,或者您有更好的章程,那么欢迎插足左上方的2个沟通群,大家一并读书探讨。

发表评论

电子邮件地址不会被公开。 必填项已用*标注