本文将对 Redis 4.0 的各项主要新功能作一个简单的介绍。模块系统 Redis 4.0 发生的最大变化就是加入了模块系统, 这个系统可让用户经过本身编写的代码来扩展和实现 Redis
自己并不具有的功能, 具体使用方法能够参考 antirez 的博文《Redis Loadable Module System》:
http://antirez.com/news/106node
由于模块系统是经过高层次 API 实现的, 它与 Redis 内核自己彻底分离、互不干扰, 因此用户能够在有须要的状况下才启用这个功能, 如下是 redis.conf 中记载的模块载入方法:git
Load modules at startup. If the server is not able to load modules it will abort. It is possible to use multiple loadmodule directives. loadmodule /path/to/my_module.so loadmodule /path/to/other_module.so
目前已经有人使用这个功能开发了各类各样的模块, 好比 Redis Labs 开发的一些模块就能够在 http://redismodules.com 看到, 此外 antirez 本身也使用这个功能开发了一个神经网络模块: https://github.com/antirez/ne...github
模块功能使得用户能够将 Redis 用做基础设施, 并在上面构建更多功能, 这给 Redis 带来了无数新的可能性。redis
新版本的 PSYNC 命令解决了旧版本的 Redis 在复制时的一些不够优化的地方:数据库
在旧版本 Redis 中, 若是一个从服务器在 FAILOVER 以后成为了新的主节点, 那么其余从节点在复制这个新主的时候就必须进行全量复制。 在 Redis 4.0 中, 新主和从服务器在处理这种状况时, 将在条件容许的状况下使用部分复制。
在旧版本 Redis 中, 一个从服务器若是重启了, 那么它就必须与主服务器从新进行全量复制, 在 Redis 4.0 中, 只要条件容许, 主从在处理这种状况时将使用部分复制。
缓存驱逐策略优化
新添加了 Last Frequently Used 缓存驱逐策略, 具体信息见 antirez 的博文《Random notes on improving the Redis LRU algorithm》: http://antirez.com/news/109缓存
另外 Redis 4.0 还对已有的缓存驱逐策略进行了优化, 使得它们可以更健壮、高效、快速和精确。服务器
在 Redis 4.0 以前, 用户在使用 DEL 命令删除体积较大的键, 又或者在使用 FLUSHDB 和 FLUSHALL 删除包含大量键的数据库时, 均可能会形成服务器阻塞。网络
为了解决以上问题, Redis 4.0 新添加了 UNLINK 命令, 这个命令是 DEL 命令的异步版本, 它能够将删除指定键的操做放在后台线程里面执行, 从而尽量地避免服务器阻塞:数据结构
redis> UNLINK fruits (integer) 1
由于一些历史缘由, 执行同步删除操做的 DEL 命令将会继续保留。app
此外, Redis 4.0 中的 FLUSHDB 和 FLUSHALL 这两个命令都新添加了 ASYNC 选项, 带有这个选项的数据库删除操做将在后台线程进行:
redis> FLUSHDB ASYNC OK redis> FLUSHALL ASYNC OK
Redis 4.0 对数据库命令的另一个修改是新增了 SWAPDB 命令, 这个命令能够对指定的两个数据库进行互换: 好比说, 经过执行命令 SWAPDB 0 1 , 咱们能够将原来的数据库 0 变成数据库 1 , 而原来的数据库 1 则变成数据库 0 。
如下是一个使用 SWAPDB 的例子:
redis> SET your_name "huangz" -- 在数据库 0 中设置一个键 OK redis> GET your_name "huangz" redis> SWAPDB 0 1 -- 互换数据库 0 和数据库 1 OK redis> GET your_name -- 如今的数据库 0 已经没有以前设置的键了 (nil) redis> SELECT 1 -- 切换到数据库 1 OK
redis[1]> GET your_name -- 以前在数据库 0 设置的键如今能够在数据库 1 找到
"huangz" -- 证实两个数据库已经互换
Redis 4.0 新增了 RDB-AOF 混合持久化格式, 这是一个可选的功能, 在开启了这个功能以后, AOF 重写产生的文件将同时包含 RDB 格式的内容和 AOF 格式的内容, 其中 RDB 格式的内容用于记录已有的数据, 而 AOF 格式的内存则用于记录最近发生了变化的数据, 这样 Redis 就能够同时兼有 RDB 持久化和 AOF 持久化的优势 —— 既可以快速地生成重写文件, 也可以在出现问题时, 快速地载入数据。
这个功能能够经过 aof-use-rdb-preamble 选项进行开启, redis.conf 文件中记录了这个选项的使用方法:
# When rewriting the AOF file, Redis is able to use an RDB preamble in the # AOF file for faster rewrites and recoveries. When this option is turned # on the rewritten AOF file is composed of two different stanzas: # # [RDB file][AOF tail] # # When loading Redis recognizes that the AOF file starts with the "REDIS" # string and loads the prefixed RDB file, and continues loading the AOF # tail. # # This is currently turned off by default in order to avoid the surprise # of a format change, but will at some point be used as the default. aof-use-rdb-preamble no
新添加了一个 MEMORY 命令, 这个命令能够用于视察内存使用状况, 并进行相应的内存管理操做:
redis> MEMORY HELP 1) "MEMORY USAGE <key> [SAMPLES <count>] - Estimate memory usage of key" 2) "MEMORY STATS - Show memory usage details" 3) "MEMORY PURGE - Ask the allocator to release memory" 4) "MEMORY MALLOC-STATS - Show allocator internal stats"
其中, 使用 MEMORY USAGE 子命令能够估算储存给定键所需的内存:
redis> SET msg "hello world" OK redis> SADD fruits apple banana cherry (integer) 3 redis> MEMORY USAGE msg (integer) 62 redis> MEMORY USAGE fruits (integer) 375 使
用 MEMORY STATS 子命令能够查看 Redis 当前的内存使用状况:
redis> MEMORY STATS 1) "peak.allocated" 2) (integer) 1014480 3) "total.allocated" 4) (integer) 1014512 5) "startup.allocated" 6) (integer) 963040 7) "replication.backlog" 8) (integer) 0 9) "clients.slaves" 10) (integer) 0 11) "clients.normal" 12) (integer) 49614 13) "aof.buffer" 14) (integer) 0 15) "db.0" 16) 1) "overhead.hashtable.main" 2) (integer) 264 3) "overhead.hashtable.expires" 4) (integer) 32 17) "overhead.total" 18) (integer) 1012950 19) "keys.count" 20) (integer) 5 21) "keys.bytes-per-key" 22) (integer) 10294 23) "dataset.bytes" 24) (integer) 1562 25) "dataset.percentage" 26) "3.0346596240997314" 27) "peak.percentage" 28) "100.00315093994141" 29) "fragmentation" 30) "2.1193723678588867"
使用 MEMORY PURGE 子命令能够要求分配器释放更多内存:
redis> MEMORY PURGE
OK
使用 MEMORY MALLOC-STATS 子命令能够展现分配器内部状态:
redis> MEMORY MALLOC-STATS
Stats not supported for the current allocator
Redis 4.0 将兼容 NAT 和 Docker , 具体的使用方法在 redis.conf 中有记载:
# In certain deployments, Redis Cluster nodes address discovery fails, because # addresses are NAT-ted or because ports are forwarded (the typical case is # Docker and other containers). # # In order to make Redis Cluster working in such environments, a static # configuration where each node known its public address is needed. The # following two options are used for this scope, and are: # # * cluster-announce-ip # * cluster-announce-port # * cluster-announce-bus-port # # Each instruct the node about its address, client port, and cluster message # bus port. The information is then published in the header of the bus packets # so that other nodes will be able to correctly map the address of the node # publishing the information. # # If the above options are not used, the normal Redis Cluster auto-detection # will be used instead. # # Note that when remapped, the bus port may not be at the fixed offset of # clients port + 10000, so you can specify any port and bus-port depending # on how they get remapped. If the bus-port is not set, a fixed offset of # 10000 will be used as usually. # # Example: # # cluster-announce-ip 10.1.1.5 # cluster-announce-port 6379 # cluster-announce-bus-port 6380
一共有15项内容,内存使用量均以字节为单位,咱们一个一个来看:
redis启动到如今,最多使用过多少内存。
当前使用的内存总量。
redis启动初始化时使用的内存,有不少读者会比较奇怪,为何个人redis启动之后什么都没作就已经占用了几十MB的内存? 这是由于redis自己不只存储key-value,还有其余的内存消耗,好比共享变量、主从复制、持久化和db元信息,下面各项会有详细介绍。
主从复制backlog使用的内存,默认10MB,backlog只在主从断线重连时发挥做用,主从复制自己并不依赖此项。
主从复制中全部slave的读写缓冲区,包括output-buffer(也即输出缓冲区)使用的内存和querybuf(也即输入缓冲区),这里简单介绍一下主从复制:
redis把一次事件循环中,全部对数据库发生更改的内容先追加到slave的output-buffer中,在事件循环结束后统一发送给slave。 那么主从之间就不免会有数据的延迟,若是主从之间链接断开,重连时为了保证数据的一致性就要作一次全量同步,这显然是不够高效的。backlog就是为此而设计,master在backlog中缓存一部分主从复制的增量数据,断线重连时若是slave的偏移量在backlog中,那就能够只把偏移量以后的增量数据同步给slave便可,避免了全量同步的开销。
除slave外全部其余客户端的读写缓冲区。 有时候一些客户端读取不及时,就会形成output-buffer积压占用内存过多的状况,能够经过配置项client-output-buffer-limit来限制,当超过阈值以后redis就会主动断开链接以释放内存,slave亦是如此。
此项为aof持久化使用的缓存和aofrewrite时产生的缓存之和,固然若是关闭了appendonly那这项就一直为0:
redis并非在有写入时就当即作持久化的,而是在一次事件循环内把全部的写入数据缓存起来,待到事件循环结束后再持久化到磁盘。 aofrewrite时缓存增量数据使用的内存,只在aofrewrite时才会使用,aofrewrite机制能够参考以前的文章《redis4.0之利用管道优化aofrewrite》。
能够看出这一项的大小与写入流量成正比。
redis每一个db的元信息使用的内存,这里只使用了db0,因此只打印了db0的内存使用状态,当使用其余db时也会有相应的信息。 db的元信息有如下三项: a) redis的db就是一张hash表,首先就是这张hash表使用的内存(redis使用链式hash,hash表中存放全部链表的头指针); b) 每个key-value对都有一个dictEntry来记录他们的关系,元信息便包含该db中全部dictEntry使用的内存; c) redis使用redisObject来描述value所对应的不一样数据类型(string、list、hash、set、zset),那么redisObject占用的空间也计算在元信息中。 overhead.hashtable.main: db的元信息也便是以上三项之和,计算公式为: hashtable + dictEntry + redisObject overhead.hashtable.expires: 对于key的过时时间,redis并无把它和value放在一块儿,而是单独用一个hashtable来存储,可是expires这张hash表记录的是key-expire信息,因此不须要`redisObject`来描述value,其元信息也就少了一项,计算公式为: hashtable + dictEntry
3-8项之和:startup.allocated+replication.backlog+clients.slaves+clients.normal+aof.buffer+dbx
全部数据所使用的内存——也即total.allocated - overhead.total——当前内存使用量减去管理类内存使用量。
全部数据占比,这里并无直接使用total.allocated作分母,而是除去了redis启动初始化的内存,计算公式为: 100 * dataset.bytes / (total.allocated - startup.allocated)
redis当前存储的key总量
平均每一个key的内存大小,直觉上应该是用dataset.bytes除以keys.count便可,可是redis并无这么作,而是把管理类内存也平摊到了每一个key的内存使用中,计算公式为: (total.allocated - startup.allocated) / keys.count
当前使用内存与历史最高值比例
相信全部redis用户都但愿对每个key-value的内存使用了如指掌,然而4.0以前redis并无提供一个明确的方法来进行内存评估,不过从4.0开始,MEMORY命令实现了这一功能。
首先看下使用方法:MEMORY usage [samples]
命令参数很少,经过字面意思也能够看出来是评估指定key的内存使用状况。samples是可选参数默认为5,以hash为例看下其若是工做:
首先相似于上一节中的overhead.hashtable.main,要计算hash的元信息内存,包括hash表的大小以及全部dictEntry的内存占用信息。 与overhead.hashtable.main不一样的是,每一个dictEntry中key-value都是字符串,因此没redisObject的额外消耗。在评估真正的数据内存大小时redis并无去遍历全部key,而是采用的抽样估算:随机抽取samples个key-value对计算其平均内存占用,再乘以key-value对的个数即获得结果。试想一下若是要精确计算内存占用,那么就须要遍历全部的元素,当元素不少时就是使redis阻塞,因此请合理设置samples的大小。
其余数据结构的计算方式相似于hash,此处就再也不赘述。
此项子命令是做者给出的关于redis内存使用方面的建议,在不一样的容许状态下会有不一样的分析结果:
首先是没问题的状况
运行状态良好: Hi Sam, I can't find any memory issue in your instance. I can only account for what occurs on this base. redis的数据量很小,暂无建议: Hi Sam, this instance is empty or is using very little memory, my issues detector can't be used in these conditions. Please, leave for your mission on Earth and fill it with some data. The new Sam and I will be back to our programming as soon as I finished rebooting.
接下来出现的结果就须要注意了
内存使用峰值1.5倍于目前内存使用量,此时内存碎片率可能会比较高,须要注意:
Peak memory: In the past this instance used more than 150% the memory that is currently using. The allocator is normally not able to release memory after a peak, so you can expect to see a big fragmentation ratio, however this is actually harmless and is only due to the memory peak, and if the Redis instance Resident Set Size (RSS) is currently bigger than expected, the memory will be used as soon as you fill the Redis instance with more data. If the memory peak was only occasional and you want to try to reclaim memory, please try the MEMORY PURGE command, otherwise the only other option is to shutdown and restart the instance.
内存碎片率太高超过1.4,须要注意:
High fragmentation: This instance has a memory fragmentation greater than 1.4 (this means that the Resident Set Size of the Redis process is much larger than the sum of the logical allocations Redis performed). This problem is usually due either to a large peak memory (check if there is a peak memory entry above in the report) or may result from a workload that causes the allocator to fragment memory a lot. If the problem is a large peak memory, then there is no issue. Otherwise, make sure you are using the Jemalloc allocator and not the default libc malloc.
每一个slave缓冲区的平均内存超过10MB,缘由多是master写入流量太高,也有多是主从同步的网络带宽不足或者slave处理较慢:
Big slave buffers: The slave output buffers in this instance are greater than 10MB for each slave (on average). This likely means that there is some slave instance that is struggling receiving data, either because it is too slow or because of networking issues. As a result, data piles on the master output buffers. Please try to identify what slave is not receiving data correctly and why. You can use the INFO output in order to check the slaves delays and the CLIENT LIST command to check the output buffers of each slave.
普通客户端缓冲区的平均内存超过200KB,缘由多是pipeline使用不当或者Pub/Sub客户端处理消息不及时致使:
Big client buffers: The clients output buffers in this instance are greater than 200K per client (on average). This may result from different causes, like Pub/Sub clients subscribed to channels bot not receiving data fast enough, so that data piles on the Redis instance output buffer, or clients sending commands with large replies or very large sequences of commands in the same pipeline. Please use the CLIENT LIST command in order to investigate the issue if it causes problems in your instance, or to understand better why certain clients are using a big amount of memory.
打印内存分配器状态,只在使用jemalloc时有用。
请求分配器释放内存,一样只对jemalloc生效。
结语
关于 Redis 4.0 的主要更新就介绍到这里, 想要详细了解 Redis 4.0 各项修改的读者能够参考 Release Note : https://raw.githubusercontent...