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

太變態了,每秒 10W 并發的無鎖緩存,你敢信?

開發 架構
司機地理位置信息會隨時變化,可能每幾秒鐘地理位置要修改一次,這一類業務,一般怎么實現呢?

有一類業務場景:

  • 超高吞吐量,每秒要處理海量請求;
  • 寫多讀少,大部分請求是對數據進行修改,少部分請求對數據進行讀取;

快狗打車,場景舉例:

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

這里要用到兩個接口:

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

void SetDriverInfo(long driver_id, DriverInfo info);

(2) 相對少量查詢司機信息:

DriverInfo GetDriverInfo(long driver_id); 

這一類業務,一般怎么實現呢?

具體到底層的實現,往往是一個Map內存緩存:

  • 查詢key定長,例如:司機ID;
  • 返回value也定長,例如:司機實體序列化后的二進制串;

即,類似這樣的一個kv緩存結構:

Map<driver_id, DriverInfo>

這個kv內存緩存是一個臨界資源,對它的并發訪問,有什么注意事項么?

臨界資源的訪問,需要注意加讀寫鎖,實施互斥。

以下,是加鎖寫入的偽代碼:

void SetDriverInfo(long driver_id, DriverInfo info){

         WriteLock (m_lock);

         Map<driver_id>= info;

         UnWriteLock(m_lock);

}

畫外音:假設info已經序列化。

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

DriverInfo GetDriverInfo(long driver_id){

         DriverInfo t;

         ReadLock(m_lock);

         t= Map<driver_id>;

         UnReadLock(m_lock);

         return t;

}

當吞吐量很高時,上述流程可能存在什么問題?

假設快狗打車有100w司機同時在線,每個司機每5秒更新一次經緯度狀態,那么每秒就有20w次寫并發操作。

假設快狗打車日訂單1000w個,平均每秒大概也有300個下單,對應到查詢并發量,大概每秒1000級別的并發讀操作。

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

有什么潛在的優化方法么?

鎖沖突之所以嚴重,是因為整個Map共用一把鎖,鎖的粒度太粗。

畫外音:可以認為是一個數據庫的“庫級別鎖”。

是否可能進行水平拆分,來降低鎖沖突呢?

答案是肯定的。

畫外音:類似于數據庫里的分庫,把一個庫鎖變成多個庫鎖,來提高并發,降低鎖沖突。

我們可以把1個Map水平切分成N個Map:

void SetDriverInfo(long driver_id, DriverInfo info){

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

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

         Map[i]<driver_id>= info;  // 操作第i個Map

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

}

如此優化,能否提高性能?

  • 一個Map變成了N個Map,每個Map的并發量,變成了1/N;
  • 同時,每個Map的數據量,變成了1/N;

所以理論上,鎖沖突會成平方指數降低,性能會提升。

有沒有可能,進一步細化鎖粒度,一個元素一把鎖呢?

答案也是肯定的。

畫外音:可以認為是一個數據庫的“庫級別鎖”,優化為“行級別鎖”。

不妨設driver_id是遞增生成的,并且假設內存比較大,此時可以把Map優化成Array,并把鎖的粒度細化到最細的,每個司機信息一個鎖:

void SetDriverInfo(long driver_id, DriverInfo info){

         index = driver_id;

         WriteLock (m_lock[index]);  //超級大內存,一條記錄一個鎖,鎖行鎖

         Array[index]= info; //driver_id就是Array下標

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

}

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

畫外音:數據量比較小的時候,可以一個元素一把鎖,典型的是連接池,每個連接用一把鎖表示連接是否可用。

還沒有方法進一步降低鎖沖突,提升并發量呢?

寫多讀少的業務,有一種優化方案:無鎖緩存,將鎖沖突降低到。

無鎖緩存,可能存在什么問題?

如果緩存不加鎖,讀寫吞吐量可以達到極限,但是多線程對緩存中同一塊定長數據進行寫操作時,有可能出現不一致的臟數據。

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

讀取時,獲取到了錯誤的數據,是不能接受的。

畫外音:作為緩存,允許cache miss,卻不允許讀臟數據。

臟數據是如何產生的?

不加鎖,在多線程并發寫時,可能出現以下情況:

  • 線程1對緩存進行操作,對key想要寫入value1;
  • 線程2對緩存進行操作,對key想要寫入value2;
  • 不加鎖,線程1和線程2對同一個定長區域進行一個并發的寫操作,可能每個線程寫成功一半,導致出現臟數據產生,最終的結果即不是value1也不是value2,而是一個亂七八糟的不符合預期的值value-unexpected;

如何解決上述問題呢?

本質上,這是一個數據完整性問題。

并發寫入的數據分別是value1和value2,讀出的數據是value-unexpected,數據被篡改,這本質上是一個數據完整性的問題。

通常如何保證數據的完整性呢?

例如:運維如何保證,從中控機分發到上線機上的二進制沒有被篡改?

md5。

又例如:即時通訊系統中,如何保證接受方收到的消息,就是發送方發送的消息?

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

“簽名”是一種常見的保證數據完整性的方案。

加入“簽名”保證數據的完整性之后,讀寫流程需要如何升級?

加上簽名之后,不但緩存要寫入定長value本身,還要寫入定長簽名(例如16bitCRC校驗):

  • 線程1對緩存進行操作,對key想要寫入value1,寫入簽名v1-sign;
  • 線程2對緩存進行操作,對key想要寫入value2,寫入簽名v2-sign;
  • 如果不加鎖,線程1和線程2對同一個定長區域進行一個并發的寫操作,可能每個線程寫成功一半,導致出現臟數據產生,最終的結果即不是value1也不是value2,而是一個亂七八糟的不符合預期的值value-unexpected,但簽名,一定是v1-sign或者v2-sign中的任意一個;

畫外音:16bit/32bit的寫可以保證原子性。

  • 數據讀取的時候,不但要取出value,還要像消息接收方收到消息一樣,校驗一下簽名,如果發現簽名不一致,緩存則返回NULL,即cache miss;

當然,對應到司機地理位置,除了內存緩存之前,肯定需要timer對緩存中的數據定期落盤,寫入數據庫,如果cache miss,可以從數據庫中讀取數據。

這個方案,巧不巧秒?

總結

業務場景:

  • 超高并發;
  • 寫多讀少;
  • 定長value;

可以用以下方法來提升吞吐量:

  • 水平拆分來降低鎖沖突,思路是:單庫變多庫;
  • Map轉Array的方式來最小化鎖沖突,一條記錄一個鎖,思路是:庫鎖變行鎖;
  • 無鎖,最大化并發,思路是:行鎖變無鎖,完整性與性能的折衷;
  • 通過簽名的方式保證數據的完整性,實現無鎖緩存,思路是:寫時寫簽名,讀時校驗簽名;

知其然,知其所以然。

思路比結論更重要。

責任編輯:趙寧寧 來源: 架構師之路
相關推薦

2020-12-21 09:57:33

無鎖緩存并發緩存

2024-08-06 08:13:26

2019-08-14 15:08:51

緩存存儲數據

2019-11-11 15:33:34

高并發緩存數據

2022-07-05 09:56:42

搜索搜索引擎

2022-11-10 16:39:59

架構系統技術架構

2024-11-01 08:31:56

2017-02-20 07:47:04

緩存HASH高并發

2020-12-21 07:36:15

緩存數據庫緩存層

2020-03-09 08:00:43

娛樂圈肖戰評論

2017-03-13 09:12:00

TCP數據結構請求包

2021-08-02 19:18:32

Redis緩存高并發

2020-09-29 10:09:43

Python文字識別編程語言

2021-01-13 14:42:36

GitHub代碼Java

2025-03-10 00:35:00

ManusAgentAI

2025-04-02 12:20:00

開發代碼函數

2025-05-12 04:20:00

Linux系統epoll

2019-04-03 08:10:17

代碼架構信息

2010-04-15 11:54:55

面試

2017-07-18 10:51:26

平板系統開源
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 夜夜久久| 在线观看精品 | 97高清国语自产拍 | av一二三区| 中文字幕不卡在线88 | 蜜桃免费一区二区三区 | 中文字幕视频在线 | 亚洲第一av | 91国内在线观看 | 日韩在线小视频 | 天堂资源最新在线 | 91在线精品视频 | 久久精品久久久久久 | 亚洲va在线va天堂va狼色在线 | 人和拘一级毛片c | 久久久久亚洲视频 | 日韩精品视频在线 | 狠狠做深爱婷婷综合一区 | 亚洲永久在线 | 国产精品视频免费看 | 美女视频久久 | 日韩成人免费视频 | 国产专区在线 | 蜜桃精品视频在线 | 涩涩视频在线观看 | 久久精品91久久久久久再现 | 在线精品观看 | 久久亚洲欧美日韩精品专区 | 色视频网站免费 | 亚洲精选一区二区 | 亚洲精品乱码久久久久v最新版 | 日本三级网站在线 | 久久久久久久亚洲精品 | 丁香五月网久久综合 | 黄色一级视频免费 | 天天草av | 在线观看亚洲 | 超碰av在线 | 国产精品久久久久久久午夜片 | 黄色日本视频 | 秋霞电影院午夜伦 |