本篇將和大家分享一下秒殺商品活動架構(gòu),采用的架構(gòu)方案正如標(biāo)題名稱.NetCore+Jexus代理+Redis,由于精力有限所以這里只設(shè)計到商品添加,搶購,訂單查詢,處理隊列搶購訂單的功能;有不足或者不夠詳細(xì)的還請見諒,順手點(diǎn)個推薦也不錯;

a. 秒殺流程

b. 封裝StackExchange.Redis的使用類

c. Ubuntu16.04上使用Jexus搭建代理完成分布式部署

d. NetCore寫實(shí)時監(jiān)控隊列服務(wù)

秒殺架構(gòu)設(shè)計圖︿( ̄︶ ̄)︿三幅

1. 一般業(yè)務(wù)性架構(gòu)

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

 

2. 后端分布式架構(gòu)

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

 

3. 整站分布式

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

 

項目工程結(jié)構(gòu)描述

a. 該項目git開源地址: https://github.com/shenniubuxing3/SeckillPro ,線上效果地址: http://www.lovexins.com:3333/

b. SeckillPro.Web:面向用戶的web站點(diǎn),主要提供商品展示,秒殺搶購,搶購結(jié)果,訂單列表等功能;

c. SeckillPro.Api:主要處理秒殺活動的請求,然后加入到秒殺隊列中,以及訂單狀態(tài)的查詢接口;

d. SeckillPro.Server:處理秒殺隊列的服務(wù);根據(jù)Redis模糊匹配key的方式,開啟多個商品秒殺的任務(wù),并處理秒殺請求和改變訂單搶購狀態(tài);

e. SeckillPro.Com:集成公共的方法;這里面前有操作Redis的list,hash,string的封裝類;

SeckillPro.Web商品后臺管理

對于商品活動來說,商品維護(hù)是必不可少的,由于這里商品維護(hù)的信息比較少,并且這里只加入到了RedisDb中,所以就不直接上代碼了;一個列表,一個添加僅此而已;這里就不再貼代碼了,如果你感興趣可以去我的git上面看源碼: https://github.com/shenniubuxing3/SeckillPro/blob/master/SeckillPro/SeckillPro.Web/Controllers/HomeController.cs 

SeckillPro.Web用戶端商品列表+秒殺請求+用戶訂單列表

商品列表和訂單列表沒有可以太多說的,一般訂單系統(tǒng)都有這兩個列表;關(guān)鍵點(diǎn)在于訂單秒殺流程中,咋們來簡單分析下面向客戶秒殺的流程需要注意的事項:

a. 限制秒殺開始時間和結(jié)束時間(測試未限制)

b. 未開始活動限制提交按鈕不可點(diǎn)(測試未限制)

c. 獲取真實(shí)剩余庫存限制秒殺提交(獲取redis中商品hash存儲的真實(shí)剩余量)

d. 把客戶的秒殺請求轉(zhuǎn)移到另外的api集群,以此提高面向客戶端的web站點(diǎn)并發(fā)承載率(測試項目中我直接指定4545端口的api測試)

這里就不再貼代碼了,如果你感興趣可以去我的git上面看看這部分源碼: https://github.com/shenniubuxing3/SeckillPro/blob/master/SeckillPro/SeckillPro.Web/Controllers/HomeController.cs 

.NetCore寫處理秒殺活動隊列的服務(wù)

這個處理隊列服務(wù)處理流程:模糊匹配Redis中每種商品的隊列key-》開啟不同商品的處理隊列任務(wù)-》處理秒殺訂單-》更新庫存和秒殺訂單狀態(tài);

a. 模糊匹配Redis中每種商品的隊列key:這里采用的是StackExchange.Redis中指定redis原生命令的方法來獲取匹配隊列key,設(shè)計的代碼如下:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

 1 /// <summary> 2         /// 模糊匹配redis中的key 3         /// </summary> 4         /// <param name="paramArr"></param> 5         /// <returns></returns> 6         public async Task<List<string>> MatchKeys(params string[] paramArr) 7         { 8             var list = new List<string>(); 9             try10             {11                 var result = await this.ExecuteAsync("keys", paramArr);12 13                 var valArr = ((RedisValue[])result);14                 foreach (var item in valArr)15                 {16                     list.Add(item);17                 }18             }19             catch (Exception ex) { }20             return list;21         }22 23         /// <summary>24         /// 執(zhí)行redis原生命令25         /// </summary>26         /// <param name="cmd"></param>27         /// <param name="paramArr"></param>28         /// <returns></returns>29         public async Task<RedisResult> ExecuteAsync(string cmd, params string[] paramArr)30         {31             try32             {33                 var db = this.GetDb();34                 return await db.ExecuteAsync(cmd, paramArr);35             }36             catch (Exception ex) { }37             return default(RedisResult);38         }

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

b. 開啟不同商品的處理隊列任務(wù):通過Task.Factory.StartNew(action,object)方法開啟不同商品的處理秒殺訂單的任務(wù);

c. 更新庫存和秒殺訂單狀態(tài):由于搶購商品要求庫存剩余實(shí)時性,所以每處理一個搶購訂單,需要對該商品減去相應(yīng)的庫存和修改秒殺訂單的狀態(tài)方便用戶查看秒殺結(jié)果;

d. 處理隊列具體的實(shí)現(xiàn)代碼可以去git看下,個人覺得還是有用的:https://github.com/shenniubuxing3/SeckillPro/blob/master/SeckillPro/SeckillPro.Server/Program.cs

使用Jexus代理部署分布式站點(diǎn)和接口

這里部署的代理采用的是Jexus代理;作為在linux和unix上部署.net程序?qū)嵱玫墓ぞ?,真的很感謝jexus作者;首先本篇講解的部署環(huán)境是ubunt16.04x64(至于這么安裝jexus可以參考上一篇分享文章),為了更直觀的看出來效果我在服務(wù)器上拷貝了兩份SeckillPro.Web發(fā)布的站點(diǎn),他們代碼都是一樣的只是分別把_Layout.cshtml試圖模板中加入了端口7777和8888,我就用這兩個端口來測試jexus的代理效果;

測試方便直接分別在兩個復(fù)制站點(diǎn)中執(zhí)行如下終端命令:dotnet SeckillPro.Web.dll http://ip:端口 ;一個監(jiān)聽7777端口一個監(jiān)聽8888;執(zhí)行命令效果圖:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

監(jiān)聽7777和8888端口成功后,我們就可以直接在瀏覽器輸入:http://172.16.9.66:7777 訪問,正常情況下能夠看到如下圖示例:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

單個站點(diǎn)訪問沒問題了,下面開始配置jexus代理;只需要在jexus/siteconf的配置文件中(我這里是default配置文件),增加如下設(shè)置:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

注意reproxy參數(shù):

a. 第一個/表示根目錄,一般不變

b. 多個被代理地址使用‘,’隔開;

c. 被代理地址后面也同樣需要加/

此時我們配置完后,只需要啟動jexus就行了:./jws start (怎么啟動可以參考上一篇文章);當(dāng)啟動jws成功后,我們就能通過配置的80端口,來訪問SeckillPro.Web站點(diǎn)了,效果圖:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

至于代理分發(fā)的策略暫不在本章的討論范圍內(nèi),如果可以建議去jexus官網(wǎng)了解下;同樣對于Seckill.Api我們也可以這樣部署,這里部署了個秒殺線上地址,有興趣的朋友可以點(diǎn)擊試試:http://www.lovexins.com:3333/ (注:這里沒有使用代理)

封裝StackExchange.Redis的使用類StackRedis.cs

其實(shí)這個在之前已經(jīng)分享過了,只不過只有操作string和list的分裝;本篇測試涉及到訂單查詢和商品查詢等功能,所以這里我又?jǐn)U展了對hash的操作方法,可以說更豐富了吧,如果您正打算使用redis或許直接用我這個封裝類是個不錯的打算;

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

  1 public class StackRedis : IDisposable  2     {  3         #region 配置屬性   基于 StackExchange.Redis 封裝  4         //連接串 (注:IP:端口,屬性=,屬性=)  5         public string _ConnectionString = "127.0.0.1:6377,password=shenniubuxing3";  6         //操作的庫(注:默認(rèn)0庫)  7         public int _Db = 0;  8         #endregion  9  10         #region 管理器對象 11  12         /// <summary> 13         /// 獲取redis操作類對象 14         /// </summary> 15         private static StackRedis _StackRedis; 16         private static object _locker_StackRedis = new object(); 17         public static StackRedis Current 18         { 19             get 20             { 21                 if (_StackRedis == null) 22                 { 23                     lock (_locker_StackRedis) 24                     { 25                         _StackRedis = _StackRedis ?? new StackRedis(); 26                         return _StackRedis; 27                     } 28                 } 29  30                 return _StackRedis; 31             } 32         } 33  34         /// <summary> 35         /// 獲取并發(fā)鏈接管理器對象 36         /// </summary> 37         private static ConnectionMultiplexer _redis; 38         private static object _locker = new object(); 39         public ConnectionMultiplexer Manager 40         { 41             get 42             { 43                 if (_redis == null) 44                 { 45                     lock (_locker) 46                     { 47                         _redis = _redis ?? GetManager(this._ConnectionString); 48                         return _redis; 49                     } 50                 } 51  52                 return _redis; 53             } 54         } 55  56         /// <summary> 57         /// 獲取鏈接管理器 58         /// </summary> 59         /// <param name="connectionString"></param> 60         /// <returns></returns> 61         public ConnectionMultiplexer GetManager(string connectionString) 62         { 63             return ConnectionMultiplexer.Connect(connectionString); 64         } 65  66         /// <summary> 67         /// 獲取操作數(shù)據(jù)庫對象 68         /// </summary> 69         /// <returns></returns> 70         public IDatabase GetDb() 71         { 72             return Manager.GetDatabase(_Db); 73         } 74         #endregion 75  76         #region 操作方法 77  78         #region string 操作 79  80         /// <summary> 81         /// 根據(jù)Key移除 82         /// </summary> 83         /// <param name="key"></param> 84         /// <returns></returns> 85         public async Task<bool> Remove(string key) 86         { 87             var db = this.GetDb(); 88  89             return await db.KeyDeleteAsync(key); 90         } 91  92         /// <summary> 93         /// 根據(jù)key獲取string結(jié)果 94         /// </summary> 95         /// <param name="key"></param> 96         /// <returns></returns> 97         public async Task<string> Get(string key) 98         { 99             var db = this.GetDb();100             return await db.StringGetAsync(key);101         }102 103         /// <summary>104         /// 根據(jù)key獲取string中的對象105         /// </summary>106         /// <typeparam name="T"></typeparam>107         /// <param name="key"></param>108         /// <returns></returns>109         public async Task<T> Get<T>(string key)110         {111             var t = default(T);112             try113             {114                 var _str = await this.Get(key);115                 if (string.IsNullOrWhiteSpace(_str)) { return t; }116 117                 t = JsonConvert.DeserializeObject<T>(_str);118             }119             catch (Exception ex) { }120             return t;121         }122 123         /// <summary>124         /// 存儲string數(shù)據(jù)125         /// </summary>126         /// <param name="key"></param>127         /// <param name="value"></param>128         /// <param name="expireMinutes"></param>129         /// <returns></returns>130         public async Task<bool> Set(string key, string value, int expireMinutes = 0)131         {132             var db = this.GetDb();133             if (expireMinutes > 0)134             {135                 return db.StringSet(key, value, TimeSpan.FromMinutes(expireMinutes));136             }137             return await db.StringSetAsync(key, value);138         }139 140         /// <summary>141         /// 存儲對象數(shù)據(jù)到string142         /// </summary>143         /// <typeparam name="T"></typeparam>144         /// <param name="key"></param>145         /// <param name="value"></param>146         /// <param name="expireMinutes"></param>147         /// <returns></returns>148         public async Task<bool> Set<T>(string key, T value, int expireMinutes = 0)149         {150             try151             {152                 var jsonOption = new JsonSerializerSettings()153                 {154                     ReferenceLoopHandling = ReferenceLoopHandling.Ignore155     
  http://www.cnblogs.com/wangrudong003/p/7111789.html