日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Orleans初战(用分布式解决高并发购物场景)

發(fā)布時(shí)間:2025/5/22 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Orleans初战(用分布式解决高并发购物场景) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

首先我們來(lái)定義這樣一個(gè)場(chǎng)景

? ? 商店有10種商品,每種商品有100件庫(kù)存。現(xiàn)在有20萬(wàn)人來(lái)?yè)屬?gòu)這些商品。

OK,那么問(wèn)題來(lái)了。要怎樣保證商品不會(huì)超賣……(要知道可能會(huì)出現(xiàn)20個(gè)人同時(shí)買(mǎi)A商品(或者更糟糕,畢竟后邊20萬(wàn)的大軍,隨時(shí)可能把商店變成廢墟),怎樣保證A商品的數(shù)量絕對(duì)安全)

?

按照大部分系統(tǒng)的解決方案是這樣的

  收到請(qǐng)求放入隊(duì)列,然后對(duì)隊(duì)列順序處理,這樣就避免了系統(tǒng)被瞬間擠爆而且不會(huì)超賣。

這種處理方式裝換成現(xiàn)實(shí)場(chǎng)景是這樣的:客戶到商店先領(lǐng)號(hào),不管買(mǎi)什么商品,都要排隊(duì),然后一個(gè)一個(gè)買(mǎi),直到所有的處理完

這個(gè)是不是弱爆了………………

這個(gè)解決方案也就相當(dāng)于一個(gè)售賣窗口,大家在那排隊(duì)買(mǎi),你能受得了嗎?

?

先看看現(xiàn)實(shí)商店怎樣解決的(存在即合理):客戶太多就加窗口唄,多雇員工,粗暴又簡(jiǎn)單的解決了問(wèn)題(當(dāng)然大家還是要排隊(duì),但是不是一個(gè)隊(duì)了,緩解了壓力提高了速度哦,老板賺到了更多的錢(qián))

Orleans閃亮登場(chǎng)…………

首先我要多開(kāi)幾臺(tái)服務(wù)器來(lái)處理客戶的請(qǐng)求,怎樣分配呢,要知道我的商品庫(kù)存數(shù)量必須保證安全,如果幾臺(tái)服務(wù)器操作一個(gè)商品那我們要想辦法做到對(duì)象的絕對(duì)同步(joab開(kāi)始也是這樣想的,后來(lái)我才知道是我想多了),要知道加的服務(wù)器處理數(shù)據(jù)同步的消耗實(shí)在太大得不償失啊(線程之間的數(shù)據(jù)安全使用線程鎖我們都閑消耗大,這個(gè)夸服務(wù)器就更別說(shuō)了)……

換個(gè)思路:加幾臺(tái)服務(wù)器,每臺(tái)服務(wù)器買(mǎi)不同的商品,例如:1號(hào)服務(wù)器賣a/b兩種商品,2號(hào)服務(wù)器賣c/d兩種商品…………以此類推,問(wèn)題解決了……

客戶消息說(shuō)買(mǎi)a商品,直接到1號(hào)服務(wù)器排隊(duì),買(mǎi)c商品就去2號(hào)服務(wù)器排隊(duì),(當(dāng)然這里服務(wù)器也要多線程,一樣的解決原理,a商品x線程排隊(duì),b商品y線程排隊(duì))

?

?

?

好了,從場(chǎng)景到解決辦法都出來(lái)了,現(xiàn)在要實(shí)現(xiàn):

照例我們開(kāi)始搭建環(huán)境(事例我就簡(jiǎn)單三層了,現(xiàn)實(shí)項(xiàng)目大家自己根據(jù)項(xiàng)目自己發(fā)揮啊)

?

訪問(wèn)關(guān)系:

?

Orleans.Samples.HostSilo就是個(gè)控制臺(tái)應(yīng)用程序,用于啟動(dòng)Orleans服務(wù)(Silo的啟動(dòng))也就相當(dāng)于售貨的窗口,不同服務(wù)器啟動(dòng)Orleans.Samples.HostSilo來(lái)處理排隊(duì)的請(qǐng)求(配置我就先不貼出來(lái)了,很多地方有)

Orleans.Samples.Grains你可以理解為商品,它在需要在窗口售賣

Orleans.Samples.StorageProvider這個(gè)怎么說(shuō)呢,首先Orleans.Samples.Grains是運(yùn)行在服務(wù)端的而且可以是有狀態(tài)的,我們?cè)趺磥?lái)管理他的狀態(tài),StorageProvider就對(duì)Grain的狀態(tài)做了擴(kuò)展(本例我就那這個(gè)狀態(tài)來(lái)做商品數(shù)據(jù)的讀寫(xiě),并且對(duì)商品扣庫(kù)存時(shí)也是直接對(duì)本Grain的state進(jìn)行操作)

?其它的幾個(gè)我就不講了大家一看就知道是什么了。

?

關(guān)鍵代碼

一、GoodsStorgeProvider

public class GoodsStorgeProvider : IStorageProvider{public Logger Log{get; set;}public string Name{get; set;}public Task ClearStateAsync(string grainType, GrainReference grainReference, IGrainState grainState){return TaskDone.Done;}public Task Close(){return TaskDone.Done;}public Task Init(string name, IProviderRuntime providerRuntime, IProviderConfiguration config){this.Name = nameof(GoodsStorgeProvider);this.Log = providerRuntime.GetLogger(this.Name);return TaskDone.Done;}public async Task ReadStateAsync(string grainType, GrainReference grainReference, IGrainState grainState){Console.WriteLine("獲取商品信息");var goodsNo = grainReference.GetPrimaryKeyString();using (var context = EntityContext.Factory()){grainState.State = context.GoodsInfo.AsNoTracking().FirstOrDefault(o => o.GoodsNo.Equals(goodsNo));}await TaskDone.Done;}public async Task WriteStateAsync(string grainType, GrainReference grainReference, IGrainState grainState){var model = grainState.State as GoodsInfo;using (var context = EntityContext.Factory()){var entity = context.GoodsInfo.FirstOrDefault(o => o.GoodsNo.Equals(model.GoodsNo));entity.Stock = model.Stock;await context.SaveChangesAsync();}}}

?前邊說(shuō)過(guò)了Grain是有狀態(tài)的,我定義了GoodsStorgeProvider管理商品的狀態(tài),商品的讀取我是直接從數(shù)據(jù)庫(kù)讀出然后賦值個(gè)它的State,那么知道這個(gè)Grain被釋放,這個(gè)State將一直存在,并且唯一,寫(xiě)入我就直接對(duì)商品的Stock進(jìn)行了賦值并且保存到數(shù)據(jù)庫(kù)(售賣商品,變更的就只有商品的數(shù)量)

?

二、GoodsInfoGrain

[StorageProvider(ProviderName = "GoodsStorgeProvider")]public class GoodsInfoGrain : Grain<GoodsInfo>, IGoodsInfoGrain{public Task<List<GoodsInfo>> GetAllGoods(){using (var context = EntityContext.Factory()){return Task.FromResult(context.GoodsInfo.AsNoTracking().ToList());}}public async Task<bool> BuyGoods(int count, string buyerUser){Console.WriteLine(buyerUser + ":購(gòu)買(mǎi)商品--" + this.State.GoodsName + " " + count + "個(gè)");if (count>0 && this.State.Stock >= count){this.State.Stock -= count;OrdersInfo ordersInfo = new OrdersInfo();ordersInfo.OrderNo = Guid.NewGuid().ToString("n");ordersInfo.BuyCount = count;ordersInfo.BuyerNo = buyerUser;ordersInfo.GoodsNo = this.State.GoodsNo;ordersInfo.InTime = DateTime.Now;using (var context = EntityContext.Factory()){context.OrdersInfo.Add(ordersInfo);await context.SaveChangesAsync();}await this.WriteStateAsync();Console.WriteLine("購(gòu)買(mǎi)完成");return await Task.FromResult(true);}else{Console.WriteLine("庫(kù)存不足--剩余庫(kù)存:" + this.State.Stock);return await Task.FromResult(false);}}}

我們有10種商品所以也就是會(huì)有10個(gè)Grain的實(shí)例保存在服務(wù)端,具體哪個(gè)Grain的實(shí)例代碼那種商品我們可以根據(jù)商品編號(hào)來(lái)劃分,GoodsInfoGrain繼承自IGoodsInfoGrain,IGoodsInfoGrain繼承自IGrainWithStringKey,IGrainWithStringKey的實(shí)例化需要一個(gè)string類型的key,我們就用商品的編號(hào)作為這個(gè)Grain實(shí)例的Key

這里我指定此Grain的StorageProvider為GoodsStorgeProvider,那么當(dāng)Grain被實(shí)例化的時(shí)候GoodsStorgeProvider也被實(shí)例化并且執(zhí)行ReadStateAsync,那么這個(gè)商品就在服務(wù)端存在了,不用每次去數(shù)據(jù)庫(kù)讀而是一直存在服務(wù)端

?

這里我們服務(wù)端是不需要特意人為的進(jìn)行排隊(duì)處理,Grain的實(shí)例我們可以理解為是線程安全的(微軟并不是使用線程鎖來(lái)做的這樣做太浪費(fèi)資源,有興趣的鞋童可以研究下源碼,這對(duì)你編程水平的提高很有作用)所以不會(huì)出現(xiàn)對(duì)象被同時(shí)調(diào)用,而是順序調(diào)用。

客戶端調(diào)用:

       var grain = GrainClient.GrainFactory.GetGrain<IGoodsInfoGrain>(goods.GoodsNo);bool result = grain.BuyGoods(count, buyerUser).Result;if (result){Addmsg(buyerUser + "--購(gòu)買(mǎi)商品" + goods.GoodsName + " " + count + "個(gè)");}else{Addmsg(buyerUser + "--購(gòu)買(mǎi)商品" + goods.GoodsName + " 庫(kù)存不足");}

大家可以看到,GrainClient.GrainFactory.GetGrain<IGoodsInfoGrain>(goods.GoodsNo)就是告訴服務(wù)端需要用哪個(gè)grain執(zhí)行我的操作,然后使用這個(gè)grain去調(diào)用BuyGoods方法購(gòu)買(mǎi)商品不需要告訴服務(wù)端商品的編號(hào),只需要買(mǎi)幾個(gè),購(gòu)買(mǎi)人是誰(shuí)就可以了,因?yàn)間rain在實(shí)例化(當(dāng)然還是那句話,Grain是有狀態(tài)的不需要每次實(shí)例化,)時(shí)就已經(jīng)定了它是哪種商品。

?

?

OK,源碼地址:https://github.com/zhuqingbo/Orleans.Samples

?今天舉例的這個(gè)場(chǎng)景是有破綻的,例如:有20萬(wàn)人都是來(lái)買(mǎi)一種商品的,那么就意味著只有一個(gè)服務(wù)器忙到死,但是其他的服務(wù)器都是空閑的,就像我商場(chǎng)雇了100個(gè)銷售人員,只有一個(gè)人在賣東西其他銷售都沒(méi)事,顧客要排隊(duì)很久…………這個(gè)是不允許出現(xiàn)的!!!我們應(yīng)該怎么解決?這個(gè)解決辦法我會(huì)在下次的事例中和大家分享,大家不妨在留言中提出一些自己的解決辦法,我們一起研究研究

?

轉(zhuǎn)載于:https://www.cnblogs.com/joab/p/5657851.html

總結(jié)

以上是生活随笔為你收集整理的Orleans初战(用分布式解决高并发购物场景)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。