标签:pipeline tag 不执行 压力 因此 二进制文件 安全性 trim channel
Redis是一种基于键值对(key-value)的NoSQL数据库。
与很多键值对数据库不同的是,Redis中的值可以是由string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)等多种数据结构和算法组成,因此Redis可以满足很多的应用场景。
而且因为Redis会将所有数据都存放在内存中,所以它的读写性能非常惊人。
不仅如此,Redis还可以将内存的数据利用快照(RDB)和日志(AOF)的形式保存到硬盘上,这样在发生类似断电或者机器故障的时候,内存中的数据不会“丢失”。
(1)速度快。速度快的原因:
(2)基于键值对的数据结构服务器。
与很多键值对数据库不同的是,Redis中的值不仅可以是字符串,而且还可以是具体的数据结构,它主要提供了5种数据结构:字符串、哈希、列表、集合、有序集合。这样不仅能便于在许多应用场景的开发,同时也能够提高开发效率。
(3)简单稳定
(4)持久化
通常看,将数据放在内存中是不安全的,一旦发生断电或者机器故障,重要的数据可能就会丢失,因此Redis提供了两种持久化方式:RDB和AOF,即可以用两种策略将内存的数据保存到硬盘中(如图1-1所示),这样就保证了数据的可持久性。
(5)主从复制
Redis提供了复制功能,实现了多个相同数据的Redis副本。
(6)高可用和分布式
Redis从2.8版本正式提供了高可用实现Redis Sentinel(哨兵模式),它能够保证Redis节点的故障发现和故障自动转移。
Redis从3.0版本正式提供了分布式实现Redis Cluster(集群模式),它是Redis真正的分布式实现,提供了高可用、读写和容量的扩展性。
(1)缓存。合理地使用缓存不仅可以加快数据的访问速度,而且能够有效地降低后端数据源的压力。
(2)排行榜系统。Redis提供了列表和有序集合数据结构,合理地使用这些数据结构可以很方便地构建各种排行榜系统。
(3)计数器应用。Redis天然支持计数功能而且计数的性能也非常好。
(4)社交网络。赞/踩、粉丝、共同好友/喜好、推送、下拉刷新等是社交网站的必备功能,由于社交网站访问量通常比较大,而且传统的关系型数据不太适合保存这种类型的数据,Redis提供的数据结构可以相对比较容易地实现这些功能。
(5)消息队列系统。消息队列系统可以说是一个大型网站的必备基础组件,因为其具有业务解耦、非实时业务削峰等特性。Redis提供了发布订阅功能和阻塞队列的功能,虽然和专业的消息队列比还不够足够强大,但是对于一般的消息队列功能基本可以满足。
第1步:将redis的源码包上传到linux系统。
Alt+p打开sftp窗口:输入put "F:/java/ziyuan/redis-3.0.0.tar.gz"
第2步:解压:tar -zxvf redis-3.0.0.tar.gz
第3步:进行编译。 cd到解压后的目录 输入命令:make
第4步:进行安装。 输入命令:make install PREFIX=/usr/local/redis
启动:redis-server (加上配置文件) [root@localhost bin]# ./redis-server redis.conf
连接Redis服务:redis-cli [root@localhost bin]# ./redis-cli
停止Redes服务:redis-cli shutdown [root@localhost bin]# ./redis-cli shutdown
keys * :将所有的键都输出
dbsize :输出键总数
exits key :检查某个键是否存在,如果存在返回1,不存在返回0
del key :删除某个键
expire key 时间 :为某个键设置过期时间
ttl key :观察某键的剩余过期时间
type key :返回某键的数据结构类型,如果键不存在返回none
type命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合),但这些只是Redis对外的数据结构。
实际上每种数据结构都有自己底层的内部编码实现,而且是多种实现,这样Redis会在合适的场景选择合适的内部编码。
多种内部编码实现可以在不同场景下发挥各自的优势,例如ziplist比较节省内存,但是在列表元素比较多的情况下,性能会有所下降,这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist。
(1)单线程模型:
Redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库服务。
因为Redis是单线程来处理命令的,所以一条命令从客户端达到服务端不会立刻被执行,所有命令都会进入一个队列中,然后逐个被执行。所以假如有多个客户端命令,则这些命令的执行顺序是不确定的,但是可以确定不会有两条命令被同时执行。
但是像发送命令、返回结果、命令排队肯定不像描述的这么简单,Redis使用了I/O多路复用技术来解决I/O的问题。
(2)为什么单线程号还能这么快?
为什么Redis使用单线程模型会达到每秒万级别的处理能力呢?可以将其归结为三点:
第一,纯内存访问,Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,这是Redis达到每秒万级别访问的重要基础。
第二,非阻塞I/O,Redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。
第三,单线程避免了线程切换和竞态产生的消耗。
字符串类型的值实际可以是字符串(简单的字符串、复杂的字符串(例如JSON、XML))、数字(整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能超过512MB。
Redis会根据当前值的类型和长度决定使用哪种内部编码实现。
(1)缓存功能
下图是比较典型的缓存使用场景,其中Redis作为缓存层,MySQL作为存储层,绝大部分请求的数据都是从Redis中获取。由于Redis具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用。
首先从Redis中获取用户信息(伪代码):
如果没有从Redis获取到用户信息,需要从MySQL中进行获取,并将结果回写到Redis,添加1小时(3600秒)过期时间:(伪代码)
(2)计数
例如使用Redis作为视频播放数计数的基础组件,用户每播放一次视频,相应的视频播放数就会自增1:
(3)共享sessio
一个分布式Web服务将用户的Session信息(例如用户登录信息)保存在各自服务器中,这样会造成一个问题,出于负载均衡的考虑,分布式服务会将用户的访问均衡到不同服务器上,用户刷新一次访问可能会发现需要重新登录,这个问题是用户无法容忍的。
为了解决这个问题,可以使用Redis将用户的Session进行集中管理,如下图所示,在这种模式下只要保证Redis是高可用和扩展性的,每次用户更新或者查询登录信息都直接从Redis中集中获取。
(4)限速
很多应用出于安全的考虑,会在每次进行登录时,让用户输入手机验证码,从而确定是否是用户本人。但是为了短信接口不被频繁访问,会限制用户每分钟获取验证码的频率,例如一分钟不能超过5次。此功能可以使用Redis来实现,下面的伪代码给出了基本实现思路:
1、命令:
2、哈希类型的内部编码:
哈希类型的内部编码有两种:
ziplist(压缩列表):当哈希类型元素个数小于hash-max-ziplist-entries配置(默认512个)、同时所有值都小于hash-max-ziplist-value配置(默认64字节)时,Redis会使用ziplist作为哈希的内部实现,ziplist使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀。
hashtable(哈希表):当哈希类型无法满足ziplist的条件时,Redis会使用hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降,而hashtable的读写时间复杂度为O(1)。
列表(list)类型是用来存储多个有序的字符串.
1、命令:
2、内部编码
列表类型的内部编码有两种:
3、使用场景
(1)消息队列
Redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端使用lrpush从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞式的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性。
(2)文章列表
每个用户有属于自己的文章列表,现需要分页展示文章列表。此时可以考虑使用列表,因为列表不但是有序的,同时支持按照索引范围获取元素。
实际上列表的使用场景很多,在选择时可以参考以下口诀:
集合(set)类型也是用来保存多个的字符串元素,但和列表类型不一样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素。
一个集合最多可以存储2^32-1个元素。Redis除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集,合理地使用好集合类型,能在实际开发中解决很多实际问题。
1、命令:
2、内部编码:
3、使用场景:
集合类型比较典型的使用场景是标签(tag)。例如一个用户可能对娱乐、体育比较感兴趣,另一个用户可能对历史、新闻比较感兴趣,这些兴趣点就是标签。
给用户添加标签:
它保留了集合不能有重复成员的特性,但不同的是,有序集合中的元素可以排序。但是它和列表使用索引下标作为排序依据不同的是,它给每个元素设置一个分数(score)作为排序的依据。
1、命令:
2、内部编码:
3、使用场景:
有序集合比较典型的使用场景就是排行榜系统。例如视频网站需要对用户上传的视频做排行榜,榜单的维度可能是多个方面的:按照时间、按照播放数量、按照获得的赞数。本节使用赞数这个维度,记录每天用户上传视频的排行榜。主要需要实现以下4个功能:
添加用户赞数:zadd和zincrby
取消用户赞数:zrem
展示获取赞数最多的十个用户:zrevrange
展示用户信息以及用户分数:zscore和zrank
Redis提供了几个面向Redis数据库的操作,它们分别是dbsize、select、flushdb/flushall命令。
(1) 切换数据库:select dbIndex
许多关系型数据库,例如MySQL支持在一个实例下有多个数据库存在的,但是与关系型数据库用字符来区分不同数据库名不同,Redis只是用数字作为多个数据库的实现。Redis默认配置中是有16个数据库。
例:selet 15 切换到15号数据库
能不能像使用测试数据库和正式数据库一样,把正式的数据放在0号数据库,测试的数据库放在1号数据库,那么两者在数据上就不会彼此受影响了。事实真有那么好吗?
Redis3.0中已经逐渐弱化这个功能,原因:
- Redis是单线程的。如果使用多个数据库,那么这些数据库仍然是使用一个CPU,彼此之间还是会受到影响的。
- 多数据库的使用方式,会让调试和运维不同业务的数据库变的困难,假如有一个慢查询存在,依然会影响其他数据库,这样会使得别的业务方定位问题非常的困难。
- 部分Redis的客户端根本就不支持这种方式。即使支持,在开发的时候来回切换数字形式的数据库,很容易弄乱。
如果要使用多个数据库功能,完全可以在一台机器上部署多个Redis实例,彼此用端口来做区分,因为现代计算机或者服务器通常是有多个CPU的。这样既保证了业务之间不会受到影响,又合理地使用了CPU资源。
(2)flushdb/flushall
flushdb/flushall命令用于清除数据库,两者的区别的是flushdb只清除当前数据库,flushall会清除所有数据库。
注意如果当前数据库键值数量比较多,flushdb/flushall存在阻塞Redis的可能性。
许多存储系统(例如MySQL)提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(例如:发生时间,耗时,命令的详细信息)记录下来,Redis也提供了类似的功能。如图3-1所示,Redis客户端执行一条命令分为如下4个部分:
1)发送命令 2)命令排队 3)命令执行 4)返回结果
慢查询的两个配置参数:slowlog-log-slower-than和slowlog-max-len
获取慢查询日志:slow get
获取慢查询日志列表当前的长度:slowlog len
慢查询日志重置:slowlog reset
Redis提供了redis-cli、redis-server、redis-benchmark等Shell工具。
启动:redis-server (加上配置文件) [root@localhost bin]# ./redis-server redis.conf
连接Redis服务:redis-cli [root@localhost bin]# ./redis-cli
停止Redes服务:redis-cli shutdown [root@localhost bin]# ./redis-cli shutdown
redis-benchmark可以为Redis做基准性能测试:
-c(clients)选项代表客户端的并发数量(默认是50)
-n(num)选项代表客户端请求总量(默认是100000)
Redis客户端执行一条命令分为如下四个过程:1)发送命令 2)命令排队 3)命令执行 4)返回结果。 其中1)+4)称为RTT(往返时间)
Redis提供了批量操作命令(例如mget、mset等),有效地节约RTT。但大部分命令是不支持批量操作的,例如要执行n次hgetall命令,并没有mhgetall命令存在,需要消耗n次RTT。
Pipeline(流水线)机制能将一组Redis命令进行组装,通过一次RTT传输给Redis,再将这组Redis命令的执行结果按顺序返回给客户端。
为了保证多条命令组合的原子性,Redis提供了简单的事务功能以及集成Lua脚本来解决这个问题。
事务表示一组动作,要么全部执行,要么全部不执行。例如在社交网站上用户A关注了用户B,那么需要在用户A的关注表中加入用户B,并且在用户B的粉丝表中添加用户A,这两个行为要么全部执行,要么全部不执行,否则会出现数据不一致的情况。
Redis提供了简单的事务功能,将一组需要一起执行的命令放到multi和exec两个命令之间。multi命令代表事务开始,exec命令代表事务结束,它们之间的命令是原子顺序执行的。
Redis提供了简单的事务,之所以说它简单,主要是因为它不支持事务中的回滚特性,同时无法实现命令之间的逻辑关系计算。Lua脚本同样可以实现事务的相关功能,但是功能要强大很多。
Redis将Lua作为脚本语言可帮助开发者定制自己的Redis命令。Lua语言提供了如下几种数据类型:booleans(布尔)、numbers(数值)、strings(字符串)、tables(表格)。
在Redis中执行Lua脚本有两种方法:eval和evalsha。
例:eval ‘return "hello" .. KEYS[1] .. ARGV[1]‘ 1 redis word (此时KEYS[1]="redis",ARGV[1]="world",所以最终的返回结果是"hello redisworld"。)
如果Lua脚本较长,还可以使用redis-cli--eval直接执行文件。
eval命令和--eval参数本质是一样的,客户端如果想执行Lua脚本,首先在客户端编写好Lua脚本代码,然后把脚本作为字符串发送给服务端,服务端会将执行结果返回给客户端。
Lua可以使用redis.call函数实现对Redis的访问,例如下面代码是Lua使用redis.call调用了Redis的get操作:
除此之外Lua还可以使用redis.pcall函数实现对Redis的调用,redis.call和redis.pcall的不同在于,如果redis.call执行失败,那么脚本执行结束会直接返回错误,而redis.pcall会忽略错误继续执行脚本,所以在实际开发中要根据具体的应用场景进行函数的选择。
Lua脚本功能为Redis开发和运维人员带来如下三个好处:
Redis提供了4个命令实现对Lua脚本的管理:
Redis提供了Bitmaps这个“数据结构”可以实现对位的操作。把数据结构加上引号主要因为:
下面说下Bitmaps的命令。假设将每个独立用户是否访问过网站存放在Bitmaps中,将访问的用户记做1,没有访问的用户记做0,用偏移量作为用户的id:
(1)设置值:setbit key offset value (设置键的第offset个位的值(从0算起))
假设现在有20个用户,userid=0,5,11,15,19的用户对网站进行了访问,那么当前Bitmaps初始化结果如下图所示:
(2)获取值:getbit key offset (获取键的第offset位的值(从0开始算))
(3)获取Bitmaps指定范围值为1的个数:bitcount [start] [end]
(4)Bitmaps间的运算:bitop and | or | not | xor destkey key [key ...] (做多个Bitmaps的and(交集)、or(并集)、not(非)、xor(异或)操作并将结果保存在destkey中)
假设网站有1亿用户,每天独立访问的用户有5千万,如果每天用集合类型和Bitmaps分别存储活跃用户,这种情况下使用Bitmaps能节省很多的内存空间,尤其是随着时间推移节省的内存还是非常可观的。
但假如该网站每天的独立访问用户很少,例如只有10万(大量的僵尸用户),那么两者的对比如下表所示,很显然,这时候使用Bitmaps就不太合适了,因为基本上大部分位都是0。
Redis提供了基于“发布/订阅”模式的消息机制,此种模式下,消息发布者和订阅者不进行直接通信,发布者客户端向指定的频道(channel)发布消息,订阅该频道的每个客户端都可以收到该消息。
命令:
使用场景:
聊天室、公告牌、服务之间利用消息解耦都可以使用发布订阅模式,下面以简单的服务解耦进行说明。如下图示,图中有两套业务,上面为视频管理系统,负责管理视频信息;下面为视频服务面向客户,用户可以通过各种客户端(手机、浏览器、接口)获取到视频信息。
Redis是用单线程来处理多个客户端的访问,因此作为Redis的开发和运维人员需要了解Redis服务端和客户端的通信协议,以及主流编程语言的Redis客户端使用方法,同时还需要了解客户端管理的相应API以及开发运维中可能遇到的问题。本章将对这些内容进行详细分析,本章内容如下:
例如客户端发送一条set hello world命令给服务端,按照RESP的标准,客户端需要将其封装为如下格式(每行用\r\n分隔):
这样Redis服务端能够按照RESP将其解析为set hello world命令,执行后回复的格式如下:+OK
Redis的返回结果类型分为以下五种:
Jedis属于Java的第三方开发包,在Java中获取第三方开发包通常有两种方式:
通常在实际项目中使用第二种方式,但如果只是想测试一下Jedis,第一种方法也是可以的。以Maven为例子,在项目中加入下面的依赖即可:
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.2</version> </dependency>
//1. 生成一个Jedis对象,这个对象负责和指定Redis实例进行通信。 初始化Jedis需要两个参数:Redis实例的IP和端口 Jedis jedis = new Jedis("127.0.0.1", 6379); //2. jedis执行set操作 jedis.set("hello", "world"); //3. jedis执行get操作, value="world" String value = jedis.get("hello");
Jedis对于Redis五种数据结构的操作:
//-----------1.string------------ // 输出结果:OK jedis.set("hello", "world"); // 输出结果:world jedis.get("hello"); // 输出结果:1 jedis.incr("counter"); //-----------2.hash--------------- jedis.hset("myhash", "f1", "v1"); jedis.hset("myhash", "f2", "v2"); // 输出结果:{f1=v1, f2=v2} jedis.hgetAll("myhash"); //-----------3.list--------------- jedis.rpush("mylist", "1"); jedis.rpush("mylist", "2"); jedis.rpush("mylist", "3"); // 输出结果:[1, 2, 3] jedis.lrange("mylist", 0, -1); //-----------4.set---------------- jedis.sadd("myset", "a"); jedis.sadd("myset", "b"); jedis.sadd("myset", "a"); // 输出结果:[b, a] jedis.smembers("myset"); //------------5.zset---------------- jedis.zadd("myzset", 99, "tom"); jedis.zadd("myzset", 66, "peter"); jedis.zadd("myzset", 33, "james"); // 输出结果:[[["james"],33.0], [["peter"],66.0], [["tom"],99.0]] jedis.zrangeWithScores("myzset", 0, -1);
客户端连接Redis使用的是TCP协议,直连的方式每次需要建立TCP连接,而连接池的方式是可以预先初始化好Jedis连接,所以每次只需要从Jedis连接池借用即可,而借用和归还操作是在本地进行的,只有少量的并发同步开销,远远小于新建TCP连接的开销。另外直连的方式无法限制Jedis对象的个数,在极端情况下可能会造成连接泄露,而连接池的形式可以有效的保护和控制资源的使用。下表给出两种方式各自的优劣势。
Jedis提供了JedisPool这个类作为对Jedis的连接池。使用JedisPool操作Redis的代码示例:
(1)Jedis连接池(通常JedisPool是单例的):
// common-pool连接池配置,这里使用默认配置 GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); // 初始化Jedis连接池 JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379);
(2)获取Jedis对象不再是直接生成一个Jedis对象进行直连,而是从连接池直接获取,代码如下:
Jedis jedis = null; try { // 1. 从连接池获取jedis对象 jedis = jedisPool.getResource(); // 2. 执行操作 jedis.get("hello"); } catch (Exception e) { logger.error(e.getMessage(),e); } finally { if (jedis != null) { // 如果使用JedisPool,close操作不是关闭连接,代表归还连接池 jedis.close(); } }
回顾:Pipeline(流水线)机制能将一组Redis命令进行组装,通过一次RTT传输给Redis,再将这组Redis命令的执行结果按顺序返回给客户端。
Jedis支持Pipeline特性,我们知道Redis提供了mget、mset方法,但是并没有提供mdel方法,如果想实现这个功能,可以借助Pipeline来模拟批量删除:
public void mdel(List<String> keys) { Jedis jedis = new Jedis("127.0.0.1"); // 1)生成pipeline对象 Pipeline pipeline = jedis.pipelined(); // 2)pipeline执行命令,注意此时命令并未真正执行 for (String key : keys) { pipeline.del(key); } // 3)执行命令 pipeline.sync(); }
Jedis中执行Lua脚本和redis-cli十分类似,Jedis提供了三个重要的函数实现Lua脚本的执行:
Object eval(String script, int keyCount, String... params) Object evalsha(String sha1, int keyCount, String... params) String scriptLoad(String script)
以一个最简单的Lua脚本为例子进行说明: return redis.call(‘get‘,KEYS[1])
在redis-cli中执行上面的Lua脚本,方法如下:
eval "return redis.call(‘get‘,KEYS[1])" 1 hello
在Jedis中执行,方法如下:
String key = "hello"; String script = "return redis.call(‘get‘,KEYS[1])"; Object result = jedis.eval(script, 1, key); System.out.println(result);
scriptLoad和evalsha函数要一起使用,首先使用scriptLoad将脚本加载到Redis中,代码如下:
String scriptSha = jedis.scriptLoad(script);
然后执行结果如下:
Stirng key = "hello"; Object result = jedis.evalsha(scriptSha, 1, key); System.out.println(result);
client list命令能列出与Redis服务端相连的所有客户端连接信息。
Redis为每个客户端分配了输入缓冲区,它的作用是将客户端发送的命令临时保存,同时Redis从会输入缓冲区拉取命令并执行,输入缓冲区为客户端发送命令到Redis执行命令提供了缓冲功能,如下图所示。
输入缓冲使用不当会产生两个问题:
Redis为每个客户端分配了输出缓冲区,它的作用是保存命令执行的结果返回给客户端,为Redis和客户端交互返回结果提供缓冲。与输入缓冲区不同的是,输出缓冲区的容量可以通过参数client-output-buffer-limit来进行设置,并且输出缓冲区做得更加细致,按照客户端的不同分为三种:普通客户端、发布订阅客户端、slave客户端,如下图所示。
和输入缓冲区相同的是,输出缓冲区也不会受到maxmemory的限制,如果使用不当同样会造成maxmemory用满产生的数据丢失、键值淘汰、OOM等情况。
Redis支持RDB和AOF两种持久化机制,持久化功能有效地避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化的文件即可实现数据恢复。
RDB持久化是把当前进程数据生成快照保存到硬盘的过程。触发RDB持久化过程分为手动触发和自动触发:
(1)手动触发分别对应save和bgsave命令:
显然bgsave命令是针对save阻塞问题做的优化。因此Redis内部所有的涉及RDB的操作都采用bgsave的方式,而save命令已经废弃。
bgsave命令的运作过程:
(2)自动触发:
RDB的优点:
RDB的缺点:
AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中的命令达到恢复数据的目的。AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式。
AOF默认是默认不开启的,开启AOF功能需要设置配置:appendonly yes。
AOF工作流程:
注:
1. AOF为什么把命令追加到aof_buf中?
Redis使用单线程响应命令,如果每次写AOF文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载。先写入缓冲区aof_buf中,还有另一个好处,Redis可以提供多种缓冲区同步硬盘的策略,在性能和安全性方面做出平衡。
2. AOF缓冲区同步文件策略,由参数appendfsync控制:
appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no #让操作系统决定何时进行同步
3. AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。重写后的AOF文件为什么可以变小?
1)进程内已经超时的数据不再写入文件。
2)旧的AOF文件含有无效命令,重写使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令。
3)多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush list c可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢出,对于list、set、hash、zset等类型操作,以64个元素为界拆分为多条。
AOF重写降低了文件占用空间,除此之外,另一个目的是:更小的AOF文件可以更快地被Redis加载。
【注】如果同时配了RDB和AOF,优先加载AOF。
标签:pipeline tag 不执行 压力 因此 二进制文件 安全性 trim channel
原文地址:https://www.cnblogs.com/toria/p/11343259.html