[转帖]美团在Redis上踩过的一些坑-4.redis内存使用优化
(磁带已死,磁盘是新磁带,闪存是新磁盘,随机存储器局部性是为王道)
| userId(用户id) | weiboCount(微博数) |
| 1 | 2000 |
| 2 |
10 |
| 3 |
288 |
| .... | ... |
| 1000000 | 1000 |
| 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 |
注意:
3. 获取方法:
- #获取userId=5003用户的微博数
- (1) get u:5003
- (2) hget allUser u:5003
- (3) hget u:50 f:3
4. 内存占用量对比(100万用户 userId u:1~u:1000000)
- #方法一 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,变化还是很大的。
- 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"
内存使用量:

- 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();
- }
- }
- }
- }
| 方案 | 优点 | 缺点 |
| string |
直观、容易理解 |
|
| hash |
直观、容易理解、整合整体 |
|
| segment-hash |
内存占用量小,虽然理解不够直观,但是总体上是最优的。 |
理解不够直观。 |

[转帖]美团在Redis上踩过的一些坑-4.redis内存使用优化的更多相关文章
- [转帖]美团在Redis上踩过的一些坑-5.redis cluster遇到的一些问题
美团在Redis上踩过的一些坑-5.redis cluster遇到的一些问题 博客分类: redis 运维 redis clustercluster-node-timeoutfailover 转载请 ...
- [转帖]美团在Redis上踩过的一些坑-3.redis内存占用飙升
美团在Redis上踩过的一些坑-3.redis内存占用飙升 博客分类: 运维 redis redismonitor内存突增client listinfo 转载请注明出处哈:http://car ...
- 美团在Redis上踩过的一些坑-3.redis内存占用飙升(转载)
一.现象: redis-cluster某个分片内存飙升,明显比其他分片高很多,而且持续增长.并且主从的内存使用量并不一致. 二.分析可能原因: 1. redis-cluster的bu ...
- [转帖]美团在Redis上踩过的一些坑-2.bgrewriteaof问题
美团在Redis上踩过的一些坑-2.bgrewriteaof问题 博客分类: redis 运维 aofaof rewrite 转载请注明出处哈:http://carlosfu.iteye.com/b ...
- [转帖]美团在Redis上踩过的一些坑-1.客户端周期性出现connect timeout
美团在Redis上踩过的一些坑-1.客户端周期性出现connect timeout 博客分类: redis 运维 jedisconnect timeoutnosqltcp 转载请注明出处哈:http ...
- 美团在Redis上踩过的一些坑-目录(本人非美团)(转)
来自:http://carlosfu.iteye.com/blog/2254154 分为5个部分: 一.周期性出现connect timeout 二.redis bgrewriteaof问 ...
- Redis上踩过的一些坑
来自: http://blog.csdn.net//chenleixing/article/details/50530419 上上周和同事(龙哥)参加了360组织的互联网技术训练营第三期,美团网的DB ...
- redis主从复制踩到的那些坑
一.报错:* MASTER <-> SLAVE sync started # Error condition on socket for SYNC: No route to host解决: ...
- 【一个idea】YesSql,一种在经典nosql数据库redis上实现SQL引擎的方案(我就要开历史的倒车)
公众号链接 最高级的红酒,一定要掺上雪碧才好喝. 基于这样的品味,我设计出了一套在经典nosql数据库redis上实现SQL引擎的方法.既然redis号称nosql,而我偏要把SQL加到redis上, ...
随机推荐
- Spring所有注解大揭秘
声明bean的注解 @Component 组件,没有明确的角色 @Service 在业务逻辑层使用(service层) @Repository 在数据访问层使用(dao层) @Controller 在 ...
- English--元音
English|元音 在一开始学习英语的时候,最需要掌握的就是音标.所以需要从音标的元音开始,并且不局限于掌握音标的元音与辅音,大家可以参考下英文版发音课,并不知道只学习元音与辅音,还有各种弱读连读等 ...
- .NetCore之基础
.NetCore几大特点 这篇文章主要从.NetCore全面开源.依赖注入.包引入.跨平台.应用服务器的特点来入手.大约需要10分钟的阅读时间. 与.Net的区别 在.Net与.NetCore在代码编 ...
- Spring Boot2(八):性感banner,在线发牌
本文在个人技术博客[鸟不拉屎]同步发布,详情可猛戳 亦可扫描文章末尾二维码关注个人公众号[鸟不拉屎] emmm,没有啥前言 玩过SpringBoot的都知道,SpringBoot启动的时候,默认会在控 ...
- using 中写 return 一样会释放using 中对象 但是会在外面定义一个一样的对象 赋值后 释放 最后 return 外面定义的那个对象
static DataTable getDataTable() { ")) { SqlCommand com = new SqlCommand("", con); Sql ...
- Hashtable,HashMap和ConcurrentHashMap的原理及区别
一.原理 Hashtable 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashM ...
- xadmin引入django-stdimage在列表页预览图片
一.安装 pip install django-stdimage 安装django-stdimage库 https://github.com/codingjoe/django-stdimage Git ...
- NVIDIA-GPU归入K8S集群管理的安装文档--第二版
一,nvidia K80驱动安装 1, 查看服务器上的Nvidia(英伟达)显卡信息,命令lspci |grep NVIDIA 2, 按下来,进行显卡驱动程序的安装,驱动程序可到nvidia的官网 ...
- 2019年南京网络赛E题K Sum(莫比乌斯反演+杜教筛+欧拉降幂)
目录 题目链接 思路 代码 题目链接 传送门 思路 首先我们将原式化简: \[ \begin{aligned} &\sum\limits_{l_1=1}^{n}\sum\limits_{l_2 ...
- serverless 如何调试(三)
在上篇文章中,我们讲解了如何调用我们的hello-world应用,只需要使用命令: serverless invoke -f hello -l ,但是我们总不可能修改一次代码,就调用一下这个命令吧,或 ...
