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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

美团在Redis上踩过的一些坑-4.redis内存使用优化

發布時間:2024/8/26 数据库 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 美团在Redis上踩过的一些坑-4.redis内存使用优化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請注明出處哈:http://carlosfu.iteye.com/blog/2254154


?? ?

?一、背景: 選擇合適的使用場景 ? ?很多時候Redis被誤解并亂用了,造成的Redis印象:耗內存、價格成本很高: ? ?1.?為了“趕時髦”或者對于Mysql的“誤解”在一個并發量很低的系統使用Redis,將原來放在Mysql數據全部放在Redis中。 ? ? ?----(Redis比較適用于高并發系統,如果是一些復雜Mis系統,用Redis反而麻煩,因為單從功能講Mysql要更為強大,而且Mysql的性能其實已經足夠了。) ? ?2. 覺得Redis就是個KV緩存 ? ? ?-----(Redis支持多數據結構,并且具有很多其他豐富的功能) ? ?3. 喜歡做各種對比,比如Mysql, Hbase, Redis等等 ? ? -----(每種數據庫都有自己的使用場景,比如Hbase吧,我們系統的個性化數據有1T,此時放在Redis根本就不合適,而是將一些熱點數據放在Redis) ? ? 總之就是在合適的場景,選擇合適的數據庫產品。 ? 附贈兩個名言: Evan Weaver, Twitter, March 2009 寫道 Everything runs from memory in Web 2.0! Tim Gray 寫道 Tape is Dead, Disk is Tape, Flash is Disk, RAM Locality is king.
(磁帶已死,磁盤是新磁帶,閃存是新磁盤,隨機存儲器局部性是為王道) ?? 二、一次string轉化為hash的優化 1. 場景: ? ? 用戶id: userId, ? ? 用戶微博數量:weiboCount? ??
userId(用戶id) weiboCount(微博數)
1 2000
2

10

3

288

.... ...
1000000 1000
? 2. 實現方法: (1) 使用Redis字符串數據結構, userId為key, weiboCount作為Value (2) 使用Redis哈希結構,hashkey只有一個, key="allUserWeiboCount",field=userId,fieldValue= weiboCount (3) 使用Redis哈希結構, ?hashkey為多個, key=userId/100, field=userId%100, fieldValue= weiboCount 前兩種比較容易理解,第三種方案解釋一下:每個hashKey存放100個hash-kv,field=userId%100,也就是
userId hashKey field
1 0 1
2 0

2

3 0

3

... .... ...
99 0 99
100 1 0
101 1 1
.... ... ...
9999 99 99
100000 1000 0

?

注意:

為了排除共享對象的問題,在真實測試時候所有key,field,value都用字符串類型。

?

3. 獲取方法:

?

Java代碼??
  • #獲取userId=5003用戶的微博數??
  • (1)?get?u:5003??
  • (2)?hget?allUser?u:5003??
  • (3)?hget?u:50?f:3??
  • ?

    ?

    4. 內存占用量對比(100萬用戶 userId u:1~u:1000000)?

    ??

    Java代碼??
  • #方法一?Memory??
  • used_memory:118002640??
  • used_memory_human:112.54M??
  • used_memory_rss:127504384??
  • used_memory_peak:118002640??
  • used_memory_peak_human:112.54M??
  • used_memory_lua:36864??
  • mem_fragmentation_ratio:1.08??
  • mem_allocator:jemalloc-3.6.0??
  • ---------------------------------------------------??
  • #方法二?Memory??
  • used_memory:134002968??
  • used_memory_human:127.80M??
  • used_memory_rss:144261120??
  • used_memory_peak:134002968??
  • used_memory_peak_human:127.80M??
  • used_memory_lua:36864??
  • mem_fragmentation_ratio:1.08??
  • mem_allocator:jemalloc-3.6.0??
  • --------------------------------------------------------??
  • #方法三?Memory??
  • used_memory:19249088??
  • used_memory_human:18.36M??
  • used_memory_rss:26558464??
  • used_memory_peak:134002968??
  • used_memory_peak_human:127.80M??
  • used_memory_lua:36864??
  • mem_fragmentation_ratio:1.38??
  • mem_allocator:jemalloc-3.6.0??
  • ??

    ?那么為什么第三種能少那么多內存呢?之前有人說用了共享對象的原因,現在我將key,field,value全部都變成了字符串,仍然還是節約很多內存。

    ?之前我也懷疑過是hashkey,field的字節數少造成的,但是我們下面通過一個實驗看就清楚是為什么了。當我將hash-max-ziplist-entries設置為2并且重啟后,所有的hashkey都變為了hashtable編碼。

    ?同時我們看到了內存從18.36M變為了122.30M,變化還是很大的。

    ?

    Java代碼??
  • 127.0.0.1:8000>?object?encoding?u:8417??
  • "ziplist"??
  • 127.0.0.1:8000>?config?set?hash-max-ziplist-entries?2??
  • OK??
  • 127.0.0.1:8000>?debug?reload??
  • OK??
  • (1.08s)??
  • 127.0.0.1:8000>?config?get?hash-max-ziplist-entries??
  • 1)?"hash-max-ziplist-entries"??
  • 2)?"2"??
  • 127.0.0.1:8000>?info?memory??
  • #?Memory??
  • used_memory:128241008??
  • used_memory_human:122.30M??
  • used_memory_rss:137662464??
  • used_memory_peak:134002968??
  • used_memory_peak_human:127.80M??
  • used_memory_lua:36864??
  • mem_fragmentation_ratio:1.07??
  • mem_allocator:jemalloc-3.6.0??
  • 127.0.0.1:8000>?object?encoding?u:8417??
  • "hashtable"??
  • ?

    ?

    ?

    ?

    ?

    ? 內存使用量:

    ??

    ??

    5. 導入數據代碼(不考慮代碼優雅性,單純為了測試,勿噴) 注意: 為了排除共享對象的問題,這里所有key,field,value都用字符串類型。 ? Java代碼??
  • package?com.carlosfu.redis;??
  • ??
  • import?java.util.ArrayList;??
  • import?java.util.HashMap;??
  • import?java.util.List;??
  • import?java.util.Map;??
  • import?java.util.Random;??
  • ??
  • import?org.junit.Test;??
  • ??
  • import?redis.clients.jedis.Jedis;??
  • ??
  • /**?
  • ?*?一次string-hash優化?
  • ?*??
  • ?*?@author?carlosfu?
  • ?*?@Date?2015-11-8?
  • ?*?@Time?下午7:27:45?
  • ?*/??
  • public?class?TestRedisMemoryOptimize?{??
  • ??
  • ????private?final?static?int?TOTAL_USER_COUNT?=?1000000;??
  • ??
  • ????private?final?static?String?HOST?=?"127.0.0.1";??
  • ??
  • ????private?final?static?int?PORT?=?6379;??
  • ??
  • ????/**?
  • ?????*?純字符串?
  • ?????*/??
  • ????@Test??
  • ????public?void?testString()?{??
  • ????????int?mBatchSize?=?2000;??
  • ????????Jedis?jedis?=?null;??
  • ????????try?{??
  • ????????????jedis?=?new?Jedis(HOST,?PORT);??
  • ????????????List<String>?kvsList?=?new?ArrayList<String>(mBatchSize);??
  • ????????????for?(int?i?=?1;?i?<=?TOTAL_USER_COUNT;?i++)?{??
  • ????????????????String?key?=?"u:"?+?i;??
  • ????????????????kvsList.add(key);??
  • ????????????????String?value?=?"v:"?+?i;??
  • ????????????????kvsList.add(value);??
  • ????????????????if?(i?%?mBatchSize?==?0)?{??
  • ????????????????????System.out.println(i);??
  • ????????????????????jedis.mset(kvsList.toArray(new?String[kvsList.size()]));??
  • ????????????????????kvsList?=?new?ArrayList<String>(mBatchSize);??
  • ????????????????}??
  • ????????????}??
  • ????????}?catch?(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}?finally?{??
  • ????????????if?(jedis?!=?null)?{??
  • ????????????????jedis.close();??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?純hash?
  • ?????*/??
  • ????@Test??
  • ????public?void?testHash()?{??
  • ????????int?mBatchSize?=?2000;??
  • ????????String?hashKey?=?"allUser";??
  • ????????Jedis?jedis?=?null;??
  • ????????try?{??
  • ????????????jedis?=?new?Jedis(HOST,?PORT);??
  • ????????????Map<String,?String>?kvMap?=?new?HashMap<String,?String>();??
  • ????????????for?(int?i?=?1;?i?<=?TOTAL_USER_COUNT;?i++)?{??
  • ????????????????String?key?=?"u:"?+?i;??
  • ????????????????String?value?=?"v:"?+?i;??
  • ????????????????kvMap.put(key,?value);??
  • ????????????????if?(i?%?mBatchSize?==?0)?{??
  • ????????????????????System.out.println(i);??
  • ????????????????????jedis.hmset(hashKey,?kvMap);??
  • ????????????????????kvMap?=?new?HashMap<String,?String>();??
  • ????????????????}??
  • ????????????}??
  • ????????}?catch?(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}?finally?{??
  • ????????????if?(jedis?!=?null)?{??
  • ????????????????jedis.close();??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?segment?hash?
  • ?????*/??
  • ????@Test??
  • ????public?void?testSegmentHash()?{??
  • ????????int?segment?=?100;??
  • ????????Jedis?jedis?=?null;??
  • ????????try?{??
  • ????????????jedis?=?new?Jedis(HOST,?PORT);??
  • ????????????Map<String,?String>?kvMap?=?new?HashMap<String,?String>();??
  • ????????????for?(int?i?=?1;?i?<=?TOTAL_USER_COUNT;?i++)?{??
  • ????????????????String?key?=?"f:"?+?String.valueOf(i?%?segment);??
  • ????????????????String?value?=?"v:"?+?i;??
  • ????????????????kvMap.put(key,?value);??
  • ????????????????if?(i?%?segment?==?0)?{??
  • ????????????????????System.out.println(i);??
  • ????????????????????int?hash?=?(i?-?1)?/?segment;??
  • ????????????????????jedis.hmset("u:"?+?String.valueOf(hash),?kvMap);??
  • ????????????????????kvMap?=?new?HashMap<String,?String>();??
  • ????????????????}??
  • ????????????}??
  • ????????}?catch?(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}?finally?{??
  • ????????????if?(jedis?!=?null)?{??
  • ????????????????jedis.close();??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • }??
  • ? 三、結果對比 ?redis核心對象 數據類型 + 編碼方式 + ptr ?分段hash也不會造成drift
    方案 優點 缺點
    string

    直觀、容易理解

  • 內存占用較大
  • key值分散、不變于計算整體
  • hash

    直觀、容易理解、整合整體

  • 內存占用大
  • 一個key占用過大內存,如果是redis-cluster會出 現data drift
  • ?

    segment-hash

    內存占用量小,雖然理解不夠直觀,但是總體上是最優的。

    理解不夠直觀。

    ? 四、結論: ? ?在使用Redis時,要選擇合理的數據結構解決實際問題,那樣既可以提高效率又可以節省內存。所以此次優化方案三為最佳。 附圖一張:redis其實是一把瑞士軍刀: ? ? ? ?

    總結

    以上是生活随笔為你收集整理的美团在Redis上踩过的一些坑-4.redis内存使用优化的全部內容,希望文章能夠幫你解決所遇到的問題。

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