上一篇文章简单的介绍了单机的情况下如何进行加锁,防止高并发带来的问题。
然而现实中,一般会高并发的应用,很少会单机部署。当用户量达到一定的程度,分布式、集群部署是必然的选择。在分布式部署的情况下,之前的单机锁还会有效吗?代码还是之前的代码:
private static object lck = new object(); /// <summary> /// 单机锁 /// </summary> /// <returns></returns> /// <exception cref="Exception"></exception> [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是其中比较常见的解决方案,以下是简单的实现代码:
/// <summary> /// 分布式锁 /// </summary> /// <returns></returns> /// <exception cref="Exception"></exception> [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。说明此次的分布式锁是有效的。
需要注意的是,要避免死锁,所以加锁的时候,要根据业务场景 设置 过期时间。
为了避免释放错误,加锁的时候也要加上身份认证。
好了此次关于锁的分享完毕。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章