• c# .NET 高级编程 高并发必备技巧(二) - 分布式锁


    上一篇文章简单的介绍了单机的情况下如何进行加锁,防止高并发带来的问题。
    然而现实中,一般会高并发的应用,很少会单机部署。当用户量达到一定的程度,分布式、集群部署是必然的选择。在分布式部署的情况下,之前的单机锁还会有效吗?代码还是之前的代码:

        private static object lck = new object();
        /// 
        /// 单机锁
        /// 
        /// 
        /// 
        [HttpGet]
        public  int Reduce1()
        {
            lock(lck)
            {
                int r = 0;
                string key = "stock";
                string stock = Rds.cli.Get(key);
                r = int.Parse(stock);
                if (r > 0)
                {
                    r--;
                    Rds.cli.Set(key, r);
                }
                else
                {
                    throw new Exception("库存用尽!");
                }
                return r;
            }
        } 
    

    今天再来测试一下,首先在本机模拟分布式的部署。
    api 部署3个,分别对应的端口 1020、1021、1022。使用nginx进行负载均衡转发,Nginx简单配置信息如下:

    Jmeter请求的接口是nginx的8000,请求线程和上一次一样100*10


    1000次请求后,再去查库存,发现库存并不为0。所以单机锁,在分布式的情况下,根本没起作用。

    所以在分布式的情况下,必须要借助第三方的中间件。Redis是其中比较常见的解决方案,以下是简单的实现代码:

        /// 
        /// 分布式锁
        /// 
        /// 
        /// 
        [HttpGet]
        public int Reduce2()
        {
            bool Lck1 =false;
            int r = 0;
            string identity=Guid.NewGuid().ToString(); //设置识别,避免错误释放锁。
            int OverTime = 10; //根据实际业务场景设置 超时时间,避免出现死锁
            try
            {
                Lck1 = Rds.cli.SetNx("lock", identity, OverTime);
                while (!Lck1)
                {
                    Lck1 = Rds.cli.SetNx("lock", identity, OverTime);
                }
                string key = "stock";
                string stock = Rds.cli.Get(key);
                r = int.Parse(stock);
                if (r > 0)
                {
                    r--;
                    Rds.cli.Set(key, r);
                }
                else
                {
                    throw new Exception("库存用尽!");
                }
            }
            catch (Exception ex)
            {
                throw;
            }
            finally
            {
                string id = Rds.cli.Get("lock");
                if(id==identity)
                {
                    Rds.cli.Del("lock");
                }
            }
            return r;
        }
    

    再次通过Jmeter 请求nginx 的端口。经过改造后的代码方法,在1000次请求后,库存已经为0。说明此次的分布式锁是有效的。

    需要注意的是,要避免死锁,所以加锁的时候,要根据业务场景 设置 过期时间。
    为了避免释放错误,加锁的时候也要加上身份认证。

    好了此次关于锁的分享完毕。

  • 相关阅读:
    ROS机器人移动到指定坐标点
    SSM宾馆客房管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目
    【微服务】Alibaba Cloud Linux环境下Docker以及MySQL安装
    go设计模式之工厂方法模式
    VSLAM特征之线特征&面特征
    Java(15)Object类
    我的创作纪念日 - 2048
    Matlab之并行程序设计实战教程
    业主方怎么管理固定资产
    聚合打车“战火”不停歇
  • 原文地址:https://www.cnblogs.com/pzscit/p/17647504.html