Redis 是一个 Key-Value 类型的分布式缓存数据库, 以用作数据库、缓存、消息中间件等
官方测试性能数据:
$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -P 16 -q # 优于无流水线。
SET: 552028.75 requests per second
GET: 707463.75 requests per second
LPUSH: 767459.75 requests per second
LPOP: 770119.38 requests per second
$ ./redis-benchmark -r 1000000 -n 2000000 -t get,set,lpush,lpop -q
SET: 122556.53 requests per second
GET: 123601.76 requests per second
LPUSH: 136752.14 requests per second
LPOP: 132424.03 requests per second
看起来相当大哇塞吗,那么redis究竟适合做数据库吗?跟我们其他的分布式内存数据库又有什么区别?
Redis能否做数据库用取决于如下几个条件:
与全量式的RDB持久化功能不同,AOF提供的是增量式的持久化功能, 这种持久化的核心原理在于:服务器每次执行完写命令之后,都会以协议文本的方式将被执行的命令追加到AOF文件的末尾。这样一来,服务 器在停机之后,只要重新执行AOF文件中保存的Redis命令,就可以将 数据库恢复至停机之前的状态。
从表15-3中可以看到,随着服务器不断地执行命令,被执行的命令也会 不断地被保存到AOF文件中(文件中唯一不是用户执行的命令SELECT 0是服务器根据用户正在使用的数据库号码自动加上的)。这样一来, 即使服务器在T4停机,它也可以在重启时通过重新执行AOF文件包含的 命令来恢复数据。对于表15-3中展示的例子来说,服务器只要重新执行 AOF文件中包含的4个命令,就可以让数据库重新回到停机之前的状 态。
为了方便展示,本书在介绍AOF相关内容时,通常会直接写出被执行的命令,但是在实际的AOF文件中,命令都是以Redis网络协议的方式保存的。比如,对于表15-3所示的情况,服务器将创建一个包含代码清单 15-1所示内容的AOF文件(为了能够清晰地辨别各个命令,清单将每个 命令都单独列为一行)。
用户可以通过服务器的appendonly选项来决定是否打开AOF持久化功能: 反之,如果用户想要关闭AOF持久化功能,那么只需要将这个值设置为 no即可。当AOF持久化功能处于打开状态时,Redis服务器在默认情况下将创建 一个名为appendonly.aof的文件作为AOF文件
为了提高程序的写入性能,现代化的操作系统通常会把针对硬盘的多次写操作优化为一次写操作。具体的做法是,当程序调用write系统调用对 文件进行写入时,系统并不会直接把数据写入硬盘,而是会先将数据写 入位于内存的缓冲区中,等到指定的时限到达或者满足某些写入条件 时,系统才会执行flush系统调用,将缓冲区中的数据冲洗至硬盘。 这种优化机制虽然提高了程序的性能,但是也给程序的写入操作带来了不确定性,特别是对于AOF这样的持久化功能来说,AOF文件的冲洗机制将直接影响AOF持久化的安全性。为了消除上述机制带来的不确定 性,Redis向用户提供了appendfsync选项,以此来控制系统冲洗AOF文件的频率:
appendfsync选项拥有always、everysec和no 3个值可选,它们代表的意义分别为:
always——每执行一个写命令,就对AOF文件执行一次冲洗操作。
everysec——每隔1s,就对AOF文件执行一次冲洗操作。
no——不主动对AOF文件执行冲洗操作,由操作系统决定何时对AOF 进行冲洗。
这3种不同的冲洗策略不仅会直接影响服务器在停机时丢失的数据量, 还会影响服务器在运行时的性能:
在使用always值的情况下,服务器在停机时最多只会丢失一个命令的数 据,但使用这种冲洗方式将使Redis服务器的性能降低至传统关系数据 库的水平。
在使用everysec值的情况下,服务器在停机时最多只会丢失1s之内产生的命令数据,这是一种兼顾性能和安全性的折中方案。
在使用no值的情况下,服务器在停机时将丢失系统最后一次冲洗AOF 文件之后产生的所有命令数据,至于数据量的具体大小则取决于系统冲 洗AOF文件的频率。
因为no策略给可能丢失的数据量带来了不确定性,而always策略对于安全性的追求又牺牲了服务器的性能,所以Redis使用everysec作为 appendfsync选项的默认值。除非有明确的需求,否则用户不应该随意修改appendfsync选项的值。
随着服务器不断运行,被执行的命令将变得越来越多,而负责记录这些 命令的AOF文件也会变得越来越大。与此同时,如果服务器曾经对相同 的键执行过多次修改操作,那么AOF文件中还会出现多个冗余命令。
举个例子,对于代码清单15-2所示的AOF文件:
随着服务器不断运行,被执行的命令将变得越来越多,而负责记录这些 命令的AOF文件也会变得越来越大。与此同时,如果服务器曾经对相同 的键执行过多次修改操作,那么AOF文件中还会出现多个冗余命令。
冗余命令的存在不仅增加了AOF文件的体积,并且因为Redis服务器在 停机之后需要通过重新执行AOF文件中保存的命令来恢复数据,所以 AOF文件中的冗余命令越多,恢复数据时耗费的时间也会越多。为了减 少冗余命令,让AOF文件保持“苗条”,并提供数据恢复操作的执行速 度,Redis提供了AOF重写功能,该功能能够生成一个全新的AOF文件,并且文件中只包含恢复当前数据库所需的尽可能少的命令。
对于上图几个关键点:
1、在重写期间,由于主进程依然在响应命令,为了保证最终备份的完整性;因此它依然会写入旧的AOF file中,如果重写失败,能够保证数据不丢失。
2、为了把重写期间响应的写入信息也写入到新的文件中,因此也会为子进程保留一个buf,防止新写的file丢失数据。如果主进程收到了写请求,子进程和父进程是通过管道的方式进行发送这个期间发生的请求,所以这个期间写操作并不会丢失。
3、重写是直接把当前内存的数据生成对应命令,并不需要读取老的AOF文件,最后通过 rename 完成文件的替换工作。
与RDB持久化可能会丢失大量数据相比,AOF持久化的安全性要高得多:通过使用everysec选项,用户可以将数据丢失的时间窗口限制在1s 之内,QPS据说也能上万,起码也比mysql高10倍了。其实你会发现内存数据库大多采用这种策略,比如es也是1s去刷一次盘,只不过es的数据结构又比redis复杂一些
但是与RDB持久化相比,AOF持久化也有相应的缺点:
如果用做单独使用Redis的话,它是成当不起数据库的任务,比如你每日活跃用户是1万人,但是你那台redis里面已经积累了50万人了(这个比例很正常),那么每次redis启动,就需要把50万load内存,每次redis备份,又需要把50万dump到磁盘,这个恢复过程是无法承受之痛,当然你也是使用主备,主坏了切备就是。
总结:
参考:
1、https://blog.csdn.net/norang/article/details/119832677?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-119832677-blog-122422724.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-119832677-blog-122422724.pc_relevant_default&utm_relevant_index=2
2、https://blog.csdn.net/u012516914/article/details/122422724?spm=1001.2101.3001.6650.5&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5-122422724-blog-119832677.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5-122422724-blog-119832677.pc_relevant_aa&utm_relevant_index=10