redis技术梳理

适用于如下场景:

对数据高并发处理

对大数据高效率存储和访问

对数据高可用及高扩展


RedisNoSQL数据库的一种Redis是以KV方式存储数据库

特点:非关系,分布,开源,可扩展,高速内存操作。

适合运行在廉价的pc服务器上分布式处理海量数据

Redis是一个开源的,先进的kv存储方式的数据库,通常叫数据结构服务器,键可以包含字符串strings,哈希hasheslists链表,集合sets,有序集合sorted sets/zsets,这些数据类型支持pushpopaddmove及集合等操作,支持各种不同方式排序,为了提供性能,数据都在内存中,为了数据可靠根据需要周期更新数据到磁盘或日志记录文件。

待续:

redis 持久化缓存:

一:SNAPSHOTTING(快照方式 -》二进制文件)

①定时生成快照

②定量生成快照

观察redis的配置文件中的SNAPSHOTTING设置模块的设置信息,我们可以发现

redis技术梳理_第1张图片

上图已经对save命令的意思做出了解释,现在我再来说一下,意思就是:

save  900  1      每900秒(15分钟)至少一次键值变更时被触发;

redis技术梳理_第2张图片 

##当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,“错误”可能因为磁盘已满/磁盘故障/OS级别异常等  
stop-writes-on-bgsave-error yes  


rdbcompression 

RDB文件过大时,是可以压缩的,Redis默认开启压缩,当然也可以通过配置rdbcompression参数来禁用压缩

压缩和不压缩的优缺点:

压缩:

优点:减少磁盘存储空间
缺点:消耗CPU资源

不压缩:

优点:不消耗CPU资源
缺点:占用磁盘空间多

如何选择? 那就需要看需求、看服务器资源情况了。

RDB的快照过程:

1.redis 调用 fork,现在有了子进程和父进程。

2. 父进程继续处理 client 请求,子进程负责将内存内容写入到临时文件。由于 os 的实时复制机制( copy on write)父子进程会共享相同的物理页面,当父进程处理写请求时 os 会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程地址空间内的数据是 fork时刻整个数据库的一个快照。

3.当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出。client 也可以使用 save 或者 bgsave 命令通知 redis 做一次快照持久化。 save 操作是在主线程中保存快照的,由于 redis 是用一个主线程来处理所有 client 的请求,这种方式会阻塞所有client 请求。所以不推荐使用。另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步变更数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘 io 操作,可能会严重影响性能。

手动快照:

如果没有触发自动快照,可以对redis进行手动快照操作,SAVE和BGSAVE都可以执行手动快照,两个命令的区别是前者是由主进程进行快照操作,会阻塞其他请求;而后者是通过fork子进程进行快照操作。

redis技术梳理_第3张图片

注意:

由于redis使用fork来复制一份当前进程,那么子进程就会占有和主进程一样的内存资源,比如说主进程8G内存,那么在备份的时候必须保证有16G内存,要不然会启用虚拟内存,性能非常差。

工作原理

  • Redis forks.
  • 子进程开始将数据写到临时RDB文件中。
  • 当子进程完成写RDB文件,用新文件替换老文件。
  • 这种方式可以使Redis使用copy-on-write技术。

写时复制(copy-on-write/COW)技术:

写入时复制(Copy-on-write)是一个被使用在程式设计领域的最佳化策略。其基础的观念是,如果有多个呼叫者(callers)同时要求相同资源,他们会共同取得相同的指标指向相同的资源,直到某个呼叫者(caller)尝试修改资源时,系统才会真正复制一个副本(private copy)给该呼叫者,以避免被修改的资源被直接察觉到,这过程对其他的呼叫只都是通透的(transparently)。此作法主要的优点是如果呼叫者并没有修改该资源,就不会有副本(private copy)被建立。


二:APPEND ONLY MODE(aof类似于预写日志)

①后台执行

②边服务边备份

Redis AOF是类似于log的机制,每次写操作都会写到硬盘上,当系统崩溃时,可以通过AOF来恢复数据。每个带有写操作的命令被Redis服务器端收到运行时,该命令都会被记录到AOF文件上。由于只是一个append到文件操作,所以写到硬盘上的操作往往非常快。

其实Redis oaf机制包括了两件事,rewrite和AOF。rewrite类似于普通数据库管理系统日志恢复点,当AOF文件随着写命令的运行膨胀时,当文件大小触碰到临界时,rewrite会被运行。
rewrite会像replication一样,fork出一个子进程,创建一个临时文件,遍历数据库,将每个key、value对输出到临时文件。输出格式就是Redis的命令,但是为了减小文件大小,会将多个key、value对集合起来用一条命令表达。在rewrite期间的写操作会保存在内存的rewrite buffer中,rewrite成功后这些操作也会复制到临时文件中,在最后临时文件会代替AOF文件。

以上在AOF打开的情况下,如果AOF是关闭的,那么rewrite操作可以通过bgrewriteaof命令来进行。

Redis Bgrewriteaof 命令用于异步执行一个 AOF(AppendOnly File) 文件重写操作。重写会创建一个当前 AOF 文件的体积优化版本。

即使 Bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 Bgrewriteaof 成功之前不会被修改。

注意:从 Redis 2.4 开始, AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操作。

自动的bgrewriteaof

为了避免aof文件过大,我们会周期性的做bgrewriteaof来重整aof文件。以前我们会额外的配置crontab在业务低峰期执行这个命令,这额外的增加一个workaroud的脚本任务在大集群里是很糟糕的,不易检查,出错无法即时发现。

于是这个自动bgrewriteaof功能被直接加到redis的内部。首先对于aof文件,server对象添加一个字段来记录aof文件的大小server.appendonly_current_size,每次aof发生变化都会维护这个字段。

bgrewriteaof完毕或者实例启动载入aof数据后也会调用aofUpdateCurrentSize这个函数维护这个字段,同时会记录下此时的aof文件的大小server.auto_aofrewrite_base_size作为基准值,用于接下来判断aof增长率。

有了当前值和基准值我们就可以判断aof文件的增长情况。另外还需要配置两个参数来判断是否需要自动触发bgrewriteaof。

 auto-aof-rewrite-percentage:aof文件的大小超过基准百分之多少后触发bgrewriteaof。默认这个值设置为100,意味着当前aof是基准大小的两倍的时候触发bgrewriteaof。把它设置为0可以禁用自动触发的功能。
auto-aof-rewrite-min-size: 当前aof文件大于多少字节后才触发。避免在aof较小的时候无谓行为。默认大小为64mb。
两个参数都是可以在conf里静态配置,或者通过config set来动态修改的。

redis技术梳理_第4张图片

appendonly  是否开启aof缓存机制

appendfilename    aof文件的名称

appendfsync   的三种执行方式:

调用fsync()方式让操作系统写数据到磁盘上,数据同步方式,有下列三种模式

always          每次都调用,比如安全,但速度最慢;

everysec       每秒同步,这也是默认方式;

no              不调用fsync,由操作系统决定何时同步,比如快的模式;

no-appendfsync-on-rewrite   no

如上面所说到的bgrewriteaof机制,在一个子进程中进行aof的重写,从而不阻塞主进程对其余命令的处理,同时解决了aof文件过大问题。现在问题出现了,同时在执行bgrewriteaof操作和主进程写aof文件的操作,两者都会操作磁盘,而bgrewriteaof往往会涉及大量磁盘操作,这样就会造成主进程在写aof文件的时候出现阻塞的情形,现在no-appendfsync-on-rewrite参数出场了。如果该参数设置为no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为yes呢?这就相当于将appendfsync设置为no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候redis挂掉,就会丢失数据。丢失多少数据呢?在linux的操作系统的默认设置下,最多会丢失30s的数据。

因此,如果应用系统无法忍受延迟,而可以容忍少量的数据丢失,则设置为yes。如果应用系统无法忍受数据丢失,则设置为no。

写数据的流程:

    1. 客户端向服务端发送写操作(数据在客户端的内存中)。
    2. 数据库服务端接收到写请求的数据(数据在服务端的内存中)。
    3. 服务端调用write这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)。
    4. 操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)。
    5. 磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)。

三.总结:

AOF和RDB各有优缺点,这是有它们各自的特点所决定:

  • 1) AOF更加安全,可以将数据更加及时的同步到文件中,但是AOF需要较多的磁盘IO开支,AOF文件尺寸较大,文件内容恢复数度相对较慢。
    *2) snapshot,安全性较差,它是“正常时期”数据备份以及master-slave数据同步的最佳手段,文件尺寸较小,恢复数度较快。

可以通过配置文件来指定它们中的一种,或者同时使用它们(不建议同时使用),或者全部禁用,在架构良好的环境中,master通常使用AOF,slave使用snapshot,主要原因是master需要首先确保数据完整性,它作为数据备份的第一选择;slave提供只读服务(目前slave只能提供读取服务),它的主要目的就是快速响应客户端read请求;但是如果你的redis运行在网络稳定性差/物理环境糟糕情况下,建议你master和slave均采取AOF,这个在master和slave角色切换时,可以减少“人工数据备份”/“人工引导数据恢复”的时间成本;如果你的环境一切非常良好,且服务需要接收密集性的write操作,那么建议master采取snapshot,而slave采用AOF。

Redis数据恢复

当redis服务器挂掉时,重启时将按以下优先级恢复数据到内存种:

1. 如果只配置了AOF,重启时加载AOF文件恢复数据.

2. 如果同时配置了RBD和AOF,启动时只加载AOF文件恢复数据.

3. 如果只配置了RDB,启动时将加载dump文件恢复数据.

问题总结

这是我在redis使用中,所遇到的一些问题,以及解决方案:

①Redis低版本无法向前兼容高版本RDB文件

问题的:在模拟redis集群中主redis kill掉之后且没有开启redis aof追加模式的情况下,去读取从redis的rdb快照文件,来恢复数据

主redis:redis_version:2.8.17

从服务器:redis_version:3.2.8

造成影响就是主redis无法启动了。

解决方案就是:删除掉主redis上的rdb文件就可以了。

②redis 安全模式所造成的:

在配置文件redis.conf中,默认的bind 接口是127.0.0.1,也就是本地回环地址。
这样的话,访问redis服务只能通过本机的客户端连接,而无法通过远程连接,
这样可以避免将redis服务暴露于危险的网络环境中,防止一些不安全的人随随便便通过远程
连接到redis服务。
如果bind选项为空的话,那会接受所有来自于可用网络接口的连接。

但是那样会接到redis安全模式的报错:

-DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.
译文:
否认redis是因为保护模式是启用保护模式运行,没有指定绑定地址,没有密码要求的客户。在这种模式下,连接只接受环回接口。如果你想连接外部计算机使用您可以通过下面的一个解决方案:1)只禁用保护模式发送命令的配置设置保护模式没有从环回接口通过从同一主机运行的服务器连接到redis,但是确保如果你不公开访问redis来自互联网。使用配置重写使此更改永久。2)或者你可以仅仅通过编辑redis配置文件禁用保护模式,并设置保护模式选择“否”,然后重新启动服务器。3)如果您只是为了测试而手动启动服务器,则用“保护模式NO”选项重新启动它。4)设置绑定地址或身份验证密码。注意:您只需要做上面的其中一件事情,以便服务器开始接受来自外部的连接。

解决方案:设置密码,或者远程连接的ip

redis内置高并发测试工具测试结果

Redis-benchmark是官方自带的Redis性能测试工具,可以有效的测试Redis服务的性能。
经测试发现,redis处理100000个请求set、get请求需要处理的时间分别是1.58秒和1.53秒。
经测试,redis承受10000的并发,处理100000个set、get请求,需要处理的时间为2.35秒和2.5秒。
经测试,redis测试承受50000的高并发处理100000个请求已经在支持不了了。提示:无法分配请求的地址。 redis技术梳理_第5张图片
经多次测试,redis测试承受的最大限度是10000-20000高并发 处理100000个请求。
以上测试均是基于:

redis技术梳理_第6张图片

默认最大连接数为10000,一旦达到最大限制,redis将关闭所有的新连接,并发送一个“max number of clients reached”的错误



你可能感兴趣的:(redis)