成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

太變態(tài)了,每秒 10W 并發(fā)的無(wú)鎖緩存,你敢信?

開(kāi)發(fā) 架構(gòu)
司機(jī)地理位置信息會(huì)隨時(shí)變化,可能每幾秒鐘地理位置要修改一次,這一類業(yè)務(wù),一般怎么實(shí)現(xiàn)呢?

有一類業(yè)務(wù)場(chǎng)景:

  • 超高吞吐量,每秒要處理海量請(qǐng)求;
  • 寫(xiě)多讀少,大部分請(qǐng)求是對(duì)數(shù)據(jù)進(jìn)行修改,少部分請(qǐng)求對(duì)數(shù)據(jù)進(jìn)行讀取;

快狗打車,場(chǎng)景舉例:

  • 司機(jī)地理位置信息會(huì)隨時(shí)變化,可能每幾秒鐘地理位置要修改一次;
  • 用戶打車的時(shí)候查看某個(gè)司機(jī)的地理位置,查詢地理位置的頻率相對(duì)較低;

這里要用到兩個(gè)接口:

(1) 大量修改司機(jī)信息:

void SetDriverInfo(long driver_id, DriverInfo info);

(2) 相對(duì)少量查詢司機(jī)信息:

DriverInfo GetDriverInfo(long driver_id); 

這一類業(yè)務(wù),一般怎么實(shí)現(xiàn)呢?

具體到底層的實(shí)現(xiàn),往往是一個(gè)Map內(nèi)存緩存:

  • 查詢key定長(zhǎng),例如:司機(jī)ID;
  • 返回value也定長(zhǎng),例如:司機(jī)實(shí)體序列化后的二進(jìn)制串;

即,類似這樣的一個(gè)kv緩存結(jié)構(gòu):

Map<driver_id, DriverInfo>

這個(gè)kv內(nèi)存緩存是一個(gè)臨界資源,對(duì)它的并發(fā)訪問(wèn),有什么注意事項(xiàng)么?

臨界資源的訪問(wèn),需要注意加讀寫(xiě)鎖,實(shí)施互斥。

以下,是加鎖寫(xiě)入的偽代碼:

void SetDriverInfo(long driver_id, DriverInfo info){

         WriteLock (m_lock);

         Map<driver_id>= info;

         UnWriteLock(m_lock);

}

畫(huà)外音:假設(shè)info已經(jīng)序列化。

以下,是加鎖讀取的偽代碼:

DriverInfo GetDriverInfo(long driver_id){

         DriverInfo t;

         ReadLock(m_lock);

         t= Map<driver_id>;

         UnReadLock(m_lock);

         return t;

}

當(dāng)吞吐量很高時(shí),上述流程可能存在什么問(wèn)題?

假設(shè)快狗打車有100w司機(jī)同時(shí)在線,每個(gè)司機(jī)每5秒更新一次經(jīng)緯度狀態(tài),那么每秒就有20w次寫(xiě)并發(fā)操作。

假設(shè)快狗打車日訂單1000w個(gè),平均每秒大概也有300個(gè)下單,對(duì)應(yīng)到查詢并發(fā)量,大概每秒1000級(jí)別的并發(fā)讀操作。

在這樣的吞吐量下(每秒20w寫(xiě),1k讀),鎖m_lock會(huì)成為潛在瓶頸,導(dǎo)致Map訪問(wèn)效率極低。

有什么潛在的優(yōu)化方法么?

鎖沖突之所以嚴(yán)重,是因?yàn)檎麄€(gè)Map共用一把鎖,鎖的粒度太粗。

畫(huà)外音:可以認(rèn)為是一個(gè)數(shù)據(jù)庫(kù)的“庫(kù)級(jí)別鎖”。

是否可能進(jìn)行水平拆分,來(lái)降低鎖沖突呢?

答案是肯定的。

畫(huà)外音:類似于數(shù)據(jù)庫(kù)里的分庫(kù),把一個(gè)庫(kù)鎖變成多個(gè)庫(kù)鎖,來(lái)提高并發(fā),降低鎖沖突。

我們可以把1個(gè)Map水平切分成N個(gè)Map:

void SetDriverInfo(long driver_id, DriverInfo info){

         i = driver_id % N; // 水平拆分成N份,N個(gè)Map,N個(gè)鎖

         WriteLock (m_lock[i]);  //鎖第i把鎖

         Map[i]<driver_id>= info;  // 操作第i個(gè)Map

         UnWriteLock (m_lock[i]); // 解鎖第i把鎖

}

如此優(yōu)化,能否提高性能?

  • 一個(gè)Map變成了N個(gè)Map,每個(gè)Map的并發(fā)量,變成了1/N;
  • 同時(shí),每個(gè)Map的數(shù)據(jù)量,變成了1/N;

所以理論上,鎖沖突會(huì)成平方指數(shù)降低,性能會(huì)提升。

有沒(méi)有可能,進(jìn)一步細(xì)化鎖粒度,一個(gè)元素一把鎖呢?

答案也是肯定的。

畫(huà)外音:可以認(rèn)為是一個(gè)數(shù)據(jù)庫(kù)的“庫(kù)級(jí)別鎖”,優(yōu)化為“行級(jí)別鎖”。

不妨設(shè)driver_id是遞增生成的,并且假設(shè)內(nèi)存比較大,此時(shí)可以把Map優(yōu)化成Array,并把鎖的粒度細(xì)化到最細(xì)的,每個(gè)司機(jī)信息一個(gè)鎖:

void SetDriverInfo(long driver_id, DriverInfo info){

         index = driver_id;

         WriteLock (m_lock[index]);  //超級(jí)大內(nèi)存,一條記錄一個(gè)鎖,鎖行鎖

         Array[index]= info; //driver_id就是Array下標(biāo)

         UnWriteLock (m_lock[index]); // 解鎖行鎖

}

這個(gè)方案使得鎖沖突降到了最低,但鎖資源大增,在數(shù)據(jù)量非常大的情況下,內(nèi)存往往是裝不下的。

畫(huà)外音:數(shù)據(jù)量比較小的時(shí)候,可以一個(gè)元素一把鎖,典型的是連接池,每個(gè)連接用一把鎖表示連接是否可用。

還沒(méi)有方法進(jìn)一步降低鎖沖突,提升并發(fā)量呢?

寫(xiě)多讀少的業(yè)務(wù),有一種優(yōu)化方案:無(wú)鎖緩存,將鎖沖突降低到。

無(wú)鎖緩存,可能存在什么問(wèn)題?

如果緩存不加鎖,讀寫(xiě)吞吐量可以達(dá)到極限,但是多線程對(duì)緩存中同一塊定長(zhǎng)數(shù)據(jù)進(jìn)行寫(xiě)操作時(shí),有可能出現(xiàn)不一致的臟數(shù)據(jù)。

這個(gè)方案為了提高性能,犧牲了一致性。

讀取時(shí),獲取到了錯(cuò)誤的數(shù)據(jù),是不能接受的。

畫(huà)外音:作為緩存,允許cache miss,卻不允許讀臟數(shù)據(jù)。

臟數(shù)據(jù)是如何產(chǎn)生的?

不加鎖,在多線程并發(fā)寫(xiě)時(shí),可能出現(xiàn)以下情況:

  • 線程1對(duì)緩存進(jìn)行操作,對(duì)key想要寫(xiě)入value1;
  • 線程2對(duì)緩存進(jìn)行操作,對(duì)key想要寫(xiě)入value2;
  • 不加鎖,線程1和線程2對(duì)同一個(gè)定長(zhǎng)區(qū)域進(jìn)行一個(gè)并發(fā)的寫(xiě)操作,可能每個(gè)線程寫(xiě)成功一半,導(dǎo)致出現(xiàn)臟數(shù)據(jù)產(chǎn)生,最終的結(jié)果即不是value1也不是value2,而是一個(gè)亂七八糟的不符合預(yù)期的值value-unexpected;

如何解決上述問(wèn)題呢?

本質(zhì)上,這是一個(gè)數(shù)據(jù)完整性問(wèn)題。

并發(fā)寫(xiě)入的數(shù)據(jù)分別是value1和value2,讀出的數(shù)據(jù)是value-unexpected,數(shù)據(jù)被篡改,這本質(zhì)上是一個(gè)數(shù)據(jù)完整性的問(wèn)題。

通常如何保證數(shù)據(jù)的完整性呢?

例如:運(yùn)維如何保證,從中控機(jī)分發(fā)到上線機(jī)上的二進(jìn)制沒(méi)有被篡改?

md5。

又例如:即時(shí)通訊系統(tǒng)中,如何保證接受方收到的消息,就是發(fā)送方發(fā)送的消息?

發(fā)送方除了發(fā)送消息本身,還要發(fā)送消息的簽名,接收方收到消息后要校驗(yàn)簽名,以確保消息是完整的,未被篡改。

“簽名”是一種常見(jiàn)的保證數(shù)據(jù)完整性的方案。

加入“簽名”保證數(shù)據(jù)的完整性之后,讀寫(xiě)流程需要如何升級(jí)?

加上簽名之后,不但緩存要寫(xiě)入定長(zhǎng)value本身,還要寫(xiě)入定長(zhǎng)簽名(例如16bitCRC校驗(yàn)):

  • 線程1對(duì)緩存進(jìn)行操作,對(duì)key想要寫(xiě)入value1,寫(xiě)入簽名v1-sign;
  • 線程2對(duì)緩存進(jìn)行操作,對(duì)key想要寫(xiě)入value2,寫(xiě)入簽名v2-sign;
  • 如果不加鎖,線程1和線程2對(duì)同一個(gè)定長(zhǎng)區(qū)域進(jìn)行一個(gè)并發(fā)的寫(xiě)操作,可能每個(gè)線程寫(xiě)成功一半,導(dǎo)致出現(xiàn)臟數(shù)據(jù)產(chǎn)生,最終的結(jié)果即不是value1也不是value2,而是一個(gè)亂七八糟的不符合預(yù)期的值value-unexpected,但簽名,一定是v1-sign或者v2-sign中的任意一個(gè);

畫(huà)外音:16bit/32bit的寫(xiě)可以保證原子性。

  • 數(shù)據(jù)讀取的時(shí)候,不但要取出value,還要像消息接收方收到消息一樣,校驗(yàn)一下簽名,如果發(fā)現(xiàn)簽名不一致,緩存則返回NULL,即cache miss;

當(dāng)然,對(duì)應(yīng)到司機(jī)地理位置,除了內(nèi)存緩存之前,肯定需要timer對(duì)緩存中的數(shù)據(jù)定期落盤,寫(xiě)入數(shù)據(jù)庫(kù),如果cache miss,可以從數(shù)據(jù)庫(kù)中讀取數(shù)據(jù)。

這個(gè)方案,巧不巧秒?

總結(jié)

業(yè)務(wù)場(chǎng)景:

  • 超高并發(fā);
  • 寫(xiě)多讀少;
  • 定長(zhǎng)value;

可以用以下方法來(lái)提升吞吐量:

  • 水平拆分來(lái)降低鎖沖突,思路是:?jiǎn)螏?kù)變多庫(kù);
  • Map轉(zhuǎn)Array的方式來(lái)最小化鎖沖突,一條記錄一個(gè)鎖,思路是:庫(kù)鎖變行鎖;
  • 無(wú)鎖,最大化并發(fā),思路是:行鎖變無(wú)鎖,完整性與性能的折衷;
  • 通過(guò)簽名的方式保證數(shù)據(jù)的完整性,實(shí)現(xiàn)無(wú)鎖緩存,思路是:寫(xiě)時(shí)寫(xiě)簽名,讀時(shí)校驗(yàn)簽名;

知其然,知其所以然。

思路比結(jié)論更重要。

責(zé)任編輯:趙寧寧 來(lái)源: 架構(gòu)師之路
相關(guān)推薦

2020-12-21 09:57:33

無(wú)鎖緩存并發(fā)緩存

2024-08-06 08:13:26

2019-11-11 15:33:34

高并發(fā)緩存數(shù)據(jù)

2019-08-14 15:08:51

緩存存儲(chǔ)數(shù)據(jù)

2022-07-05 09:56:42

搜索搜索引擎

2022-11-10 16:39:59

架構(gòu)系統(tǒng)技術(shù)架構(gòu)

2024-11-01 08:31:56

2017-02-20 07:47:04

緩存HASH高并發(fā)

2020-03-09 08:00:43

娛樂(lè)圈肖戰(zhàn)評(píng)論

2017-03-13 09:12:00

TCP數(shù)據(jù)結(jié)構(gòu)請(qǐng)求包

2020-12-21 07:36:15

緩存數(shù)據(jù)庫(kù)緩存層

2020-09-29 10:09:43

Python文字識(shí)別編程語(yǔ)言

2021-08-02 19:18:32

Redis緩存高并發(fā)

2021-01-13 14:42:36

GitHub代碼Java

2025-03-10 00:35:00

ManusAgentAI

2025-04-02 12:20:00

開(kāi)發(fā)代碼函數(shù)

2025-05-12 04:20:00

Linux系統(tǒng)epoll

2010-04-15 11:54:55

面試

2017-07-18 10:51:26

平板系統(tǒng)開(kāi)源

2019-04-03 08:10:17

代碼架構(gòu)信息
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 午夜免费电影 | 6996成人影院网在线播放 | 日日摸日日添日日躁av | 九九久久久 | 午夜视频在线播放 | 亚洲一区亚洲二区 | 国产真实精品久久二三区 | 日本精品一区二区三区视频 | 91一区二区三区在线观看 | 一区二区三区在线看 | 亚洲人成人一区二区在线观看 | 国产精品99久久久久久久vr | 国产精品电影在线观看 | 综合网伊人 | 妞干网视频 | 久草在线高清 | 亚洲精品成人 | 国产国产精品久久久久 | 99久久精品国产麻豆演员表 | 精品国产欧美一区二区 | 日日夜夜天天综合 | 日韩精品视频在线观看一区二区三区 | 欧美成人高清 | 精品福利一区二区三区 | 欧美精品久久久久 | 粉嫩av在线 | 三级成人在线 | 欧美福利在线 | 久久久久久久久91 | 国产精品视频在线播放 | 欧美亚洲一区二区三区 | 欧美成人一区二区三区 | 在线免费观看a级片 | 天天色综网| 成人午夜网站 | 99热热99| 狠狠干天天干 | 久久久www成人免费无遮挡大片 | 亚洲精品大片 | 精品国产一区二区三区性色av | 久久久久久亚洲精品不卡 |