Chapter 6. Common Pitfalls (Avoiding Traps)

本章讲述使用Redis的一些误区,部分例子基于Yipit (www.yipit.com)和其它一些公司的经验教训。

The wrong data type for the job

Yipit最初将要发送给用户的deal存于Set中,尽管可以运行,但开发者担心由于用户量太大,Set的内存消耗大,因此转向用Bitmap存储,结果是上线后不久,内存就满了,下来会解释原因。

教训:在提交解决方案前必须做benchmark测试。

The Set approach

Set的实现非常直接,每一个用户一个Set,即userID作为key, DealID用Set存放,例如(1, 2, 3, 4, 5, …).

The following code is a benchmark of this implementation, using 100,000 Sets with 12 deal IDs each, and each user will receive the same 12 deals.

Create a file called benchmark-set.js in the chapter 6 folder with the following code:

以下为使用Set的benchmark代码,模拟10万用户,每用户12个deal。

var redis = require("redis");
var client = redis.createClient();
var MAX_USERS = 100000;
var MAX_DEALS = 12;
var MAX_DEAL_ID = 10000;for (var i = 0 ; i < MAX_USERS ; i++) {var multi = client.multi();for (var j = 0 ; j < MAX_DEALS ; j++) {multi.sadd("set:user:" + i, MAX_DEAL_ID - j, 1);}multi.exec();
}client.quit();

运行benchmark程序,得到内存使用情况:

[redis@tt12c chapter 6]$ redis-cli FLUSHALL && node benchmark-set.js && redis-cli INFO memory
OK
# Memory
used_memory:14355424
used_memory_human:13.69M
used_memory_rss:18239488
used_memory_peak:32488744
used_memory_peak_human:30.98M
used_memory_lua:36864
mem_fragmentation_ratio:1.27
mem_allocator:jemalloc-3.6.0

The Bitmap approach

Bitmap的实现中,也是userID作为key,然后dealID存放于Bitmap中,需要发送的deal置为1。
不过Bitmap的问题在于最大的dealID决定了其存储开销,如果最大的dealID是1,000,000,Bitmap就需要消耗1,000,001 bit。

以下为使用Bitmap的benchmark代码,模拟10万用户,每用户12个deal。

var redis = require("redis");
var client = redis.createClient();
var MAX_USERS = 100000;
var MAX_DEALS = 12;
var MAX_DEAL_ID = 10000;for (var i = 0 ; i < MAX_USERS ; i++) {var multi = client.multi();for (var j = 0 ; j < MAX_DEALS ; j++) {multi.setbit("bitmap:user:" + i, MAX_DEAL_ID - j, 1);}multi.exec();
}client.quit();

运行benchmark程序,得到内存使用情况:

[redis@tt12c chapter 6]$ redis-cli FLUSHALL && node benchmark-bitmap.js && redis-cli INFO memory
OK
# Memory
used_memory:265555560
used_memory_human:253.25M
used_memory_rss:291766272
used_memory_peak:283525488
used_memory_peak_human:270.39M
used_memory_lua:36864
mem_fragmentation_ratio:1.10
mem_allocator:jemalloc-3.6.0

Bitmap实现使用了 253MB内存,而Set实现仅使用了近14M。
为何有如此大的区别,理论上Bitmap应更省内存。仔细看这段代码,比Set的实现多了MAX_DEAL_ID参数,使得Bitmap被”撑大了”,一个Bitmap需要100000个bit,约12500字节

multi.setbit("bitmap:user:" + i, MAX_DEAL_ID - j, 1);

Multiple Redis databases

Redis服务器支持多个数据库,类似于SQL数据库,如MySQL,只不过Redis用数字表示不同的数据库。

但Redis不推荐使用多个数据库,而推荐在一个机器上启动多个Redis服务,因为Redis是单线程的,这样可以更好的利用CPU core。
而且多个数据库不好管理,无法判断是谁引起问题。

Keys without a namespace

使用namespace是最佳建议,目的是为了避免key name的冲突,并且可以很好的对key进行组织。

在 SQL数据库中, namespace可以用数据库名或表名表示。而Redis并不支持namespace,因此必须模拟namespace,常用的方法是加前缀, 形式namespace:key_name。这种方法在前面例子中已经见到很多了,例如:

music-online:song:1
music-online:song:2
music-online:album:10001:metadata
music-online:album:10001:songs
music-online:author:123

Using Swap

不要用Swap,尽可能让Redis运行在内存中。因频繁的使用swap会阻塞客户端的访问。
Linux有一个kernel参数swappiness控制如何使用swap,数越大,使用swap越频繁。将它设置为0。

sysctl -w vm.swappiness=0 同时 修改/etc/sysctl.conf

Not planning and configuring the memory properly

Redis服务器需要足够的内存来执行备份,在备份是,最极端的情况需要Redis内存的两倍。

在创建RDB snapshot 和 AOF rewriting时, redis-server需要通过fork()复制自身。

如果在fork时,Redis非常忙,这时copy-on-write以及内存overcommitting已经不够,子进程可能需要和父进程同样大小的内存。

如果是Linux操作系统,在/etc/sysctl.conf中设置vm.overcommit_memory=1可加速后台的数据保存。

Redis有一配置参数maxmemory可限制Redis最多可使用的内存。

在备份开启后,Redis使用的内存不要超过可用内存的一半。

An inappropriate persistence strategy

在Yipit,有一个读密集的Redis实例变得缓慢,开始以为是代码有问题,后来发现是定期的备份(持久化)使其变慢。

在Redis开始创建RDB snapshot和AOF rewriting时,需要用fork创建子进程,然后让新的子进程来处理。在fork执行时,Redis不能对外服务,这时用户会感觉到响应慢。
Yipit的问题就是因为fork时间过长,因为Redis运行在AWS上,机器使用的是较慢的PV而非HVM虚拟机。

通过以下的措施可以缓解此问题:
* 禁止transparent huge pages内核参数 (echo never > /sys/kernel/mm/transparent_hugepage/enabled)
* 使用HVN虚拟机
* 进行复制,复制目标端用且仅用于持久化
* 减少备份的频度
* 禁止自动持久化,手工来做
* 如果数据可以很快的重建,就不要做持久化

Redislab 发布了fork时间的benchmark:https://redislabs.com/blog/testing-fork-time-on-awsxen-infrastructure.

Summary

本章讲述了Redis使用的一些误区,比较重要的有:
* 要使用namespace避免key命名冲突
* 才提交解决方案时需要先测试,做benchmark测试
* 不做或少做持久化

Redis Essentials 读书笔记 - 第六章: Common Pitfalls (Avoiding Traps)相关推荐

  1. 《Python从入门到实践》读书笔记——第六章 字典

    <Python从入门到实践>读书笔记--第六章 字典 1. 一个简单的字典 alien_0 = {'color': 'green', 'points': 5}print(alien_0[' ...

  2. Redis Essentials 读书笔记 - 第九章: Redis Cluster and Redis Sentinel (Collective Intelligence)

    Chapter 9. Redis Cluster and Redis Sentinel (Collective Intelligence) 上一章介绍了复制,一个master可以对应一个或多个slav ...

  3. Entity Framework 4 in Action读书笔记——第六章:理解实体的生命周期(三)

    objectstatemanager更改跟踪管理 ObjectStateManager组件(从现在开始称之为 state manager)负责与上下中对象追踪有关的一切: 1.当添加,附加到上下文或者 ...

  4. 《C++ Primer》读书笔记—第六章 函数

    声明: 文中内容收集整理自<C++ Primer 中文版 (第5版)>,版权归原书所有. 学习一门程序设计语言最好的方法就是练习编程 一.函数基础 1.一个典型的函数定义包括以下内容:返回 ...

  5. 财务自由之路 读书笔记 第六章 债务

    第六章 债务 25 绝不要用短期方法解决长期问题 ​ -丹尼尔·s<交易与收益> "赢家一生只做头等舱". 第一节 坏债是如何产生的 好债和坏债  个人认为,使用消费贷 ...

  6. 强化学习(RLAI)读书笔记第六章差分学习(TD-learning)

    第六章:Temporal-Difference Learning TD-learning算法是强化学习中一个独具特色而又核心的想法,结合了蒙特卡洛算法和动态规划的想法.和MC一样不需要环境模型直接从s ...

  7. 《Microsoft Sql server 2008 Internals》读书笔记--第六章Indexes:Internals and Management(3)

    <Microsoft Sql server 2008 Internals>读书笔记订阅地址: http://www.cnblogs.com/downmoon/category/230397 ...

  8. [swift 进阶]读书笔记-第六章:函数 C6P1函数的灵活性(The flexibility of function)...

    第六章:函数(function) 6.1 函数的灵活性(The flexibility of function) 注:本节前部分主要通过一个排序的demo来介绍了函数的灵活性 话不多说,直接上代码 v ...

  9. Redis Essentials 读书笔记 - 第一章: Getting Started (The Baby Steps)

    Chapter 1. Getting Started (The Baby Steps) Redis是在内存中运行的NoSQL key-value数据库. Redis的优势除了内存的高性能外,还有其支持 ...

最新文章

  1. python-docx 使用教程_python docx 中文字体设置的操作方法
  2. vlc生成rtsp流
  3. P3830-[SHOI2012]随机树【数学期望,dp】
  4. 常见的Hadoop十大应用误解
  5. TYAN联合AMD举办线上研讨会,分享最新第三代AMD EPYC服务器产品
  6. [HNOI2005]狡猾的商人 带权并查集
  7. OpenGL立方体面的显示问题?
  8. QQ帐户的申请与登陆 (25 分)(map映射)
  9. VirtualBox虚拟机压缩减少体积
  10. 不要再学 JSP 了,学 SpringBoot + Thymeleaf + Vue吧
  11. 2019 全国大学生电子设计竞赛题目
  12. 面试官:说说Java反射机制
  13. Java网络聊天室系统的设计与实现
  14. Linux Email服务搭建与应用
  15. 计算机网络知识点总结(一)-----蜂窝移动网络
  16. innobackupex备份与恢复
  17. 四分位数算法记录(含java代码实现)
  18. ValueError: Cannot feed value of shape (100, 160) for Tensor 'Placeholder:0', which has shape '(?,
  19. DBeaver21.1.5如何迁移已有数据库连接
  20. RAM和ROM存储空间的混合

热门文章

  1. 【选址优化】基于粒子群算法求解配电网抢修选址优化问题含Matlab源码
  2. 工程转换:遇到core_cm3版本过低等问题
  3. 国家列表 Country Code List
  4. Skyline产品总体介绍
  5. 中秋节祝福html,中秋节祝福短语(人人点赞的中秋节祝福语)
  6. BurpSuite抓包手机模拟器APP
  7. 爬虫学习:基础爬虫案例实战
  8. 编程实现古典问题(兔子生崽):有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?
  9. Python经典编程习题100例:第11例:古典兔子问题
  10. 学术英语视听说2听力原文_大学英语新世纪视听说第二册听力原文及答案免费...