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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

聊一聊双十一背后的技术 - 不一样的秒杀技术, 裸秒

發布時間:2024/9/20 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 聊一聊双十一背后的技术 - 不一样的秒杀技术, 裸秒 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

聊一聊雙十一背后的技術 - 不一樣的秒殺技術, 裸秒

作者

digoal

日期

2016-11-17

標簽

PostgreSQL , 秒殺 , 裸秒 , ad lock


雙十一背后的技術系列文章

《聊一聊雙十一背后的技術 - 物流, 動態路徑規劃》

《聊一聊雙十一背后的技術 - 分詞和搜索》

《聊一聊雙十一背后的技術 - 強奸式秒殺技術實現》

《聊一聊雙十一背后的技術 - 毫秒分詞算啥, 試試正則和相似度》

云棲聚能聊 - 聊一聊雙十一背后的數據庫技術

背景

秒殺在商品交易中是一個永恒的話題,從雙十一,到一票難求,比的僅僅是手快嗎?

其實對于交易平臺來說,面對的不僅僅是人肉,還有很多腳本,外掛自動化的搶購系統,壓力可想而知。

秒殺的優化手段很多,就拿數據庫來說,有用排隊機制的,有用異步消息的,有用交易合并的。

今天,我要給大家介紹一種更極端的秒殺應對方法,裸秒。

(其實我很久以前就寫過類似的文章,趁雙十一跟大伙再練練)

目前可能只有PostgreSQL支持裸秒,也即是說,來吧,強暴我吧,一起上。 有點淫蕩,但是確實就是這么暴力。

PostgreSQL提供了一種ad lock,可以讓用戶盡情的釋放激情,以一臺32核64線程的機器為例,每秒可以獲取、探測約130萬次的ad lock。

試想一下,對單條記錄的秒殺操作,達到了單機100萬/s的處理能力后,秒殺算什么?100臺機器就能處理1億/s的秒殺請求,不行我的小心臟受不了了,下面聽我娓娓道來。

秒殺場景簡介

雖然秒殺已經很普遍了,但是出于文章的完整性,還是簡單介紹一下秒殺的業務背景。

例如,Iphone的1元秒殺,如果我只放出1臺Iphone,我們把它看成一條記錄,秒殺開始后,誰先搶到(更新這條記錄的鎖),誰就算秒殺成功。

對數據庫來說,秒殺瓶頸在于并發的對同一條記錄的多次更新請求,只有一個或者少量請求是成功的,其他請求是以失敗或更新不到記錄而告終。

例如有100臺IPHONE參與秒殺,并發來搶的用戶有100萬,對于數據庫來說,最小粒度的為行鎖,當有一個用戶在更新這條記錄時,其他的999999個用戶是在等待中度過的,以此類推。

除了那100個幸運兒,其他的用戶的等待都是無謂的,甚至它們不應該到數據庫中來浪費資源。

傳統的做法,使用一個標記位來表示這條記錄是否已經被更新,或者記錄更新的次數(幾臺Iphone)。

update tbl set xxx=xxx,upd_cnt=upd_cnt+1 where id=pk and upd_cnt+1<=5; -- 假設可以秒殺5臺

這種方法的弊端:

獲得鎖的用戶在處理這條記錄時,可能成功,也可能失敗,或者可能需要很長時間,(例如數據庫響應慢)在它結束事務前,其他會話只能等著。

等待是非常不科學的,因為對于沒有獲得鎖的用戶,等待是在浪費時間。

常用的秒殺優化手段

1. 一般的優化處理方法是先使用for update nowait的方式來避免等待,即如果無法即可獲得鎖,那么就不等待。

begin; select 1 from tbl where id=pk for update nowait; -- 如果用戶無法即刻獲得鎖,則返回錯誤。從而這個事務回滾。 update tbl set xxx=xxx,upd_cnt=upd_cnt+1 where id=pk and upd_cnt+1<=5; end;

這種方法可以減少用戶的等待時間,因為無法即刻獲得鎖后就直接返回了。

2. 合并請求,即將多個更新合并到一個更新的請求,這種做法需要修改內核,同時會破壞ACID,因為如果合并后的請求失敗了,會導致合并中的所有人的請求失敗。(與分組提交不一樣,分組提交是不會破壞ACID的)。

那么接下來我們看看AD LOCK。

什么是ad lock

手冊中的說明,AD LOCK是一種面向用戶的輕量級鎖,鎖的目標是一個整型,分為事務級和會話級的鎖,以及共享和排他鎖。

在單個DB內,只要鎖的整型值不一樣,就可以獲得鎖,如果值一樣,可以使用TRY來加鎖,沒有獲得則立即返回FALSE。

https://www.postgresql.org/docs/current/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS

Table 9-87. Advisory Lock Functions

NameReturn TypeDescription
pg_advisory_lock(key bigint)voidObtain exclusive session level advisory lock
pg_advisory_lock(key1 int, key2 int)voidObtain exclusive session level advisory lock
pg_advisory_lock_shared(key bigint)voidObtain shared session level advisory lock
pg_advisory_lock_shared(key1 int, key2 int)voidObtain shared session level advisory lock
pg_advisory_unlock(key bigint)booleanRelease an exclusive session level advisory lock
pg_advisory_unlock(key1 int, key2 int)booleanRelease an exclusive session level advisory lock
pg_advisory_unlock_all()void Releaseall session level advisory locks held by the current session
pg_advisory_unlock_shared(key bigint)booleanRelease a shared session level advisory lock
pg_advisory_unlock_shared(key1 int, key2 int)booleanRelease a shared session level advisory lock
pg_advisory_xact_lock(key bigint)voidObtain exclusive transaction level advisory lock
pg_advisory_xact_lock(key1 int, key2 int)voidObtain exclusive transaction level advisory lock
pg_advisory_xact_lock_shared(key bigint)voidObtain shared transaction level advisory lock
pg_advisory_xact_lock_shared(key1 int, key2 int)voidObtain shared transaction level advisory lock
pg_try_advisory_lock(key bigint)booleanObtain exclusive session level advisory lock if available
pg_try_advisory_lock(key1 int, key2 int)booleanObtain exclusive session level advisory lock if available
pg_try_advisory_lock_shared(key bigint)booleanObtain shared session level advisory lock if available
pg_try_advisory_lock_shared(key1 int, key2 int)booleanObtain shared session level advisory lock if available
pg_try_advisory_xact_lock(key bigint)booleanObtain exclusive transaction level advisory lock if available
pg_try_advisory_xact_lock(key1 int, key2 int)booleanObtain exclusive transaction level advisory lock if available
pg_try_advisory_xact_lock_shared(key bigint)booleanObtain shared transaction level advisory lock if available
pg_try_advisory_xact_lock_shared(key1 int, key2 int)booleanObtain shared transaction level advisory lock if available

通常數據庫支持的最小粒度的鎖(指開放給用戶的)是行鎖,行鎖相比LWLOCK,SPINLOCK等是非常重的,所以傳統的行鎖在秒殺中會成為非常大的瓶頸,包括鎖的等待。

ad lock的用途

ad lock的用途,除了我接下來要說的秒殺,其實還有很多用途,例如

并發的安全性檢查,

遞歸調用中用于UPSERT的場景,

業務邏輯設計中用來確保原子操作等。

ad lock的性能指標

因為AD LOCK很輕量化,不需要訪問數據,不需要執行冗長的代碼,所以很高效。

32核64線程機器測試可以達到131萬次/s的鎖請求。

vi test.sql \set id random(1,100000000) select pg_try_advisory_xact_lock(:id);pgbench -M prepared -n -r -P 1 -f ./test.sql -c 96 -j 96 -T 100transaction type: ./test.sql scaling factor: 1 query mode: prepared number of clients: 96 number of threads: 96 duration: 100 s number of transactions actually processed: 131516823 latency average = 0.072 ms latency stddev = 0.070 ms tps = 1314529.211060 (including connections establishing) tps = 1315395.309707 (excluding connections establishing) script statistics:- statement latencies in milliseconds:0.001 \set id random(1,100000000)0.074 select pg_try_advisory_xact_lock(:id);

ad lock用于秒殺的例子

在數據庫中,商品通常有唯一ID,我們可以對這個ID加鎖,(當然,如果對不同的表這個ID有重疊的可能,我們可以加偏移量或者其他的手段來達到無沖突)。

加鎖成功才會去對行加鎖,執行更新,這樣就能規避掉無效的行鎖等待,以及冗長的查詢代碼。

使用 AD LOCK 對單條記錄的并發更新處理QPS可以達到39.1萬/s,被秒殺的商品很快就會變成售罄狀態,不會再浪費數據庫的資源。

create table test(id int primary key, crt_time timestamp); insert into test values (1); vi test.sql update test set crt_time=now() where id=1 and pg_try_advisory_xact_lock(1);pgbench -M prepared -n -r -P 1 -f ./test.sql -c 64 -j 64 -T 100transaction type: ./test.sql scaling factor: 1 query mode: prepared number of clients: 64 number of threads: 64 duration: 100 s number of transactions actually processed: 39104368 latency average = 0.163 ms latency stddev = 0.216 ms tps = 391012.743072 (including connections establishing) tps = 391175.983419 (excluding connections establishing) script statistics:- statement latencies in milliseconds:0.163 update test set crt_time=now() where id=1 and pg_try_advisory_xact_lock(1);

此時數據庫主機還有66.2%的空閑CPU資源可用使用。

top - 13:12:43 up 51 days, 18:41, 2 users, load average: 1.12, 0.97, 0.78 Tasks: 1463 total, 28 running, 1435 sleeping, 0 stopped, 0 zombie Cpu(s): 24.5%us, 9.3%sy, 0.0%ni, 66.2%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 529321832k total, 235226420k used, 294095412k free, 903076k buffers Swap: 0k total, 0k used, 0k free, 62067636k cached

對比傳統的例子

傳統的消除等待的做法是這樣的,通過select for update nowait。

begin; select 1 from tbl where id=pk for update nowait; -- 如果用戶無法即刻獲得鎖,則返回錯誤。從而這個事務回滾。 update tbl set xxx=xxx,upd_cnt=upd_cnt+1 where id=pk and upd_cnt+1<=5; end;

在PG中,可以使用do語句,把以上合成到一個塊里面操作。

使用傳統的方法,每秒可以處理8.6萬。

vi test.sql do language plpgsql $$declare begin with t as (select * from test where id=1 for update nowait) update test set crt_time=now() from t where t.id=test.id; exception when others then return; end; $$ ;pgbench -M prepared -n -r -P 1 -f ./test.sql -c 64 -j 64 -T 100transaction type: ./test.sql scaling factor: 1 query mode: prepared number of clients: 64 number of threads: 64 duration: 100 s number of transactions actually processed: 8591222 latency average = 0.744 ms latency stddev = 0.713 ms tps = 85888.823884 (including connections establishing) tps = 85924.666940 (excluding connections establishing) script statistics:- statement latencies in milliseconds:0.744 do language plpgsql $$declare begin with t as (select * from test where id=1 for update nowait) update test set crt_time=now() from t where t.id=test.id; exception when others then return; end; $$ ;

CPU剩余54.5%

top - 13:13:48 up 51 days, 18:42, 2 users, load average: 8.14, 2.69, 1.37 Tasks: 1464 total, 21 running, 1442 sleeping, 0 stopped, 1 zombie Cpu(s): 41.7%us, 3.8%sy, 0.0%ni, 54.5%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 529321832k total, 235256052k used, 294065780k free, 903176k buffers Swap: 0k total, 0k used, 0k free, 62068308k cached

單個商品真實扣減吞吐

測試單個商品的真實扣減吞吐,我們看到QUERY QPS很高,但是真實的扣減當然不會有那么高,因為沒有拿到鎖就返回了。

postgres=# create table upd(id int primary key, cnt int8); postgres=# insert into upd values(1,0);vi t0.sql update upd set cnt=cnt-1 where id=1 and pg_try_advisory_xact_lock(1); \sleep 10 us.... vi t7.sql update upd set cnt=cnt-1 where id=1 and pg_try_advisory_xact_lock(1); \sleep 80 uspgbench -M prepared -n -r -P 1 -f t0.sql -f t1.sql -f t2.sql -f t3.sql -f t4.sql -f t5.sql -f t6.sql -f t7.sql -c 64 -j 64 -T 100postgres=# select * from upd;id | cnt ----+---------1 | -611249 (1 row)

單個商品,每秒扣減6112.49次,通常參與秒殺的商品,庫存都不會很多,通常在一千以內,否則就不叫秒殺了,用戶也犯不著來秒殺。

所以這個值是完全滿足現實需求的。

整個平臺所有商品真實扣減吞吐

假設整個平臺有1000萬商品,測試一下使用這種方法的整體扣減吞吐。

postgres=# create table upd(id int primary key, cnt int8); postgres=# insert into upd select generate_series(1,10000000), 0;vi test.sql \set id random(1,10000000) update upd set cnt=cnt-1 where id=:id and pg_try_advisory_xact_lock(:id);pgbench -M prepared -n -r -P 1 -f ./test.sql -c 64 -j 64 -T 100postgres=# select sum(cnt) from upd;sum ------------27233112 (1 row)

查看cnt得到真實的扣減情況,整個平臺來說,每秒約扣減272331.12個商品,即每秒有27萬個商品售出。

ad lock相比其他秒殺優化的優勢

使用AD LOCK可以使得CPU開銷最小化,等待最小化,從本文的測試CASE來看,單條記錄的更新可以達到39.1萬/s。

傳統的手段只能達到8.6萬/s。

使用AD LOCK不破壞ACID,單個請求單個事務,不影響其他的事務。

合并優化,本質上是破壞了ACID的,如果合并失敗,會導致所有相關的請求失敗。

如果你對PG感興趣,可以再了解一下

《德哥的PostgreSQL私房菜 - 史上最屌PG資料合集》

Count

本文為云棲社區原創內容,未經允許不得轉載,如需轉載請發送郵件至yqeditor@list.alibaba-inc.com;如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至:yqgroup@service.aliyun.com 進行舉報,并提供相關證據,一經查實,本社區將立刻刪除涉嫌侵權內容。

【云棲快訊】阿里巴巴小程序繁星計劃,20億補貼第一彈云應用立即開通購買,限量從速!??詳情請點擊

來源:https://yq.aliyun.com/articles/64351

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的聊一聊双十一背后的技术 - 不一样的秒杀技术, 裸秒的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 丝袜熟女一区二区三区 | 91婷婷在线 | 91原创国产| 91色啪| 中文字幕免费播放 | aaaa毛片| 人人干人人干 | 黄色小说图片视频 | 在线视频a| 毛片网在线观看 | 人妻一区二区三区免费 | 在线黄色免费网站 | 91丨porny丨对白 | 亚洲精品第三页 | 国产视频污在线观看 | 亚洲va欧美va国产综合久久 | 亚洲国产精品成人午夜在线观看 | 国产做爰xxxⅹ性视频国 | 中文字幕日本人妻久久久免费 | 国产免费无码一区二区 | 国产爱搞 | 亚洲av人无码激艳猛片服务器 | 香蕉在线影院 | 91爱视频 | 成人久色| 欧美日韩成人免费观看 | 日韩一区在线观看视频 | 天堂视频在线 | 日本精品不卡 | 黄色成年人| av香港经典三级级 在线 | 国产偷自拍视频 | 亚洲国产福利 | 亚洲影院在线 | 成人免费一区二区 | 手机av免费在线 | 亚洲熟女少妇一区二区 | 99久久久无码国产精品免费蜜柚 | www.国产麻豆| exo妈妈mv在线播放高清免费 | 欧美精品黑人猛交高潮 | 亚洲成人av一区二区 | 一极黄色大片 | 乳色吐息在线看 | 日本一区二区在线不卡 | 天天cao在线| 亚洲激情文学 | 亚洲av日韩精品久久久久久久 | 美脚の诱脚舐め脚视频播放 | 国产第一页在线观看 | 免费人妻一区二区三区 | 朝桐光在线观看 | 一区二区伊人 | 天天插天天操天天干 | 久久亚洲精选 | 中国毛片在线观看 | 国产69久久| 亚洲 高清 成人 动漫 | 日本黄色录像片 | 黄色理伦| 欧美午夜精品理论片 | 欧美精品国产 | 成人免费视频视频 | 黄色一级片免费播放 | 尤物自拍 | 亚洲精品粉嫩小泬 | 激情五月五月婷婷 | 亚洲精品亚洲人成人网 | 国产日韩视频在线观看 | 日本真人做爰免费视频120秒 | 国产懂色av| 国产在线播放一区二区三区 | 一本色道久久hezyo加勒比 | av专区在线 | 性一交一乱一色一视频麻豆 | 狠狠操在线 | 艳母免费在线观看 | 亚洲无吗视频 | av网站有哪些 | 在线播放你懂的 | 性欧美bbw | 91色在线播放 | 50一60岁老妇女毛片 | 91极品在线 | 在线视频www| 丰满秘书被猛烈进入高清播放在 | 国产麻豆剧传媒精品国产 | 精品免费一区二区三区 | 免费黄色小视频在线观看 | 精品成人无码久久久久久 | 久久亚洲高清 | 人妻丰满熟妇无码区免费 | 俄罗斯一级片 | 女人扒开双腿让男人捅 | 欧美一卡| 伦理自拍 | 免费污片软件 | 亚洲97色| 亚洲深夜视频 |