电商平台 都会有抢购的情况,比如 1元抢购。 而抢购 最重要的 就是库存,很多情况下 库存处理不好,就会出现超卖现象。
本文将用redis为缓存,StackExchange 框架,消息队列方式 实现分布式锁的情况
一,效果
先看效果,
窗体下单 构建高并发情况
开多个控制台应用程序 处理订单
二,配置Redis
1
2
3
4
5
6
7
8 1 <Redis.Service>
2 <DbConfig Name="Order_DBName" Hosts="127.0.0.1:6379" dbNum="2">
3
4 </DbConfig>
5 <DbConfig Name="Product_DbName" Hosts="127.0.0.1:6379" dbNum="1">
6
7 </DbConfig>
8
模拟用户下单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 1 private void button1_Click(object sender, EventArgs e)
2 {
3 var orderCount = Convert.ToInt32(txt_OrderCount.Text);
4 var productId = Convert.ToInt32(txt_ProductId.Text);
5
6 var productCount = Convert.ToInt32(txt_ProductCount.Text);
7
8 for (int i = 0; i < orderCount; i++)
9 {
10 RedisOrderModel cacheOrder = new RedisOrderModel()
11 {
12 Count = productCount,
13 OrderNo = (orderNo += 1).ToString(),
14 ProductId = productId
15 };
16 orderRedis.Push(cacheOrder);
17 }
18
19
20 }
21
控制台程序 处理订单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 1public void QueueList()
2 {
3 RedisOrderMessage redis = new RedisOrderMessage();
4 while (true)
5 {
6 try
7 {
8 var cacheOrder = redis.Pop();
9 if (cacheOrder == null)
10 {
11 Console.WriteLine("无订单,休息100毫秒");
12 Thread.Sleep(1000);
13 continue;
14 }
15
16 while (ThreadCount<=0)
17 {
18 Console.WriteLine("线程已满,休息100毫秒");
19 Thread.Sleep(100);
20 }
21 //ThreadCount--;
22 Thread thread = new Thread(new ThreadStart(cacheOrder.CreateOrder));
23 thread.Start();
24 Console.WriteLine("正在处理订单,休息100毫秒");
25 Thread.Sleep(100);
26 }
27 catch (Exception ex)
28 {
29 Console.WriteLine(ex.Message + "," + ex.StackTrace);
30 Thread.Sleep(1000);
31 }
32 finally
33 {
34 ThreadCount++;
35 }
36
37 }
38 }
39
使用分布式锁,判断库存是否足够
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 1 public void LockStore(string productId, int count)
2 {
3 var keyInfo = AddSysCustomKey(productId);
4
5 if (!Exists(keyInfo))
6 {
7 throw new Exception("商品缓存缓存不存在");
8 }
9 var redisConfig = ReadRedisConfig.GetRedisConfig(DB_Name);
10 var lockdb = redisConfig.GetDatabase(-1);
11 var db = redisConfig.GetDatabase();
12 var token = Environment.MachineName;
13 while (true)
14 {
15 //db.LockRelease(keyInfo, token);
16 var con = lockdb.LockTake(keyInfo, token, TimeSpan.FromSeconds(10.0), CommandFlags.None);
17 //var con = db.LockTake(keyInfo, token, TimeSpan.FromSeconds(20), CommandFlags.None);
18 if (con)
19 {
20 try
21 {
22 var product = ConvertObj<CacheProduct>(db.StringGet(keyInfo));
23 if (product.Count < count)
24 {
25 throw new Exception("数量不够,下单失败");
26 }
27 product.Count -= count;
28 var json = ConvertJson(product);
29 db.StringSet(keyInfo, json);
30
31 }
32 finally
33 {
34 lockdb.LockRelease(keyInfo, token);
35
36 }
37 break;
38 }
39 }
40
41 }
42
源码地址:
https://github.com/buruainiaaaa/CacheDemo.git