浅解.Net分布式锁.Net/ASP开发工程师

/ 福清师大软件学院.Net/ASP开发工程师 / 2017-03-30




.net .Net分布式锁

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 MinusStore(int no)    {      using (IDbConnection conn = GetConn())      {        return conn.Execute("update AStore set isBuyed=1 , [count]=[count]+1 where productNo=" + no) > 0;      }    }

   

3、写一个接口,部署在集群环境中,模拟请求3秒内一万个请求,来消费表中只有10个的产品,最终结果为产品不能被多次使用,如果存在多次使用则产品的count将大于1,即为失败。同学如果你看到啦,问题我给你复原的跟你说的没多少出入吧?

.Net实现分布式锁



解决问题我就一步步来递进,慢慢深入,直至痛楚!!首先我把同事操作数据上面的2个方法先贴出来。

public bool MinusStore(int no)    {      using (IDbConnection conn = GetConn())      {        return conn.Execute("update AStore set isBuyed=1 , [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 Using()    {      //获取未使用的产品编号      var no = data.GetNo();      if (no != 0)      {        //使用此产品        data.MinusStore(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

   

一次:

.net .Net分布式锁    

2次:

.net .Net分布式锁    

3次:

.net .Net分布式锁    


由结果可以看出,单机部署接口的情况下,还使一些产品被多次消费,这很显然不符合同学的要求。

那么我们进一步改进这个接口,使用单机锁,锁此方法,来实现此接口,如下。

 public JsonResult Using()    {      //锁此操作      string key = "%……¥%¥%77123吗,bnjhg%……%……&orderno:" ;      lock (key)      {        //获取未使用的产品编号        var no = data.GetNo();        if (no != 0)        {          //使用此产品          data.MinusStore(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个请求来测试此接口


.net .Net分布式锁    


结果如下:


.net .Net分布式锁    


哇塞,貌似同事的问题解决啦,哈哈,同事不急,这只是单机部署下的结果,如果把这个接口集群部署的话是什么结果呢?

使用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;    }}

   

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

第一次

.net .Net分布式锁    

第二次

.net .Net分布式锁    


由图可以看出,站点部署的集群对的住你,结果可令我们不满意啊,显然一个产品还是存在多次消费的情况,这种锁对集群部署无用,并且还要排队,性能也跟不上来。我们来进一步改写这个接口。如下:

public JsonResult Using()    {      //锁此操作      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);          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);        }              }

   

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


.net .Net分布式锁    

.net .Net分布式锁    

.net .Net分布式锁    


功能实现,同事可以安息啦。不过这里还有很多优化,和分布式锁带来的弊端,比如一单被分布式锁,锁住业务即便后续算法没有使用该产品,怎么优雅的释放锁,怎么解决遇到已经使用过的产品后再此分配新资源等等,当然也有其他一些实现方案,比如基于redis,zookeeper实现的分布式锁,我这里就不说明啦。同事,你好自珍重,祝多生孩子,多挣钱啊。

猜你喜欢

.NET开发与 Java开发PK,与抉择



公众号,微信

汇鱼网海峡创乐汇
汇鱼网海峡创乐汇