【本博客属于原创,如需转载,请注明出处:gdoujkzz】
最近研究库存的相关,在高峰期经常出现超卖等等情况,最后根据采用是基于Redis来实现了分布式锁,特此拿出来和大家分享。
准备工作:centos7,Redis,Nginx,以及JMeter测试工具。
传统的单体架构
在传统的程序中,我们写了如下最简单对库存操作的代码如下:
下面是基于AspNetCore.WebAPI 创建的一个对库存进行操作(减少)的接口,我相信很多同志都能够写出这种加lock来保证高并发的时候,库存不会出现超卖,这种做法的性能问题,不属于我们这篇文章的讨论范围,我们要讨论的是,这种写法到底会不会造成超卖的情况出现呢?,如果这是传统的企业内部应用,单体架构,如下图所示,也能满足需求;
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using StackExchange.Redis; namespace WebApplication1.Controllers { [Route("api/inv")] [ApiController] public class InvController : ControllerBase { private static readonly object LockObject = new object(); private static readonly ConfigurationOptions Options = new ConfigurationOptions() { EndPoints = { { "192.168.232.132", 6379 } }, Password = "123456" }; [HttpGet] public ActionResult<string> Get() { string msg = null; lock (LockObject) { int invQty = GetInvQty(); if (invQty > 0) { invQty = invQty - 1; SetInvQty(invQty); msg = $"扣减成功,当前库存:{invQty}"; } else { msg = "扣减失败,库存不足"; } } Console.WriteLine(msg); return msg; } private int GetInvQty() { var qty = 0; using (var conn = ConnectionMultiplexer.Connect(Options)) { var db = conn.GetDatabase(); qty = Convert.ToInt32(db.StringGet("InvQty")); } return qty; } private void SetInvQty(int qty) { using (var conn = ConnectionMultiplexer.Connect(Options)) { var db = conn.GetDatabase(); db.StringSet("InvQty", qty); } } } }
随着业务的越来越复杂,这种单体架构的形式,已经满足不了我们的正常业务需求,很多公司演变成了下面这种架构模式;
分布式架构