[转帖]美团在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上, ...
随机推荐
- ES6兼容ie9, flex兼容ie9
vue兼容ES6 在 ie9 的环境上,es6 的部分新对象.表达式,并不支持,解决方案是使用 babel-polyfill 组件,它可以将 es6 的代码翻译成低版本浏览器可以识别的 es5 代码 ...
- SpringBoot自定义Condition注解
最近碰到个这样的需求,需要同一套代码适配个版本数据库(数据库不同,且部分表的字段及关联关系可能会不同),即这套代码配置不同的数据库都能跑.项目采用的框架为SpringBoot+Mybatis. ...
- Pods应用NFS存储
Volumes选择NFS服务器: 条件: 1. k8s集群,目前为(hadoop1,hadoop2,hadoop3) 2. 另起一台服务器做专门的NFS服务器 3. NFS需要在K8S的各个节点安装 ...
- 《linux就该这么学》课堂笔记18 squid服务
Squid服务程序正向解析和反向解析 正向代理模式不仅可以让用户使用Squid代理服务器上网,还可以基于指定的IP地址.域名关键词.网站地址或下载文件后缀等信息,实现类似于访问控制列表的功能.反向代理 ...
- [转]【HttpServlet】HttpServletResponse接口 案例:完成文件下载
创建时间:6.19 & 6.24 1.案例-完成文件下载 1) 什么情况下会文件下载? 浏览器不能解析的文件就下载 *使用a标签直接指向服务器上的资源 2)什么情况下需要在服务端编写文件下载 ...
- 1 NLP学习大纲
一.自然语言处理概述 1)自然语言处理:利用计算机为工具,对书面实行或者口头形式进行各种各样的处理和加工的技术,是研究人与人交际中以及人与计算机交际中的演员问题的一门学科,是人工智能的主要内容. 2) ...
- NVIDIA-GPU归入K8S集群管理的安装文档--第二版
一,nvidia K80驱动安装 1, 查看服务器上的Nvidia(英伟达)显卡信息,命令lspci |grep NVIDIA 2, 按下来,进行显卡驱动程序的安装,驱动程序可到nvidia的官网 ...
- python关于type()与生成器generator的用法
如果按这种形式写 type(a)(b) 那此处的b是个可迭代对象,这个对象迭代完成后,再放到type里 from pymysql._compat import range_type, text ...
- LCD硬件原理
想象一下,屏幕的后面有一个电子枪,电子枪位于某个像素的背后,然后向这个像素发射红绿蓝三原色,从而就可以组成任意一种颜色.简单的说,电子枪在像素的背后一边移动,一边向像素发射红绿蓝. 如果要编写出LCD ...
- LocalDateTime的一些用法
包括获取当前时间,指定特定时间.进行时间的加减等 LocalDateTime localDateTime3 = LocalDateTime.now(); LocalDate.now(); LocalT ...
