Redis是什么?
Redis是单线程,nosql一种数据库框架,采用key-value存储,使用IO多复路,skiptable(调表结构等),内涵多个丰富数据结构,基于内存实现,支持网络,支持分布式锁,队列,订阅/发布,布隆过滤器等功能
据说5.0之后采用多线程,为了优化插入,删除,添加之后操作
看过官网得同学都知道,官网有过这么一段话,Redis得性能瓶颈不是CPU而是内存和网络,为了减少复杂度开发而采用单线程。
Redis数据结构有哪些
据我所知一般有以下五种结构
String
(一般用于存储简单JSON字符串对象)
hash(哈希类型 比如hget,hset,hkeys,havls)
(一般缓存JAVA对象hashMap得结构)
list(列表类型,lpush lpop lpushx lset等等)
(类似java ArrayList LindedList(双端列表),用于队列,延迟队列等)
set(集合类型,无序,sadd spop smove scard 等)
(用于差集交集运算,查询好友等)
zset(集合类型,有序,根据score进行排序,zadd zpop等等)
sds (简单动态字符串)
基于C语言中传统字符串的缺陷,Redis自己构建了一种名为简单动态字符串的抽象类型,简称SDS
SDS几乎贯穿了Redis的所有数据结构,应用十分广泛。
SDS的特点
和C字符串相比,SDS的特点如下:
1. 常数复杂度获取字符串长度
Redis中利用SDS字符串的len属性可以直接获取到所保存的字符串的长度,直接将获取字符串长度所需的复杂度从C字符串的O(N)降低到了O(1)。
2. 减少修改字符串时导致的内存重新分配次数
通过C字符串的特性,我们知道对于一个包含了N个字符的C字符串来说,其底层实现总是N+1个字符长的数组(额外一个空字符结尾)
那么如果这个时候需要对字符串进行修改,程序就需要提前对这个C字符串数组进行一次内存重分配(可能是扩展或者释放)而内存重分配就意味着是一个耗时的操作。
Redis巧妙的使用了SDS避免了C字符串的缺陷。在SDS中,buf数组的长度不一定就是字符串的字符数量加一,buf数组里面可以包含未使用的字节,而这些未使用的字节由free属性记录。
与此同时,SDS采用了空间预分配的策略,避免C字符串每一次修改时都需要进行内存重分配的耗时操作,将内存重分配从原来的每修改N次就分配N次——>降低到了修改N次最多分配N次。
如下是Redis对SDS的简单定义:
有兴趣得同学阔以深入了解SDS,目前只针对面试,所以本文不做深入阐述!!!!
Redis结构图
Redis 单机,主备,哨兵 ,集群应用场景?
Redis 单机
一般应用于单个系统,并发量并不是很高,Redis作为一个过度的缓存数据库
Redis 主备
1、redis的复制功能是支持多个数据库之间的数据同步。一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操作,当发生写操作的时候自动将数据同步到从数据库,而从数据库一般是只读的,并接收主数据库同步过来的数据,一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库。
2、通过redis的复制功能可以很好的实现数据库的读写分离,提高服务器的负载能力。主数据库主要进行写操作,而从数据库负责读操作。
具体流程如下图 :
1:slave数据库启动时,会向主数据库发送sync命令
2:主数据库接收到sync命令后会开始在后台保存快照(执行rdb操作),并将保存期间接收到的命令缓存起来
3:master快照完成后,redis会将快照文件和所有缓存的命令发送给slave数据库。
4:salve接收到后,会载入快照文件并执行收到的缓存的命令。
redis 6379.conf master
bind 127.0.0.1
port 6379
logfile "6379.log"
dbfilename "dump-6379.rdb"
如下是端口为6380和6381的从机的配置:
bind 127.0.0.1
port 6380
logfile "6380.log"
dbfilename "dump-6380.rdb"
slaveof 127.0.0.1 6379
bind 127.0.0.1
port 6381
logfile "6381.log"
dbfilename "dump-6381.rdb"
slaveof 127.0.0.1 6379
redis主备应用场景
数据备份,读写分离,如果Redis挂掉缓存数据没有办法访问或有可能造成程序停止状态运行,解决单例可能存在的性能问题
redis 主备存在得问题
主从模式下可以将读写操作分配给不同的实例进行从而达到提高系统吞吐量的目的,但也正是因为这种方式造成了使用上的不便,因为每个客户端连接redis实例的时候都是指定了ip和端口号的,如果所连接的redis实例因为故障下线了,而主从模式也没有提供一定的手段通知客户端另外可连接的客户端地址,因而需要手动更改客户端配置重新连接。另外,主从模式下,如果主节点由于故障下线了,那么从节点因为没有主节点而同步中断,因而需要人工进行故障转移工作如何解决呢? 请看下文
Redis哨兵模式(sentinel)
为了解决上列问题,redis在2.8版本之后引入了哨兵架构
哨兵(sentinel) 是一个分布式系统,但是不能真正得解决每一个slave负载均衡等分布式需求,你可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossipprotocols)来接收关于Master是否下线的信息,并使用投票协议(agreement protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master.
哨兵(sentinel) 为一个单独的可执行文件 redis-sentinel ,但实际上它只是一个运行在特殊模式下的 Redis 服务器,你可以在启动一个普通 Redis 服务器时通过给定 --sentinel 选项来启动哨兵(sentinel).
架构得特点:
监控(Monitoring): 哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。
提醒(Notification):当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover):当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作,它会将失效Master的其中一个Slave升级为新的Master, 并让失效Master的其他Slave改为复制新的Master; 当客户端试图连接失效的Master时,集群也会向客户端返回新Master的地址,使得集群可以使用Master代替失效Master。
每个哨兵(sentinel) 会向其它哨兵(sentinel-2)、master、slave定时发送消息,以确认对方是否”活”着,如果发现对方在指定时间(可配置)内未回应,则暂时认为对方已挂(主观认为宕机”Subjective Down,简称sdown).
若“哨兵群”中的多数sentinel,都发现master没响应,系统认为master"彻底死亡"(即:客观上的真正down机,Objective Down,简称odown),通过一定的vote(摩尔投票算法)算法,从剩下的slave节点中,选一台提升为master,然后自动修改相关配置于zk选举挺相似
如图:
Redis 哨兵实现步骤
1.拷贝到etc目录
cp sentinel.conf /usr/local/redis/etc
2.修改sentinel.conf配置文件
sentinel monitor mymast 192.168.110.133 6379 1 #主节点 名称 IP 端口号 选举次数
3. 修改心跳检测 5000毫秒
sentinel down-after-milliseconds mymaster 5000
4.sentinel parallel-syncs mymaster 2 --- 做多多少合格节点
5. 启动哨兵模式
./redis-server /usr/local/redis/etc/sentinel.conf --sentinel &
6. 停止哨兵模式
或者阔以参考:
https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247487959&idx=1&sn=2dbaf85f586da26f6f218a21ea01d0de&chksm=ebd62efbdca1a7ed051e7a2b87729bcf3731159dda729f7104af225c63e4e2bec8f18764b223&scene=21#wechat_redirect
Redis集群
Redis Cluster 是Redis.3.0推出得一个版本,阔以解决分布式这个方面得需求,当遇到单机内存瓶颈,并发和流量时,可采用Redis Cluster达到负载均衡得目的,Redis哨兵模式解决故障转移问题及主节点无法识别新得可用节点问题,但是slave节点下线,redis sentinel不会进行故障转移,cluster完美得解决此类问题
redis集群中数据是和槽(slot)挂钩的,其总共定义了16384个槽,所有的数据根据一致哈希算法会被映射到这16384个槽中的某个槽中;另一方面,这16384个槽是按照设置被分配到不同的redis节点上的。
Redis事务
Redis事务可以执行多条命令,不具备mysql事务相等得功能回滚啥之类得
特点:
命令序列化,按照顺序执行
原子性(指令执行顺序得原子性,不会被其它客户端打断)
执行过程的三个阶段:
开始事务---->命令队列-----> 执行事务
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> SET book-name "aaaa"
QUEUED
redis 127.0.0.1:6379> GET book-name
QUEUED
redis 127.0.0.1:6379> SADD tag "bbbb" "cccc" "dddd"
QUEUED
redis 127.0.0.1:6379> SMEMBERS tag
QUEUED
redis 127.0.0.1:6379> EXEC
1) OK
"dddd"
"Mastering Series"
"bbbb"
"cccc"
Redis 事务的相关命令 可行百度查看
Redis持久化
什么是持久化?什么是Redis持久化?
持久化指数据永久的保存
redis持久化指把内存数据保存到硬盘
Redis持久化方式?优缺点?
RDB
RDB是一种快照存储持久化方式 存储某个时刻的指令及数据,具体就是将Redis某一时刻的内存数据保存到硬盘的文件当中,默认保存的文件名为dump.rdb,而在Redis服务器启动时,会重新加载dump.rdb文件的数据到内存当中恢复数据
优点:
使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能
于AOP方式恢复数据,RDB快
RDB生成文件比较紧凑,适合数据备份
RDB备份,都是由子进程(子进程是同步的),不影响Redis服务器性能就算有也是比较小
缺点
RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。适合数据要求不严谨的时候,具体间隔时间阔以自行设置
RDB使用save指令时,会造成服务器堵塞,之到数据同步完成才可接收后续请求
RDB使用bgsave指令,如果数据量太大,forks过程有可能发生堵塞,forks子进程会消耗内存
开启RDB持久化方式
客户端像Redis服务器执行一段save/bgsave命令就可生成文件或者通过服务器配置文件触发RDB快照存储条件
客户端指定:
1.save命令
# 同步数据到磁盘上
> save
当客户端向服务器发送save命令请求进行持久化时,服务器会阻塞save命令之后的其他客户端的请求,直到数据同步完成。
如果数据量太大,同步数据会执行很久,而这期间Redis服务器也无法接收其他请求,所以,最好不要在生产环境使用save命令。
2.bgsave
于save命令不同,它是一个异步操作
当客户端发服务发出bgsave命令时,Redis服务器主进程会forks一个子进程来数据同步问题,在将数据保存到rdb文件之后,子进程会退出。
所以,与save命令相比,Redis服务器在处理bgsave采用子线程进行IO写入,而主进程仍然可以接收其他请求,但forks子进程是同步的,forks子进程时不能接收其他请求,如果forks一个子进程花费的时间太久(一般是很快的),bgsave命令会有阻塞其他客户的请求的情况发生。
服务器配置保存指令
RDB是默认开启,感兴趣的童靴阔以下一个windows版本或者自行安装查看(linux)redis.conf
(windows)redis.windows.conf
#dbfilename:持久化数据存储在本地的文件,可自行修改RDB名字
dbfilename dump.rdb
#dir:持久化数据存储在本地的路径,如果是在/redis/redis-3.0.6/src
#下启动的redis-cli,则数据会存储在当前src目录下
dir ./
##snapshot触发的时机,save
##如下为900秒后,至少有一个变更操作,才会snapshot
##对于此值的设置,需要谨慎,评估系统的变更操作密集程度
##可以通过“save “””来关闭snapshot功能
# 900s内至少达到一条写命令
save 900 1
# 300s内至少达至10条写命令
save 300 10
# 60s内至少达到10000条写命令
save 60 10000
##当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,
##“错误”可能因为磁盘已满/磁盘故障/OS级别异常等
stop-writes-on-bgsave-error yes
##是否启用rdb文件压缩,默认为“yes”,压缩往往意味着“额外的cpu消耗”,
##同时也意味这较小的文件尺寸以及较短的网络传输时间
rdbcompression yes
于bgsave命令相似,当达到触发条件时,forks一个子进程会执行进行同步指令
介意:最好不要通过这种方式进行同步,设置时间太短容易造成频繁写入RDB,影响服务器性能,太长时间会造成数据丢失
RDB文件生成过程
- redis服务器安装启动时,会默认生成临时rdb文件,并写入数据
- 完成数据写入,用临时文件代替正式的rdb文件
- 删除原来的db文件
介意多机Redis服务器进程时,阔以修改rdb名字做为区分 可参考上列文件
AOF
AOF持久化方式会存储记录客服端对服务器每一次操作的指令,并将这些操作指令以Redis协议追加保存到aof文件后缀末尾,服务器重启时,会加载并运行aof,从而达到恢复数据的目的
优点 :
它与mysql binlog日志相似,如果aof文件设置追加的时间是一秒的话,那么丢失的只会是一秒数据,保证了更高数据的完整性
日志写入不完整可通过redis-check-aop
如果aof没被重写之前,文件较大,aof会自动进行重写 比如bgrewriteaof no-appendfsync-on-rewrite
缺点:
AOF 文件比 RDB 文件大,且恢复速度慢
执行过程如图:
开启AOF持久化方式
Redis默认不开启AOF
#开启aof机制
appendonly yes
# aof文件名
appendfilename "appendonly.aof"
# 写入策略,always表示每个写操作都保存到aof文件中,也可以是everysec或no
appendfsync always
# 默认不重写aof文件
no-appendfsync-on-rewrite no
##aof文件rewrite触发的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才会触发rewrite,默认“64mb”,建议“512mb”
auto-aof-rewrite-min-size 64mb
##相对于“上一次”rewrite,本次rewrite触发时aof文件应该增长的百分比。
##每一次rewrite之后,redis都会记录下此时“新aof”文件的大小(例如A),
##那么当aof文件增长到A*(1 + p)之后
##触发下一次rewrite,每一次aof记录的添加,都会检测当前aof文件的尺寸。
auto-aof-rewrite-percentage 100
##指定aof写入策略
###默认为everysec 下列会做详细讲解
appendfsync everysec
# 保存目录
dir ~/redis/
AOF三种写入策略
1. always
客户端的每一个写操作都保存到aof文件当,这种策略很安全,但是每个写请注都有IO操作,所以也很慢。
2. everysec
appendfsync的默认写入策略,每秒写入一次aof文件,因此,最多可能会丢失1s的数据。
3. no
Redis服务器不负责写入aof,而是交由操作系统来处理什么时候写入aof文件。更快,但也是最不安全的选择,不推荐使用。
AOF重写
AOF将客户端的每一个写操作都追加到aof文件末尾,指将多个指令相同的key进行重写,生成一个最少命令集
两种重写方式
通过在redis.conf配置文件中的选项no-appendfsync-on-rewrite可以设置是否开启重写,这种方式会在每次fsync时都重写,影响服务器性,因此默认值为no,不推荐使用。
# 默认不重写aof文件
no-appendfsync-on-rewrite no
客户端向服务器发送bgrewriteaof命令,也可以让服务器进行AOF重写
# 让服务器异步重写追加aof文件命令
> bgrewriteaof
AOF重写方式也是异步操作,即如果要写入aof文件,则Redis主进程会forks一个子进程来处理,如下所示:
重写aof文件的好处
- 压缩aof文件,减少磁盘占用量。
- 将aof的命令压缩为最小命令集,加快了数据恢复的速度。
AOF文件损坏
在写入aof日志文件时,如果Redis服务器宕机,则aof日志文件文件会出格式错误,在重启Redis服务器时,Redis服务器会拒绝载入这个aof文件,可以通过以下步骤修复aof并恢复数据。
1、备份现在aof文件,以防万一。
2、使用redis-check-aof命令修复aof文件,该命令格式如下:
# 修复aof日志文件
$ redis-check-aof -fix file.aof
3、重启Redis服务器,加载已经修复的aof文件,恢复数据。
Redis订阅发布,队列不做详细补充,百度上案例太多了0.0.
总结:
如果你只是单纯把Redis作为缓存服务器,那么可以完全不用考虑持久化,在大多数企业级bat中redis只扮演着cache service角色 。AOF更加安全,阔以及时更新文件到文件中,恢复相对比较慢
关于Redis hash一致性算法 布隆过滤器 hyperLoglog,redis令牌,redis漏洞限流后续后面慢慢有时间进行学习和更新
参考: