網易視頻雲技術分享:Facebook memcache優化經驗

網易視頻雲是網易傾力打造的一款基於雲計算的分佈式多媒體處理集羣和專業音視頻技術,提供穩定流暢、低時延、高併發的視頻直播、錄製、存儲、轉碼及點播等音視頻的PAAS服務,在線教育、遠程醫療、娛樂秀場、在線金融等各行業及企業用戶只需經過簡單的開發即可打造在線音視頻平臺。現在,網易視頻雲的技術專家給大家分享一則技術文:Facebook memcache優化經驗

memcache是facebook的重要基礎設施,  有數據爲證: 緩存了T級記錄, 支持每秒G級別訪問次數, 單頁面經常訪問上千次memcache。 facebook從memcache節點、集羣、region、跨region等各層次對memcache做了大量優化和改造, 本文簡單介紹facebook在memcache節點和集羣層次做的一些優化工作。

降低延遲的方法:

並行請求。根據數據依賴關係構建DAG, 無依賴的數據批量發送到memache服務端, 根據統計平均每個請求包括24個key。

通訊優化。get操作使用UDP,刪除和更新操作使用TCP, 響應時間降低20%。

流量控制。通過滑動窗口控制單個客戶端發出的併發請求數目,避免服務器過載。

降低負載的方法:

Lease, 用於解決 memcache應用過程常見的兩個問題: (1)stale sets, 由於併發更新請求發生亂序, 導致memcache中存儲了舊的數據;  (2)thundering herds(驚羣), 讀寫率特別高的鍵值, 寫操作失效memcache時,大量讀操作不命中,導致後端壓力激增。 lease的原理是, memcache讀不命中時,返回一個64位token給客戶端, 只有當token有效時, 才允許客戶端加載數據到memcache。  服務端接收到delete請求時(寫操作之前應用一般會發送delete請求去失效memcache),則失效鍵值對應的所有token, 從而避免讀不命中的客戶端加載老數據到緩存。 memcache服務器限制每個鍵值10s內只產生一個token, token產生後10s內, 其他客戶端若讀不到鍵值,則等待一小段時間之後,再次重試。 由於新的value很快就加載到緩存中, 重試一次讀到最新value的概率非常大, 這就徹底避免了thundering herds問題。 根據facebook的實測結果, 在某些場景下有lease能將數據庫的qps從17K降低到1.3K。 此外, 刪除鍵值時,只在數據上做一個已刪除標誌,讓數據在緩存中保留一段時間。由於很多應用能夠容忍讀取舊數據,保留已刪除數據可進一步提高效率。

memcache pool。 memcache劃分成爲不同pool, 以應對應用負載的多樣性。

複製。 pool內部實現複製, 提高性能,  複製由客戶端控制。

處理節點失敗的策略:

保留大約1%節點組成一個Gutter集羣, 當memcache服務端無響應時, 轉而將數據緩存到gutter集羣中。 採用gutter而不是rehash到其他節點的原因是避免負載不均(例如一個key承擔了20%致其他節點級聯失敗。

單機memcached優化技術:

使用可擴展哈希,已經貢獻到社區。

多線程, 已經貢獻到社區。

每個線程獨立監聽一個UDP端口,避免衝突。

Adaptive Slab Allocator。 允許多個Slab之間相互替換內存。

優化之後的memcached性能驚人, 32字節GET達到1.8M次每秒( Xeon X5650 ,2.67GHZ,  12cores, 12hyperthreads, intel 82574L 千兆以太網, memcached服務器開了24個線程)。

參考資料:

《scaling memcache at facebook》

Categories:存儲Tags:

mysql 行級binlog複製 的 attribute promotion 分析

June 21st, 2013書包不見了Comments off

基本概念:

mysql在做主備複製時,如果主備庫的表定義不同, 也就意味着要做異構複製。 attribute promotion 就是當定義Binlog_Format = Row ,並且列屬性不同時,slave端在apply binlog時做的結構轉換。

按照官方文檔來說,在mysql-5.1.21版本開始支持不同表定義之間的複製,主備上列的數目可以不同,屬性也可以不同。列數目不同,意味着master的列數目要小於等於slave的列數目,兩者的列順序要一致,slave額外的列需要有defaults值.

主要來看列屬性的不同的情況:

在5.1版本中:

row binlog 只支持類似於char(10) 到 char(25) 這樣的複製,不允許不同int之間的轉換,也不支持char類型的和大對象轉換,只有在binlog中使用相同類型表示的列屬性間可以轉換。並且只支持master端列寬小於slave端的轉換方式,而反之會導致truncate的轉換是不被支持的。其次所有的前綴唯一索引,必須保證主備的前綴長度一致(否則會導致唯一性錯誤)

5.1支持的轉換類型 (來自官方文檔)

From (Master)

To (Slave)

BINARY    CHAR    

BLOB    TEXT    

CHAR    BINARY    

DECIMAL    NUMERIC    

NUMERIC    DECIMAL    

TEXT    BLOB    

VARBINARY    VARCHAR    

VARCHAR    VARBINARY    

5.1 不支持的轉換類型:

INT (including TINYINT, SMALLINT, MEDIUMINT, BIGINT).

SET or ENUM.

FLOAT or DOUBLE.

All of the data types relating to dates, times, or both: DATE, TIME, DATETIME, TIMESTAMP, and YEAR.

5.5.3版本開始,mysql按照之前mysql cluster的做法,引入了row binlog 的異構複製

row binlog 開始支持更多種類的列屬性轉換:

引入新參數 slave_type_conversion ,可以設置4個值 ALL_LOSSY(數據被truncate), ALL_NON_LOSSY(不需要被truncate的轉換), ALL_LOSSY,ALL_NON_LOSSY(可以兼容以上兩種轉換),  EMPTY(不支持屬性轉換)

5.5 支持的轉換類型(來自官方文檔)

Between any of the integer types TINYINT, SMALLINT, MEDIUMINT, INT, and BIGINT.

Between any of the decimal types DECIMAL, FLOAT, DOUBLE, and NUMERIC.

Between any of the string types CHAR, VARCHAR, and TEXT, including conversions between different widths.(不同字符集列之間不支持複製, 會出現主備不一致的狀態)

Between any of the binary data types BINARY, VARBINARY, and BLOB, including conversions between different widths.

Between any 2 BIT columns of any 2 sizes.

分析行級binlog attribute promotion的源代碼

以下以mysql-5.5.22爲例,主要的入口函數爲 sql/log_event.cc 中的 Rows_log_event::do_apply_event(Relay_log_info const *rli),在打開表並加完鎖之後需要檢查是否需要轉換。

TABLE *conv_table;

if (!ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli),

ptr->table, &conv_table))

{

...

}

ptr->m_conv_table= conv_table;

mysql 遍歷所有binlog涉及的表,檢測主庫binlog傳過來的表信息是否和當前slave端的表定義相吻合。如果需要進行列屬性轉換,則爲attribute promote 建立一張內存的臨時表來完成,否則傳出的conv_table爲NULL

compatible_with() 方法流程

1. 檢測主備庫的最小列數

2. 針對這些列進行是否能轉換的檢測can_convert_field_to()

a.  判斷field->real_type 是否相等

b.  如果real type 相等:

i.   判斷metadata是否爲0,metadata的size取決於field的real type(例如固定大小的int 類型metaData就爲0,而char,varchar類型都有)

ii.  如果metadata爲0,直接返回成功,否則的話要比較主備兩列的field size 再調用is_conversion_ok()

(i) 根據slave_type_conversion 參數來判斷是否能進行轉換

c.  如果real type 不相等,又沒有設置slave_type_conversion(也就是採用默認值EMPTY),返回上層錯誤

d.  判斷不同用類型之間能否轉換(int之間,char到text等等) 先比較列的長度 compare_length()

i.    調用 max_display_length() 方法獲得列的最大長度

再判斷列類型能否轉 is_conversion_ok()

3. 如果檢測出結果需要轉換,並且臨時表爲NULL,則建立一張臨時轉換表create_conversion_table()

4. 如果檢測到列類型不能轉換,向上層拋錯

5. 設置臨時轉換表中的屬性類型

在設置完臨時表convert table之後,真正使用是在unpack_current_row 中調用 rpl_record.cc 中的unpack_row

unpack_row () 方法流程:

1. 根據本地表起始指針和結束指針,依次獲取每個屬性

a. 判斷對應的convert_table 是否是NULL, 如果不是NULL則採用convert_table的列,否則採用原本slave 表本身的列, 暫時稱這列爲f

b. 檢測f列的bitmap,並設置null_bits 和 null_mask, 如果有必要的話,設置default值

c. 調用Field::unpack 方法,解析master傳過來的binlog數據內容, 拷貝到f列

d. 如果是該列是轉換列那麼source 和target 各自根據系統字符集開闢一塊buffer, 此處是做真正的列類型轉換, convert列和master一致,這裏採用一個臨時的Copy_field做轉換,Copy_field是mysql專門用作列轉換的輔助類,通過不同的source和target列類型,設置轉換函數指針,將convert table中的數據拷貝到最終的slave對應的列中

i.         copy.set(*field_ptr, f, TRUE);     設置轉換類的各個參數,包括轉換函數

ii.        (*copy.do_copy)(&copy);  做拷貝操作

2. 將master data 中複製用不到的那些列丟棄

3. 設置master side 的記錄長度

自此attribute promotion 的主要流程完成。

更多技術交流,請關注網易視頻雲哦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章