redis
Redis简介
随着互联网+和大数据时代的来临,传统的关系型数据库已经不能满足中大型网站日益增长的访问量和数据量,这个时候就需要一种能够快速存取数据的组件来缓解数据库服务I/O的压力 ,来解决系统性能上的瓶颈。
数据库应用的发展历史:
1: 在互联网大数据时代来临前,企业的一些内部信息管理系统,一个单个数据库实例就可以应付系统的需求
单数据库实例
2: 随着系统访问量用户的增多,数据量的增大 ,单个数据库实例已经满足不了系统读取数据的需求
缓存(ehCache/MemCached)+数据库实例
3: 缓存可以缓解数据库的读取压力,但是数据量的写入压力持续增大,可以采取数据库主从进行读写分离
缓存+主从数据库+读写分离
4: 数据量再次增大,读写分离以后 ,主数据库的写库压力出现瓶颈
缓存+主从数据库集群+读写分离 +分库分表
5 :互联网+大数据时代来临,关系型数据库不能很好的存取一些并发性大,实时性高而且格式不固定的数据
NoSql数据库 +主从数据库集群+读写分离 +分库分表
什么是redis?
Redis是当前比较热门的NOSQL数据库系统之一,它是一个开源的使用C语言编写的键值对(key-value)数据存储系统(区别于MySQL的二维表格的形式存储)。
- NoSql: Not Only Sql 泛指非关系型数据库,如:Redis / MongoDB/Hbase
- 关系型数据库 : Oracle/ Mysql/ SqlServer
左边rdbms右边nosql很多以json格式进行存储数据的(mongodb,redis)
Redis和Memcache类似,但很大程度补偿了Memcache的不足,Redis数据都是缓存在计算机内存中,不同的是,Memcache只能将数据缓存到内存中,无法自动定期写入硬盘,这就表示,一断电或重启,内存清空,数据丢失。所以Memcache的应用场景适用于缓存无需持久化的数据。而Redis不同的是它会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,实现数据的持久化.
Redis的特点
1、Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
2、Redis不仅仅支持简单的key-value类型的数据,同时还提供字符串(strings)、lists(列表)、sets(集合)和zsets(有序集合)、散列(hash)等数据结构的存储。
3、Redis支持数据的备份,即master-slave模式的数据备份。
4、性能极高:Redis能读的速度是110000次/s,写的速度是81000次/s 。
5、原子性:Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
6、丰富的特性:Redis还支持 publish(发布)/subscribe(订阅), 通知, key 过期等等特性。
Redis与memcache的区别:
1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。
2、数据结构:Memcache仅能支持简单的K-V形式,Redis不仅仅支持简单的k/v类型的数据,同时还提供字符串(strings)、lists(列表)、sets(集合)和zsets(有序集合)、散列(hash)等数据结构的存储。
3、虚拟内存:Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘。Memcache当内存用完之后,会根据LRU策略,计算最近没有使用过的数据,将其进行替换。
4、过期策略:memcache在set时就指定,例如set key 1008,即永不过期。Redis可以通过例如expire 设定,例如expire name 10
5、分布式:redis可以做一主多从。Memcached的分布式不是在服务器端实现的,而是在客户端应用中实现的,即通过内置算法制定目标数据的节点,如下图所示
6、存储数据安全:memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)
7、灾难恢复:memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复
8、Redis支持数据的备份,即master-slave模式的数据备份。
9、Memcache支持多线程,Redis支持单线程,CPU利用方面,Memcache利用率更高。
10、应用场景: Memcache做缓存,适合多读少写,大数据量的情况(如人人网大量查询用户信息、好友信息、文章信息等),减轻数据库负载,提升性能。Redis适用于对读写效率要求都很高,数据处理业务复杂和对安全性要求较高的系统(如新浪微博的计数和微博发布部分系统,对数据安全性、读写要求都很高)。
Redis服务端的默认端口是:6379
持久化的两种方式:
由于Redis的数据都存放在内存中,如果没有配置持久化,Redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当Redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化:
一种是RDB持久化,原理是将Reids在内存中的数据定时dump到磁盘上。性能高,但可能会引起一定程度的数据丢失。
另外一种是AOF(append only file)持久化,原理是将Reids的操作日志以追加的方式写入文件,类似MySQL的binlog,记录每次更新的日志。
Redis的应用场景:
以电商平台为例,Redis在系统架构中的一个位置
单点登陆/直播平台里面在线好友列表/抢购、秒杀/商品的排行榜/点赞/数据过期
Redis的应用场景:
1、缓存(热点数据的缓存)
热点数据(经常会被查询,但是不经常被修改或者删除的数据),由于redis访问速度块、支持的数据类型比较丰富,首选是使用redis缓存。
Select 数据库前查询redis,有的话使用redis数据,放弃select 数据库,没有的话,select 数据库,然后将数据插入redis
update或者delete数据前,查询redis是否存在该数据,存在的话先删除redis中数据,然后再update或者delete数据库中的数据
缓存现在几乎是所有中大型网站都在用的,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。另外结合expire,我们可以设置过期时间然后再进行缓存更新操作。所以,现在Redis用在缓存的场合非常多。
2、排行榜
很多网站都有排行榜应用的,如京东的月度销量榜单、商品按时间的上新排行榜等。Redis提供的有序集合数据类构能实现各种复杂的排行榜应用。
3、计数器
什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,并发量高时如果每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景。
4、消息系统
消息队列是大型网站必用中间件,如ActiveMQ、RabbitMQ、Kafka等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。
还有其他应用场景,就不一一介绍了。
Redis部署方案
Redis的几种常见使用方式包括:
redis单机模式
Redis单机模式,采用单个Redis节点部署架构,没有备用节点实时同步数据,不提供数据持久化和备份策略,适用于数据可靠性要求不高的纯缓存业务场景。
优点:
• 架构简单,部署方便;
• 高性价比:缓存使用时无需备用节点(单实例可用性可以用supervisor或crontab保证),当然为了满足业务的高可用性,也可以牺牲一个备用节点,但同时刻只有一个实例对外提供服务;
缺点:
• 不保证数据的可靠性;
• 在缓存使用,进程重启后,数据丢失,即使有备用的节点解决高可用性,但是仍然不能解决缓存预热问题,因此不适用于数据可靠性要求高的业务;
• 高性能受限于单核CPU的处理能力(Redis是单线程机制),CPU为主要瓶颈,所以适合操作命令简单,排序、计算较少的场景。也可以考虑用Memcached替代。
Redis多副本(主从)
Redis多副本,采用主从(replication)部署结构,相较于单副本而言最大的特点就是主从实例间数据实时同步,并且提供数据持久化和备份策略。主从实例部署在不同的物理服务器上,根据公司的基础环境配置,可以实现同时对外提供服务和读写分离策略。
Redis sentinel(哨兵模式) sentinel [ˈsentɪnl]
当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)没有实现自动进行主备切换,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。
Redis Sentinel是社区版本推出的原生高可用解决方案,其部署架构主要包括两部分:Redis Sentinel集群和Redis数据集群。
而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行切换。redis-Sentinel(哨兵模式)是Redis官方推荐的高可用性(HA)解决方案。
sentinel是redis高可用的解决方案,sentinel系统可以监视一个或者多个redis master服务,以及这些master服务的所有从服务;当某个master服务下线时,自动将该master下的某个从服务升级为master服务替代已下线的master服务继续处理请求。
sentinel可以让redis实现主从复制,当一个集群中的master失效之后,sentinel可以选举出一个新的master用于自动接替master的工作,集群中的其他redis服务器自动指向新的master同步数据。一般建议sentinel采取奇数台(Redis Sentinel的节点数量要满足2n+1(n>=1)的奇数个,官方建议至少3个),防止某一台sentinel无法连接到master导致误切换。其结构如下:
Sentinel由一个或多个Sentinel 实例组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。
例如下图所示:
在Server1 掉线后:
升级Server2 为新的主服务器:
选出新的master节点,redis sentinel会选一个合适的slave来升级为master,那么,如何选择一个合适的slave呢?顺序如下:
1). 选择slave-priority最高的slave节点(默认是相同)。
2). 选择复制偏移量最大的节点。
3). 如果以上两个条件都不满足,选runId最小的(启动最早的)。
Sentinel的作用
这里的哨兵有两个作用:
- 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
- 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。
注:然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。
sentinel哨兵通过如下功能实现故障切换
描述一下故障切换(failover)的过程。假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时(大于等于配置文件指定的值),那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。这样对于客户端而言,一切都是透明的。当客户端试图连接失效的主服务器时,sentine集群也会向客户端返回新主服务器的地址,使得集群可以使用新主服务器代替失效服务器。
(1) monitoring:监控redis是否正常运行
(2) notification:通知application错误信息
(3) failover:当某个master死掉,选择另外一个slave升级为master,更新master-slave关系。
(4) configuration provider:client通过sentinel获取redis地址,并在failover时更新地址。
注:主观下线和客观下线
主观下线:Subjectively Down,简称 SDOWN,指的是当前 Sentinel 实例对某个redis服务器做出的下线判断。
客观下线:Objectively Down, 简称 ODOWN,指的是多个 Sentinel 实例在对Master Server做出 SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,然后开启failover。
从SDOWN切换到ODOWN不需要任何一致性算法,只需要一个gossip(流言)协议,如果一个sentinel收到了足够多的sentinel发来消息告诉它某个master已经down掉了,SDOWN状态就会变成ODOWN状态。
redis-cluster(集群模式)
Redis Sentinel集群模式中,随着业务量和数据量增到性能达到redis单节点瓶颈,垂直扩容受机器限制,水平扩容涉及对应用的影响以及数据迁移中数据丢失风险。针对这些痛点,Redis3.0推出cluster分布式集群方案,当遇到单节点内存,并发,流量瓶颈时,采用cluster方案实现负载均衡。
Redis Cluster有效地解决了 Redis 分布式方面的需求。分布式数据存储方案中最为重要的一点就是数据分片,也就是所谓的 Sharding。
为了使得集群能够水平扩展,首要解决的问题就是如何将整个数据集按照一定的规则分配到多个节点上,常用的数据分片的方法有:范围分片,哈希分片,一致性哈希算法,哈希槽等。
Redis Cluster 采用虚拟哈希槽分区,所有的键根据哈希函数映射到 0 ~ 16383 整数槽内,计算公式:slot = CRC16(key) & 16383。每一个节点负责维护一部分槽以及槽所映射的键值数据。
下图展现一个五个节点构成的集群,每个节点平均大约负责3276个槽,以及通过计算公式映射到对应节点的对应槽的过程。
Redis Cluster 一般由多个节点组成,节点数量至少为 6 个才能保证组成完整高可用的集群,其中三个为主节点,三个为从节点。三个主节点会分配槽,处理客户端的命令请求,而从节点可用在主节点故障后,顶替主节点。
一般来说,主 Redis 节点会处理 Clients 的读写操作,而从节点只处理读操作。
官网地址
https://redis.io
安装reids
上传软件包
[root@cong11 ~]# tar -zxvf redis-5.0.5.tar.gz
安装gcc
[root@cong11 ~]# yum install -y gcc
编译安装
[root@cong11 ~]# cd redis-5.0.5
[root@cong11 redis-5.0.5]# make
[root@cong11 redis-5.0.5]# cd src/
[root@cong11 src]# make install PREFIX=/usr/local/redis
移动配置文件到指定位置
[root@cong11 src]# cd ..
[root@cong11 redis-5.0.5]# mkdir /usr/local/redis/etc
[root@cong11 redis-5.0.5]# cp redis.conf /usr/local/redis/etc/
启动redis服务
[root@cong11 ~]# /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
以上警告信息的解决方法:
执行ulimit -n查看当前用户打开的最大文件数
[root@cong11 ~]# ulimit -n
1024
修改vim /etc/security/limits.conf文件,在文件末尾添加下面的两行:
* soft nofile 10032
* hard nofile 10032
修改vim /etc/pam.d/login文件,在文件末尾添加下面的内容:
session required /usr/lib64/security/pam_limits.so
重新登录使修改生效
执行ulimit -n查看:
[root@cong11 ~]# ulimit -n
10032
在vim /etc/sysctl.conf文件中添加下面的两行内容:
net.core.somaxconn = 511
vm.overcommit_memory = 1
执行sysctl -p使内核参数修改生效
执行下面的命令:
[root@cong11 ~]# echo never > /sys/kernel/mm/transparent_hugepage/enabled
再次启动redis服务:
[root@cong11 ~]# /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
注:默认redis服务是在前台终端运行。
把redis调入后台运行
默认情况,Redis不是在后台运行,我们需要把redis放在后台运行
[root@cong11 ~]# vim /usr/local/redis/etc/redis.conf
daemonize yes #修改no为yes
bind 127.0.0.1 192.168.30.11 #默认监控127.0.0.1 添加本机IP 192.168.30.11
[root@cong11 ~]# /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
执行netstat和ps命令查看redis监听和进程信息
客户端连接Redis
[root@cong11 ~]# /usr/local/redis/bin/redis-cli
127.0.0.1:6379>
停止redis实例
[root@cong11 ~]# /usr/local/redis/bin/redis-cli shutdown
或者:
[root@cong11 ~]# pkill redis-server
/usr/local/redis/bin目录下的几个文件是什么
redis-benchmark:redis性能测试工具,测试Redis在你的系统及你的配置下的读写性能
redis-check-aof:检查aof日志的工具
redis-check-rdb:检查rdb日志的工具
redis-cli:连接用的客户端
redis-server:redis服务进程
添加path环境变量
[root@cong11 ~]# ln -s /usr/local/redis/bin/* /usr/local/bin/
添加开机自启动
[root@cong11 ~]# chmod +x /etc/rc.d/rc.local
[root@cong11 ~]# echo " /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf" >> /etc/rc.d/rc.local
redis配置文件详解
#是否作为守护进程运行
daemonize yes
#如以后台进程运行,则需指定一个pid,默认为/var/run/redis.pid
pidfile redis.pid
#绑定主机IP,默认值为127.0.0.1
#bind 127.0.0.1 192.168.网段.主机号
#Redis默认监听端口
port 6379
#客户端闲置多少秒后,断开连接,默认为300(秒)
timeout 300
#日志记录等级,有4个可选值,debug,verbose(默认值),notice,warning
loglevel verbose
#指定日志输出的文件名,默认值为stdout,也可设为/dev/null屏蔽日志
logfile stdout
#可用数据库数,默认值为16,默认数据库为0
databases 16
#保存数据到disk的策略
#当至少有一条Key数据被改变时,900秒刷新到disk一次
save 900 1
#当至少有10条Keys数据被改变时,300秒刷新到disk一次
save 300 10
#当至少有1w条keys数据被改变时,60秒刷新到disk一次
save 60 10000
#当dump .rdb数据库的时候是否压缩数据对象
rdbcompression yes
#存储和加载rdb文件时校验
rdbchecksum yes
#本地数据库文件名,默认值为dump.rdb
dbfilename dump.rdb
#后台存储错误停止写。
stop-writes-on-bgsave-error yes
#本地数据库存放路径,默认值为 ./
dir /var/lib/redis/
########### Replication #####################
#Redis的复制配置
# replicaof <masterip> <masterport> 当本机为从服务时,设置主服务的IP及端口
# masterauth <master-password> 当本机为从服务时,设置主服务的连接密码
#连接密码
# requirepass foobared
#最大客户端连接数,默认不限制
# maxclients 128
#最大内存使用设置,达到最大内存设置后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理后,一旦到达最大内存设置,将无法再进行写入操作。
# maxmemory <bytes>
#是否在每次更新操作后进行日志记录,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认值为no
appendonly no
#更新日志文件名,默认值为appendonly.aof
#appendfilename
#更新日志条件,共有3个可选值。no表示等操作系统进行数据缓存同步到磁盘,always表示每次更新操作后调用fsync()将数据写到磁盘,everysec表示每秒同步一次(默认值)。
# appendfsync always
appendfsync everysec
# appendfsync no
#当slave失去与master的连接,或正在拷贝中,如果为yes,slave会响应客户端的请求,数据可能不同步甚至没有数据,如果为no,slave会返回错误"SYNC with master in progress"
replica -serve-stale-data yes
#如果为yes,slave实例只读,如果为no,slave实例可读可写。
replica -read-only yes
# 在slave和master同步后(发送psync/sync),后续的同步是否设置成TCP_NODELAY . 假如设置成yes,则redis会合并小的TCP包从而节省带宽,但会增加同步延迟(40ms),造成master与slave数据不一致 假如设置成no,则redis master会立即发送同步数据,没有延迟
repl-disable-tcp-nodelay no
#如果master不能再正常工作,那么会在多个slave中,选择优先值最小的一个slave提升为master,优先值为0表示不能提升为master。
replica-priority 100
#### LIMITS ####
maxclients 10000 #客户端并发连接数的上限是10000,到达上限,服务器会关闭所有新连接并返回错误"max number of clients reached"
maxmemory 15G #设置最大内存,到达上限,服务器会根据驱逐政策(eviction policy)删除某些键值,如果政策被设置为noeviction,那么redis只读,对于增加内存的操作请求返回错误。
#### APPEND ONLY MODE ####
appendonly no #redis默认采用快照(snapshotting)异步转存到硬盘中,它是根据save指令来触发持久化的,当Redis异常中断或停电时,可能会导致最后一些写操作丢失。AOF(Append Only File,只追加文件)可以提供更好的持久性,结合apendfsync指令可以把几分钟的数据丢失降至一秒钟的数据丢失,它通过日志把所有的操作记录下来,AOF和RDB持久化可以同时启动。
appendfilename appendonly.aof #指定aof的文件名。
apendfsync always|everysec|no #调用fsync()写数据到硬盘中,always是每一次写操作就马上同步到日志中,everysec是每隔一秒强制fsync,no是不调用fsync(),让操作系统自己决定何时同步。
no-appendfsync-on-rewrite no #如果为yes,当BGSAVE或BGREWRITEAOF指令运行时,即把AOF文件转写到RDB文件中时,会阻止调用fsync()。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb #Redis会将AOF文件最初的大小记录下来,如果当前的AOF文件的大小增加100%并且超过64mb时,就会自动触发Redis改写AOF文件到RDB文件中,如果auto-aof-rewrite-percentage为0表示取消自动rewrite功能。
#### LUA SCRIPTING ####
lua-time-limit 5000 #一个Lua脚本最长的执行时间为5000毫秒(5秒),如果为0或负数表示无限执行时间。
#### SLOW LOG ####
slowlog-log-slower-than 10000 #当某个请求执行时间(不包括IO时间)超过10000微妙(10毫秒),把请求记录在慢日志中 ,如果为负数不使用慢日志,如果为0强制记录每个指令。
slowlog-max-len 128 #慢日志的最大长度是128,当慢日志超过128时,最先进入队列的记录会被踢出来,慢日志会消耗内存,你可以使用SLOWLOG RESET清空队列回收这些内存。
#### ADVANCED CONFIG ####
hash-max-ziplist-entries 512
hash-max-ziplist-value 64 #较小的hash可以通过某种特殊的方式进行编码,以节省大量的内存空间,我们指定最大的条目数为512,每个条目的最大长度为64。
list-max-ziplist-entries 512
list-max-ziplist-value 64 #同上。
zset-max-ziplist-entries 128
zset-max-ziplist-value 64 #同上。
activerehashing yes #重新哈希the main Redis hash table(the one mapping top-level keys to values),这样会节省更多的空间。
client-output-buffer-limit normal 0 0 0 #对客户端输出缓冲进行限制可以强迫那些就不从服务器读取数据的客户端断开连接。对于normal client,第一个0表示取消hard limit,第二个0和第三个0表示取消soft limit,normal client默认取消限制,因为如果没有寻问,他们是不会接收数据的。
client-output-buffer-limit slave 256mb 64mb 60 #对于slave client和MONITER client,如果client-output-buffer一旦超过256mb,又或者超过64mb持续60秒,那么服务器就会立即断开客户端连接。
client-output-buffer-limit pubsub 32mb 8mb 60 #对于pubsub client,如果client-output-buffer一旦超过32mb,又或者超过8mb持续60秒,那么服务器就会立即断开客户端连接。
#### INCLUDES ####
include /path/to/conf #包含一些可以重用的配置文件。
hz 10 #Redis 调用内部函数来执行后台task,比如关闭已经timeout连接,删除过期的keys并且永远不会被访问到的,执行频率根据 hz 后面的值来确定。在Redis 比较空闲的时候,提高这个值,能充分利用CPU,让Redis相应速度更快,可取范围是1-500 ,建议值为 1--100
aof-rewrite-incremental-fsync yes # 当子进程重写AOF文件,以下选项开启时,AOF文件会每产生32M数据同步一次。这有助于更快写入文件到磁盘避免延迟
################ VIRTUAL MEMORY ###########
#是否开启VM功能,默认值为no
vm-enabled no
# vm-enabled yes
#虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
vm-swap-file /tmp/redis.swap
#将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的 (Redis的索引数据就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0。
vm-max-memory 0
vm-page-size 32
vm-pages 134217728
vm-max-threads 4
############# ADVANCED CONFIG ###############
glueoutputbuf yes
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
#是否重置Hash表
activerehashing yes
Redis数据存储
Redis的存储分为内存存储、磁盘存储和log文件三部分,配置文件中有三个参数对其进行配置。
save seconds updates: save配置,指出在多长时间内,有多少次更新操作,就将数据同步到数据文件。这个可以多个条件配合,比如默认配置文件中的设置,就设置了三个条件。
appendonly yes/no : appendonly配置,指出是否在每次更新操作后进行日志记录,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为Redis本身同步数据文件是按上面的save条件来同步的,所以有的数据会在一段时间内只存在于内存中。
appendfsync no/always/everysec :appendfsync配置,no表示等操作系统进行数据缓存同步到磁盘,always表示每次更新操作后调用fsync()将数据写到磁盘,everysec表示每秒同步一次。
redis认证设置
修改redis.conf配置文件
[root@cong11 ~]# vim /usr/local/redis/etc/redis.conf
# requirepass foobared //启用此项,并指定密码即可
requirepass password
重启redis
[root@cong11 ~]# redis-cli shutdown
[root@cong11 ~]# redis-server /usr/local/redis/etc/redis.conf
测试
[root@cong11 ~]# redis-cli
127.0.0.1:6379> select 1 #提示需要密码认证
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 123456 #输入认证密码
OK
127.0.0.1:6379> select 1 #可以正常执行命令,select指令表示选择数据库。
OK
或者:
登陆的时候使用密码
[root@cong11 ~]# redis-cli -a 123456
注:关于redis-cli客户端工具可以参考redis-cli -h
Reids命令
Redis常规命令
[root@cong11 ~]# redis-cli -h 192.168.1.11 -p 6379 -a 123456
192.168.1.11:6379> set myname "berry" #插入一条记录
OK
192.168.1.11:6379> get myname #获取myname key的值
"berry"
192.168.1.11:6379> set foo bar
OK
192.168.1.11:6379> get foo
"bar"
192.168.1.11:6379> keys * #查看所有key
1) "myname"
2) "foo"
键的遵循:
可以使用ASCII字符
键的长度不要过长,键的长度越长则消耗的空间越多
在同一个库中(名称空间),键的名称不得重复,如果复制键的名称,实际上是修改键中的值
在不同的库中(名称空间),键的同一个名称可以重复
键可以实现自动过期
Redis帮助命令
说明:redis的help命令非常强大,因为redis支持众多的数据结构,每一种数据结构当中都支持N种操作,因此需要使用 help @group方式来获取某一种数据结构所支持的操作
192.168.1.11:6379> help #获取命令帮助
redis-cli 5.0.5
To get help arubout Redis commands type:
"help @<group>" to get a list of commands in <group>
"help <command>" for help on <command>
"help <tab>" to get a list of possible help topics
"quit" to exit
To set redis-cli preferences:
":set hints" enable online hints(提示)
":set nohints" disable online hints
Set your preferences in ~/.redisclirc
查询set帮助
192.168.1.11:6379> help set #查询set帮助
SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
//命令 键 值 [EX 过期时间,单位秒]
NX:如果一个键不存在,才创建并设定值,否则不允许设定
XX:如果一个键存在则设置键的值,如果不存在则不创建并不设置其值
summary: Set the string value of a key
since: 1.0.0
group: string
举例:
192.168.1.11:6379> set cjk aaa
OK
192.168.1.11:6379> set cjk bbb NX
(nil) #反回提示一个没能执行的操作
192.168.1.11:6379> get cjk
"aaa"
192.168.1.11:6379> set foo abc XX #设置foo key值,foo之前存在
OK #修改成功
192.168.1.11:6379> get foo
"abc"
查询get帮助
192.168.1.11:6379> help get #查询get帮助
GET key
summary: Get the value of a key
since: 1.0.0
group: string
查询一个命令组的帮助
#查询一个命令组的帮助,例如查询字符串类型数据的操作命令
192.168.1.11:6379> help @string
APPEND key value
summary: Append a value to a key
since: 2.0.0
BITCOUNT key [start end]
summary: Count set bits in a string
since: 2.6.0
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
summary: Perform arbitrary bitfield integer operations on strings
since: 3.2.0
BITOP operation destkey key [key ...]
summary: Perform bitwise operations between strings
since: 2.6.0
BITPOS key bit [start] [end]
summary: Find first bit set or clear in a string
since: 2.8.7
DECR key
summary: Decrement the integer value of a key by one
since: 1.0.0
DECRBY key decrement
summary: Decrement the integer value of a key by the given number
since: 1.0.0
GET key
summary: Get the value of a key
since: 1.0.0
GETBIT key offset
summary: Returns the bit value at offset in the string value stored at key
since: 2.2.0
查询string组中APPEND命令帮助
192.168.1.11:6379> help APPEND #查询string组中APPEND命令帮助
APPEND key value
summary: Append a value to a key
since: 2.0.0
group: string
append添加键中的值(在原有键中附加值的内容):
192.168.1.11:6379> append cjk fda
(integer) 6
192.168.1.11:6379> get cjk
"aaafda"
获取指定键中的值的字符串的长度:
192.168.1.11:6379> strlen cjk
(integer) 6
删除键:
192.168.1.11:6379> del cjk
(integer) 1
192.168.1.11:6379> get cjk
(nil)
列表的操作:
键指向一个列表,而列表可以理解为是一个字符串的容器,列表是有众多元素组成的集合,可以在键所指向的列表中附加一个值
lpush //在键所指向的列表前面插入一个值(左边加入)
rpush //在键所指向的列表后面附加一个值(右边加入)
lpop //在键所指向的列表前面弹出一个值(左边弹出)
rpop //在键所指向的列表后面弹出一个值(右边弹出)
lindex //根据索引获取值,指明索引位置进行获取对应的值
lset //用于修改指定索引的值为指定的值
创建一个列表
创建一个新的列表,在帮助中并没产明哪个命令用于创建一个新的列表,实际上创建一个新的列表使用LPUSH或RPUSH都可以。
192.168.1.11:6379> lpush ll cjk # ll为列表名称,cjk为值
(integer) 1
192.168.1.11:6379> lindex ll 0 #第一个索引(值)则为0
"cjk"
在原有的列表中的左侧加入一个值
192.168.1.11:6379> lpush ll fda #在原有的列表中的左侧加入一个值
(integer) 2
192.168.1.11:6379> lindex ll 0
"fda"
192.168.1.11:6379> lindex ll 1
"cjk"
在原有的列表中的右侧加入一个值
192.168.1.11:6379> rpush ll www
(integer) 3
192.168.1.11:6379> lindex ll 2
"www"
192.168.1.11:6379> lindex ll 1
"cjk"
192.168.1.11:6379> lindex ll 0
"fda"
修改一个已有的列表中的值:
192.168.1.11:6379> lset ll 0 abc
OK
192.168.1.11:6379> lindex ll 0
"abc"
查看列表中的值的数量
192.168.1.11:6379> llen ll
(integer) 3
在已有的列表中右侧弹出(删除)一个值
192.168.1.11:6379> rpop ll
"www"
在已有的列表中左侧弹出(删除)一个值
192.168.1.11:6379> lpop ll
"abc"
192.168.1.11:6379> lpop ll
"cjk"
192.168.1.11:6379> lpop ll
(nil)
清空数据库:
flushdb:删除当前选择的数据库所有key
flushall:清空所有库
192.168.1.11:6379> flushdb
OK
type查看 key 的数据类型
数据类型有:
none (key不存在)
string (字符串)
list (列表)
set (集合)
zset (有序集)
hash (哈希表)
192.168.1.11:6379> set myname "zhenglincong"
192.168.1.11:6379> type myname #查看key的数据查看类型
string #字符串
192.168.1.11:6379> lpush book_list "programming in scala" #插入一个列表
(integer) 1
192.168.1.11:6379> type book_list
list #列表
192.168.1.11:6379> sadd myset "hello" #插入一个集合
(integer) 1
192.168.1.11:6379> sadd myset "foo" "world"
(integer) 2
注:Redis sadd 命令将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略。
192.168.1.11:6379> smembers myset
1) "foo"
2) "world"
3) "hello"
192.168.1.11:6379> type myset
set
Pexpireat设置 key 的过期时间以毫秒计
Redis PEXPIREAT 命令用于设置 key 的过期时间,以毫秒计。key 过期后将不再可用。
实例:
首先创建一个 key 并赋值:
192.168.1.11:6379> set w3 redis #创建一条记录
OK
192.168.1.11:6379> pexpireat w3 10000 #为 key 设置过期时间
(integer) 1
查看redis状态信息
192.168.1.11:6379> info #查看redis状态信息
官网命令详解
https://www.redis.net.cn/order/3533.html
redis持久化
持久化概述:
默认情况下,Redis工作时所有数据都是存储于内存中的,不论是否有磁盘上的持久化数据,都是工作于内存当中,Redis本身就是一个内存的数据库,如果Redis崩溃或断电导致所有数据丢失,所以Redis提供了持久化功能来保证数据的可靠性,Redis持久化有两种实现:RDB和AOF
RDB
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
RDB持久化是默认启动的持久化机制;按事先定制的策略,周期性地将数据保存至磁盘,数据文件默认为dump.rdb。
RDB持久化有两种方式:
1、借助于配置文件所定义的save和策略进行保存。
2、客户端使用SAVE或BGSAVE命令启动快照保存机制。
SAVE命令: 是同步保存,在客户端使用save保存快照时,是在Redis主线程中保存快照;因为Redis的主线程是用于处理请求的,所以此时会阻塞所有客户端请求,每次的保存快照都是把内存中的数据完整的保存一份,并非是增量的,如果内存中的数据比较大,而还有大量的写操作请求时,此方式会引起大量的I/O,会导致Redis性能下降
BGSAVE命令:异步方式,将立即返回结果,但自动在后台保持操作,所以BGSAVE命令启动以后,前台不会被占用,客户端的请求是不会被阻塞(主进程不会被阻塞)。
如果是在配置文件中定义的save,那么Redis在持久化的时候,则会开启另外的进程去处理,不会阻塞Redis的主进程
Redis的RDB持久化不足之处则是,一旦数据出现问题,由于RDB的数据不是最新的,所以基于RDB恢复过来的数据一定会有一部分数据丢失,也就是RDB保存之后的修改的数据会丢失
AOF
AOF:Append Only File,持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。AOF类似于MySQL的二进制日志,记录每一次Redis的写操作命令,以顺序IO方式附加在指定文件的尾部,是使用追加方式实现的,这也叫做一种附加日志类型的持久化机制,由于每一次的操作都记录,则会随着时间长而增大文件的容量,AOF不像RDB,RDB是保存数据集的本身。
二者优缺点
RDB存在哪些优势呢?
1). 采用RBD方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常方便的,因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
2). 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
3). 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。
RDB又存在哪些劣势呢?
1). 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
AOF的优势有哪些呢?
1). AOF机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3种同步策略,即每秒同步、每修改同步和不同步。事实上,对于每秒同步,一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,即每次发生的数据变化都会被立即记录到磁盘中。至于无同步,无需多言,我想大家都能正确的理解它。
2). 由于AOF机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
3). 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
4). AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
AOF的劣势有哪些呢?
1). 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。
配置文件中的与RDB相关的参数:
[root@cong11 ~]# mkdir -p /redis/data #创建RDB文件路径
[root@cong11 ~]# vim /usr/local/redis/etc/redis.conf
stop-writes-on-bgsave-error yes //在进行快照备份时,一旦发生错误的话是否停止写操作
rdbcompression yes //RDB文件是否使用压缩,压缩会消耗CPU
rdbchecksum yes //是否对RDB文件做校验码检测,此项定义在redis启动时加载RDB文件是否对文件检查校验码,在redis生成RDB文件是会生成校验信息,在redis再次启动或装载RDB文件时,是否检测校验信息,如果检测的情况下会消耗时间,会导致redis启动时慢,但是能够判断RDB文件是否产生错误
dbfilename dump.rdb //定义RDB文件的名称
dir /redis/data //定义RDB文件存放的目录路径
[root@cong11 ~]# redis-cli -a 123456 shutdown
#关闭redis,这里注意,设置完密码后关闭redis需要携带密码
[root@cong11 ~]# redis-server /usr/local/redis/etc/redis.conf
[root@cong11 ~]# redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> config get dir
1) "dir"
2) "/redis/data" #设置成功
配置文件中的与AOF相关的参数:
appendonly no //定义是否开启AOF功能,默认为关闭,启用修改为yes
appendfilename "appendonly.aof" //定义AOF文件
appendfsync always //表示每次收到写命令时,立即写到磁盘上的AOF文件,虽然是最好的持久化功能,但是每次有写命令时都会有磁盘的I/O操作,容易影响redis的性能
appendfsync everysec //表示每秒钟写一次,不管每秒钟收到多少个写请求都往磁盘中的AOF文件中写一次
appendfsync no //表示append功能不会触发写操作,所有的写操作都是提交给OS,由OS自行决定是如何写的
no-appendfsync-on-rewrite no //当此项为yes时,表示在重写时,对于新的写操作不做同步,而暂存在内存中
auto-aof-rewrite-percentage 100 //表示当前AOF文件的大小是上次重写AOF文件的二倍时,则自动日志重写过程
auto-aof-rewrite-min-size 64mb //定义AOF文件重写过程的条件,最少为定义大小则触发重写过程
注意:持久本身不能取代备份;还应该制定备份策略,对Redis数据库定期进行备份;
RDB与AOF同时启用需要注意:
(1) bgsave和bgrewriteaof不会同时执行,为了避免对磁盘的I/O影响过大,在某一时刻只允许一者执行;
如果bgsave在执行当中,而用户手动执行bgrewriteaof时,redis会立即返回OK,但是Redis不会同时执行,会等bgsave执行完成,再执行bgrewriteaof
(2) 在Redis服务器启动用于恢复数据时,会优先使用AOF
数据恢复
每次Redis重启都会去读取相对应的文件,如果误删除可以用备份文件直接替换原来的文件,dump.rdb或者appendonly.aof。
redis主从架构
复制的工作过程:
主库会基于ping check方式检查从库是否在线,如果在线则直接同步数据文件至从服务端,从服务端也可以主动发送同步请求到主服务端,主库如果是启动了持久化功能时,会不断的同步数据到磁盘上,主库一旦收到从库的同步请求时,主库会将内存中的数据做快照,然后把数据文件同步给从库,从库得到以后是保存在本地文件中(磁盘),而后则把该文件装载到内存中完成数据重建。
1、启动redis slave
2、slave会向master发送同步命令,请求主库上的数据,不论从是第一次连接,还是非第一次连接,master此时都会启动一个后台的子进程将数据快照保存在数据文件中,然后把数据文件发送给slave
3、slave收到数据文件以后会保存到本地,而后把文件重载装入内存
特点:
1、一个Master可以有多个Slave;
2、支持链式复制(一个slave也可以是其它的slave的slave);
3、Master以非阻塞方式同步数据至slave(master可以同时处理多个slave的读写请求,salve端在同步数据时也可以使用非阻塞方式);
启动复制功能:
在cong12上安装redis
参照上面cong11主机的安装操作。过程略
配置slave的主
[root@cong12 ~]# vim /usr/local/redis/etc/redis.conf
replicaof 192.168.30.11 6379 #指定master IP,端口
masterauth 123456 #指定主Redis连接认证密码
重启redis服务
[root@cong12 ~]# redis-cli shutdown
[root@cong12 ~]# redis-server /usr/local/redis/etc/redis.conf
看看主从信息
[root@cong12 ~]# redis-cli -h 192.168.30.12
192.168.30.12:6379> info replication #查看主从信息
注意:如果master使用requirepass开启了认证功能,从服务器要使用masterauth <PASSWORD>来连入服务请求使用此密码进行认证;
测试
在cong11插入数据
[root@cong11 ~]# redis-cli -a 123456
127.0.0.1:6379> set test aa
OK
127.0.0.1:6379> get test
"aa"
在cong12查看同步信息
192.168.1.12:6379> keys *
1) "test"
192.168.1.12:6379> get test
"aa"
使用sentinel实现主从架构高可用
Redis主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。
sentinel的工作过程:
sentinel即可以部署在另外的主机上也可以部署在redis主机上,sentinel既能监控又能提供配置功能,向sentinel指明主redis服务器即可(仅监控主服务器),sentinel可以从主服务中获取主从架构信息,并分辨从节点。sentinel可以监控当前整个主从服务器架构的工作状态,一旦发现master离线的情况,sentinel会从多个从服务器中选择并提升一个从节点成为主节点,当主节点被从节点取代以后,那么IP地址则发生了变化,客户之前连接的主节点IP无法连接,此时可以向sentinel发起查询请求,sentinel会告知客户端新的主节点的IP,所以sentinel是redis在主从架构中实现高可用的解决方案。为了防止sentinel误判和单点故障,sentinel也应该部署为集群,sentinel多个节点同时监控redis主从架构,一旦有一个sentinel节点发现redis的主节点不在线时的情况,sentinel会与其他的sentinel节点协商,看其他的sentinel节点是否也同样发现redis的主节点不在线,如果sentinel的多个点节点都发现redis的主节点都为离线,那么则判定redis主节点为离线状态,以此方式避免误判,同样也避免了单点故障。
sentinel:
1、用于管理多个Redis服务实现HA;
2、监控多个Redis服务节点
3、自动故障转移
sentinel是一个分布式系统,可以在一个架构中运行多个sentinel进程,多个进程之间使用“流言协议”接收Redis主节点是否离线,并使用“投票协议”是否实现故障转移,选择哪一个Redis的从服务器成为主服务器
该方案有个缺陷:因为主从实例地址(IP,PORT)是不同的,当故障发生进行主从切换后,应用程序无法知道新地址,在Jedis2.2.2中新增了对Sentinel的支持,应用通过redis.clients.jedis.JedisSentinelPool.getResource()取得的Jedis实例会及时更新到新的主实例地址。
Jedis是Redis官方推荐的Java连接开发工具。要在Java开发中使用好Redis中间件,必须对Jedis熟悉才能写成漂亮的代码。运维人员不下需要关心redis集群连接接,这个是开发人员作的工作。如果要提供统一访问出口。可以使用Twemproxy中间件部署集群。
Redis配置哨兵模式
配置Reids的主从
Reids可以在一台机器上启动多个进程,即在一台主机上开启3个Redis进程,相当于3台Redis服务器。也可以在3台不同的服务器上进行搭建Redis。
这里配置配置3个哨兵和1主2从的Redis服务器来演示这个过程。
服务类型 |
是否是主服务器 |
IP地址 |
端口 |
redis |
是 |
192.168.30.11 |
6379 |
redis |
否 |
192.168.30.12 |
6379 |
redis |
否 |
192.168.30.13 |
6379 |
sentinel |
- |
192.168.30.11 |
26379 |
sentinel |
- |
192.168.30.12 |
26379 |
sentinel |
- |
192.168.30.13 |
26379 |
先配置redis的主从服务器
第1台Redis配置(主Redis)
第一台就用我们上面配置好的Reids(cong11)
[root@cong11 ~]# mkdir -p /var/log/redis
[root@cong11 ~]# cd /usr/local/redis/etc/
[root@cong11 etc]# vim redis.conf
…………省略部分内容
logfile "/var/log/redis/redis_6379.log"
masterauth 123456 #主从切换需要用到密码,如果你Redis设置了密码
重启Redis服务:
[root@cong11 ~]# pkill redis-server
[root@cong11 ~]# redis-server /usr/local/redis/etc/redis.conf
查看redis的端口监听
[root@cong11 ~]# netstat -anplt | grep redis
tcp 0 0 192.168.30.11:6379 0.0.0.0:* LISTEN 69582/redis-server
第2台Redis配置(从Redis)
就用我们上面安装好的Redis(cong12)
[root@cong12 ~]# mkdir -p /var/log/redis #创建日志目录
[root@cong12 ~]# mkdir -p /redis/data #创建第2台数据保存目录
[root@cong12 ~]# vim /usr/local/redis/etc/redis.conf #修改配置文件
………..省略部分内容
bind 127.0.0.1 192.168.30.12
port 6379
requirepass 123456
pidfile /var/run/redis_6379.pid #修改pid文件为redis_6380.pid
logfile "/var/log/redis/redis_6379.log" #修改log文件路径
dir /redis/data #修改RDB目录
replicaof 192.168.30.11 6379 #指定master的IP和端口
masterauth 123456 #指定master登陆密码
重启Redis服务:
[root@cong12 ~]# pkill redis-server
[root@cong12 ~]# redis-server /usr/local/redis/etc/redis.conf
查看redis的端口监听:
查看主从信息:
第3台Redis配置(从Redis)
在cong13主机上安装Redis,参考前面Redis的安装部分。
[root@cong13 ~]# mkdir -p /redis/data
[root@cong13 ~]# mkdir /var/log/redis
[root@cong13 ~]# cp redis-5.0.5/redis.conf /usr/local/redis/etc/
[root@cong13 ~]# vim /usr/local/redis/etc/redis.conf
………….省略部分内容
daemonize yes
bind 127.0.0.1 192.168.30.13
port 6379
requirepass 123456
pidfile /var/run/redis_6379.pid #修改pid文件为redis_6380.pid
logfile "/var/log/redis/redis_6379.log" #修改log文件路径
dir /redis/data #修改RDB目录
replicaof 192.168.30.11 6379 #指定master的IP和端口
masterauth 123456
重启Redis服务:
[root@cong13 ~]# redis-server /usr/local/redis/etc/redis.conf
查看Redis的端口监听:
查看主从信息:
在主Redis中查看主从信息:
添加开机启动(3台redis)
[root@cong11 ~]# echo "redis-server /usr/local/redis/etc/redis.conf" >> /etc/rc.local
[root@cong11 ~]# chmod +x /etc/rc.d/rc.local
[root@cong12 ~]# echo "redis-server /usr/local/redis/etc/redis.conf" >> /etc/rc.local
[root@cong12 ~]# chmod +x /etc/rc.d/rc.local
[root@cong13 ~]# echo "redis-server /usr/local/redis/etc/redis.conf" >> /etc/rc.local
[root@cong13 ~]# chmod +x /etc/rc.d/rc.local
测试主从
[root@cong11 ~]# redis-cli -p 6379
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> set key1 abc
OK
127.0.0.1:6379> get key1
"abc"
[root@cong12 ~]# redis-cli -p 6379
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> get key1
"abc"
[root@cong13 ~]# redis-cli -p 6379
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> get key1
"abc"
部署sentinel:
三个sentinel节点的sentinel.conf文件配置一样,如果是在同一个主机上,则需要使用不同的端口号。
生成sentinel配置文件
redis-sentinel可以理解为运行有着特殊代码的Redis,Redis自身也可以运行sentinel,sentinel也依赖配置文件,在Redis解压目录下有一个sentinel.conf文件,copy一份进行修改用于保存sentinel不断收集的状态信息.
[root@cong11 ~]# cd redis-5.0.5
[root@cong11 redis-5.0.5]# cp sentinel.conf /usr/local/redis/etc/
修改sentinel.conf配置文件
配置3个哨兵,每个哨兵的配置都是一样的。在Redis安装目录下有一个sentinel.conf文件,copy一份进行修改。
[root@cong11 ~]# vim /usr/local/redis/etc/sentinel.conf #标红的部分需修改
daemonize yes
bind 0.0.0.0 #添加监控IP,一定要写0.0.0.0,不然主从切换不了
logfile "/var/log/redis/sentinel_26379.log"
sentinel monitor mymaster 192.168.30.11 6379 2 #修改master IP
# sentinel monitor <master-name> <ip> <redis-port> <quorum> //此项可以出现多次,可以监控多组Redis主从架构,此项用于监控主节点 <master-name> 自定义的主节点名称,<ip> 主节点的IP地址,<redis-port>主节点的端口号,<quorum>主节点对应的quorum法定数量,是一个大于sentinel数量一半的值,所以sentinel数量尽量为奇数个,如果sentinel有3个,则指定为2即可,如果有4个,不能够指定为2,避免导致集群分裂,注意,<master-name>为集群名称,可以自定义,如果同时监控有多组Redis集群时,<master-name>不能相同。
注:最后数字2表示如果有两个sentinel认为master挂了,则这个master即认为不可用;
sentinel auth-pass mymaster 123456 #添加这一行
# sentinel auth-pass <master-name> <password>
# sentinel author-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码
sentinel down-after-milliseconds mymaster 30000
#sentinel down-after-milliseconds <master-name> <milliseconds> //默认30秒,sentinel会通过ping来判断master是否存活,如果在30秒内master返回pong给sentinel,则认为master是好的,否则sentinel认为master不可用。
sentinel parallel-syncs mymaster 1
#sentinel parallel-syncs <master-name> <numslaves> //当Sentinel节点集合对主节点故障判定达成一致时,Sentinel领导者节点会做故障转移操作,选出新的主节点,原来的从节点会向新的主节点发起复制操作,限制每次向新的主节点发起复制操作的从节点个数为1
sentinel failover-timeout mymaster 180000
#sentinel failover-timeout <master-name> <milliseconds> //故障转移超时时间,在指定时间没能完成则判定为失败,单位为毫秒(默认为180秒)
注:
Redis Sentinel中的身份验证
当一个master配置为需要密码才能连接时,客户端和slave在连接时都需要提供密码;
master通过requirepass设置自身的密码,不提供密码无法连接到这个master;
slave通过masterauth来设置访问master时的密码;
但是当使用了sentinel时,由于一个master可能会变成一个slave,一个slave也可能会变成master,所以需要同时设置上述两个配置项。
将cong11上配置好的sentinel.conf文件拷贝给cong12、cong13。
[root@cong11 ~]# cd /usr/local/redis/etc/
[root@cong11 etc]# scp sentinel.conf root@192.168.30.12:/usr/local/redis/etc/
[root@cong11 etc]# scp sentinel.conf root@192.168.30.13:/usr/local/redis/etc/
启动方式:
sentinel节点有两种启动方法:
# redis-sentinel /usr/local/redis/etc/sentinel.conf
或者:
# redis-server /usr/local/redis/etc/sentinel.conf --sentinel
注意启动的顺序。首先是主机的Redis服务进程,然后启动从机的服务进程,最后启动3个哨兵的服务进程。
[root@cong11 ~]]# redis-sentinel /usr/local/redis/etc/sentinel.conf
[root@cong12 ~]# redis-sentinel /usr/local/redis/etc/sentinel.conf
[root@cong13 ~]# redis-sentinel /usr/local/redis/etc/sentinel.conf
添加开机启动:
[root@cong11 ~]#echo "redis-sentinel /usr/local/redis/etc/sentinel.conf" >> /etc/rc.local
[root@cong12 ~]#echo "redis-sentinel /usr/local/redis/etc/sentinel.conf" >> /etc/rc.local
[root@cong13 ~]#echo "redis-sentinel /usr/local/redis/etc/sentinel.conf" >> /etc/rc.local
查看端口监听:
Cong12和cong13也一样。
检查整个集群的状态:
[root@cong11 etc]# redis-cli -h 192.168.30.11 -p 26379
192.168.30.11:26379> info sentinel #看到如下信息说明配置成功
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.30.11:6379,slaves=2,sentinels=3
检查整个集群的状态
192.168.30.11:26379> client list
id=3 addr=192.168.1.12:35149 fd=13 name=sentinel-bbded0b7-cmd age=416 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ping
id=4 addr=192.168.1.13:37022 fd=15 name=sentinel-31d3685a-cmd age=408 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=ping
id=5 addr=192.168.1.11:49514 fd=17 name= age=101 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client
注:当我们启动主从节点和sentinel节点后,sentinel.conf配置文件会自动添加或修改参数
测试:
测试自动failover
可以通过跟踪sentinel的日志文件查看failover切换
关闭master
[root@cong11 ~]# ps -ef | grep redis
[root@cong11 ~]# kill -9 70043
查看主从状态
[root@cong11 ~]# redis-cli -h 192.168.30.11 -p 26379
192.168.1.11:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.30.13:6379,slaves=2,sentinels=3
或
[root@cong11 ~]# redis-cli -h 192.168.30.11 -p 26379
192.168.30.11:26379> sentinel masters
1) 1) "name"
2) "mymaster"
3) "ip"
4) "192.168.30.13"
5) "port"
6) "6379"
………….
192.168.30.11:26379> sentinel slaves mymaster
1) 1) "name"
2) "192.168.30.11:6379"
3) "ip"
4) "192.168.30.11"
5) "port"
6) "6379"
7) "runid"
8) "4e28d6c4515dd61ed296ece6e7450827bc6d2b16"
9) "flags"
10) "slave"
………….
2) 1) "name"
2) "192.168.30.12:6379"
3) "ip"
4) "192.168.30.12"
5) "port"
6) "6379"
7) "runid"
8) "e16264a30605fc49f8edc1c2b37bffee2a6b7ce4"
9) "flags"
10) "slave"
启动主服务器
重启修复好的旧master之后,会自动成为新master的从库
[root@cong11 etc]# redis-server /usr/local/redis/etc/redis.conf
查看主从状态
[root@cong11 etc]# redis-cli -h 192.168.30.11 -p 6379
192.168.30.11:6381> auth 123456
OK
192.168.30.11:6381> info replication
在新的主Redis上查看主从信息:
[root@cong13 ~]# redis-cli -p 6379
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> info replication
由以上测试可见,主的故障离线后,sentinel重新选了其一个从reids成为了新的主节点,在原来的主节点重新上线后,仍然不会恢复为主节点。
总结:
Failover过程分析:
sentinel节点会定期通过ping检测redis的master是否存活,一旦master crash,
首先sentinel自己会主观认为master crash,然后三个sentinel之间彼此通信,只要有两个sentinel节点认为master crash,则客观认为master crash,
接着三个sentinel节点会投票,得到两票的一个sentinel会去执行failover,
最后master 30s之内没有响应sentinel才会真正的failover;
一旦挂掉的旧master修复,重新启动后,会作为新master的从库存在;
Redis-cluster集群
尽管可以使用哨兵主从集群实现可用性保证,但是这种实现方式每个节点的数据都是全量复制,数据存放量存在着局限性,受限于内存最小的节点,因此考虑采用数据分片的方式,来实现存储,这个就是Redis-cluster。
Redis cluster 是redis的分布式解决方案,在3.0版本正式推出后,有效的解决了redis分布式方面的需求;当遇到单机内存,并发,流量等瓶颈时,可以采用cluster架构方案达到负载均衡的目的。
官方网站:https://redis.io/topics/cluster-tutorial
2018年十月 Redis 发布了稳定版本的 5.0 版本,推出了各种新特性,其中一点是放弃 Ruby的集群方式,改为使用 C语言编写的 redis-cli的方式,是集群的构建方式复杂度大大降低。
在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般,特别是在主从切换的瞬间存在访问瞬断的情况,而且哨兵模式只有一个主节点对外提供服务,没法支持很高的并发,且单个主节点内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率。
Redis数据分区
Redis cluster 采用虚拟槽分区,所有的键根据哈希函数映射到0~16383整数槽内,计算公式:Slot=CRC16(key)&16384。每个节点负责维护一部分槽以及槽所映射的键值数据。
redis群集中的每个节点都负责哈希槽的子集,例如,您可能拥有一个包含3个节点的群集,其中:
节点A包含从0到5460的散列槽。
节点B包含从5461到10922的散列槽。
节点C包含从10923到16383的散列槽。
Redis Cluster主从模型
如果只具有节点A,B,C实例的集群中,如果节点B发生故障,则群集无法继续,因为我们不再能够在5461-10922范围内提供服务哈希位置的方法。
然而,当创建集群时(或稍后),我们向每个主节点添加一个从节点,以便最终集群由作为主节点的A,B,C和作为从节点的A1,B1,C1组成。 ,如果节点B出现故障,系统就能继续运行。
节点B1复制B,B失败,集群将节点B1升级为新的主节点,并将继续正常运行。
但请注意,如果节点B和B1同时发生故障,Redis Cluster将无法继续运行。
Redis Cluster 一般由多个节点组成,节点数量至少为 6 个才能保证组成完整高可用的集群,其中三个为主节点,三个为从节点。三个主节点会分配槽,处理客户端的命令请求,而从节点可用在主节点故障后,顶替主节点。
Redis-cluster搭建
Redis集群至少需要3个节点,因为投票容错机制要求超过半数节点认为某个节点挂了该节点才是挂了,所以2个节点无法构成集群。
要保证集群的高可用,需要每个节点都有从节点,也就是备份节点,所以Redis集群至少需要6台服务器。
我们这里搭建三个master节点,并且给每个master再搭建一个slave节点,三主三从。
实验环境
主机 |
IP |
角色 |
端口 |
Cong11 |
192.168.30.11 |
Master |
6379 |
Cong11 |
192.168.30.11 |
Slave |
6380 |
Cong12 |
192.168.30.12 |
Master |
6381 |
Cong12 |
192.168.30.12 |
Slave |
6382 |
Cong13 |
192.168.30.13 |
Master |
6383 |
Cong13 |
192.168.30.13 |
Slave |
6384 |
安装Redis
Cong11配置
先修改hosts
[root@cong11 ~]# vim /etc/hosts #添加IP与主机名映射
192.168.30.11 cong11
192.168.30.12 cong12
192.168.30.13 cong13
创建cluster工作目录
[root@cong11 ~]# mkdir -p /etc/redis/cluster/{6379,6380}
[root@cong11 ~]# ll /etc/redis/cluster/
总用量 0
drwxr-xr-x 2 root root 6 6月 17 21:19 6379
drwxr-xr-x 2 root root 6 6月 17 21:19 6380
创建数据存储目录
[root@cong11 ~]# mkdir -p /data/redis/data/{6379,6380}
[root@cong11 ~]# mkdir /var/log/redis
[root@cong11 ~]# ll /data/redis/data/
总用量 0
drwxr-xr-x 2 root root 6 6月 17 21:20 6379
drwxr-xr-x 2 root root 6 6月 17 21:20 6380
生成配置文件
[root@cong11 ~]# cp /root/redis-5.0.5/redis.conf /etc/redis/cluster/6379/
[root@cong11 ~]# cp /root/redis-5.0.5/redis.conf /etc/redis/cluster/6380/
修改配置文件
[root@cong11 ~]# vim /etc/redis/cluster/6379/redis.conf
daemonize yes //redis后台运行
bind 192.168.1.11 //监听地址
pidfile /var/run/redis_6379.pid //pidfile文件对应端口
port 6379 //端口
dir "/data/redis/data/6379" //配置redis rdb数据保存位置
logfile "/var/log/redis/redis_6379.log"
cluster-enabled yes //开启集群 把注释#去掉
cluster-config-file nodes_6379.conf //集群的配置,配置文件首次启动自动生成
cluster-node-timeout 15000 //请求超时15s
appendonly yes //aof日志开启,有需要就开启,它会每次写操作都记录一条日志
主要参数说明:
cluster-enabled <yes/no>:如果设置为yes,则在特定Redis实例中启用Redis群集支持。否则,实例像往常一样作为独立实例启动。
cluster-config-file <filename>:请注意,这不是用户可编辑的配置文件,而是每次发生更改时Redis群集节点自动保持群集配置(基本上是状态)的文件,为了能够在启动时重新阅读它。该文件列出了集群中其他节点,状态,持久变量等内容。
luster-node-timeout <milliseconds>:Redis集群节点不可用的最长时间,如果主节点的可访问时间超过指定的时间,则其从属节点将进行故障转移。
[root@cong11 ~]# vim /etc/redis/cluster/6380/redis.conf
daemonize yes //redis后台运行
bind 192.168.1.11
pidfile "/var/run/redis_6380.pid"
port 6380
dir "/data/redis/data/6380"
logfile "/var/log/redis/redis_6380.log" //修改log日志路径
cluster-enabled yes //开启集群 把注释#去掉
cluster-config-file nodes_6380.conf //集群的配置,配置文件首次启动自动生成
cluster-node-timeout 15000 //请求超时15s
appendonly yes //aof日志开启,有需要就开启,它会每次写操作都记录一条日志
启动redis服务
[root@cong11 ~]# redis-server /etc/redis/cluster/6379/redis.conf
[root@cong11 ~]# redis-server /etc/redis/cluster/6380/redis.conf
查看端口
[root@cong11 ~]# netstat -antup | grep 63
添加开机自启动
[root@cong11 ~]# echo "redis-server /etc/redis/cluster/6379/redis.conf" >> /etc/rc.local
[root@cong11 ~]# echo "redis-server /etc/redis/cluster/6380/redis.conf" >> /etc/rc.local
拷贝软件和配置文件到cong12,cong13
[root@cong11 ~]# scp -r /etc/redis/ 192.168.1.12:/etc/
[root@cong11 ~]# scp -r /etc/redis/ 192.168.1.13:/etc/
[root@cong11 ~]# scp -r /usr/local/redis/ 192.168.1.12:/usr/local/
[root@cong11 ~]# scp -r /usr/local/redis/ 192.168.1.13:/usr/local/
Cong12配置
先修改hosts
[root@cong12 ~]# vim /etc/hosts #添加IP与主机名映射
192.168.1.11 cong11
192.168.1.12 cong12
192.168.1.13 cong13
添加path环境变量
[root@cong12 ~]# ln -s /usr/local/redis/bin/* /usr/local/bin/
创建工作目录
[root@cong12 ~]# mkdir -p /data/redis/data/{6381,6382}
[root@cong12 ~]# mkdir /var/log/redis
修改配置文件
[root@cong12 ~]# mv /etc/redis/cluster/6379 /etc/redis/cluster/6381
[root@cong12 ~]# mv /etc/redis/cluster/6380 /etc/redis/cluster/6382
[root@cong12 ~]# vim /etc/redis/cluster/6381/redis.conf
daemonize yes //redis后台运行
bind 192.168.1.12 //监听地址
pidfile /var/run/redis_6381.pid //pidfile文件对应端口
port 6381 //端口
dir "/data/redis/data/6381" //配置redis rdb数据保存位置
logfile "/var/log/redis/redis_6381.log" //修改log日志路径
cluster-enabled yes //开启集群 把注释#去掉
cluster-config-file nodes_6381.conf //集群的配置,配置文件首次启动自动生成
cluster-node-timeout 15000 //请求超时15s
appendonly yes //aof日志开启,有需要就开启,它会每次写操作都记录一条日志
[root@cong12 ~]# vim /etc/redis/cluster/6382/redis.conf
daemonize yes //redis后台运行
bind 192.168.1.12 //监听地址
pidfile /var/run/redis_6382.pid //pidfile文件对应端口
port 6382 //端口
dir "/data/redis/data/6382" //配置redis rdb数据保存位置
logfile "/var/log/redis/redis_6382.log" //修改log日志路径
cluster-enabled yes //开启集群 把注释#去掉
cluster-config-file nodes_6382.conf //集群的配置,配置文件首次启动自动生成
cluster-node-timeout 15000 //请求超时15s
appendonly yes //aof日志开启,有需要就开启,它会每次写操作都记录一条日志
启动redis服务
[root@cong12 ~]# redis-server /etc/redis/cluster/6381/redis.conf
[root@cong12 ~]# redis-server /etc/redis/cluster/6382/redis.conf
查看端口
[root@cong12 cluster]# netstat -antup | grep 63
添加开机自启动
[root@cong12 cluster]# echo "redis-server /etc/redis/cluster/6381/redis.conf" >> /etc/rc.local
[root@cong12 cluster]# echo "redis-server /etc/redis/cluster/6382/redis.conf" >> /etc/rc.local
Cong13配置
先修改hosts
[root@cong12 ~]# vim /etc/hosts #添加IP与主机名映射
192.168.1.11 cong11
192.168.1.12 cong12
192.168.1.13 cong13
添加path环境变量
[root@cong13 ~]# ln -s /usr/local/redis/bin/* /usr/local/bin/
创建工作目录
[root@cong13 ~]# mkdir -p /data/redis/data/{6383,6384}
[root@cong13 ~]# mkdir /var/log/redis
修改配置文件
[root@cong13 ~]# mv /etc/redis/cluster/6379 /etc/redis/cluster/6383
[root@cong13 ~]# mv /etc/redis/cluster/6380 /etc/redis/cluster/6384
[root@cong13 ~]# vim /etc/redis/cluster/6383/redis.conf
daemonize yes //redis后台运行
bind 192.168.1.13 //监听地址
pidfile /var/run/redis_6383.pid //pidfile文件对应端口
port 6383 //端口
dir "/data/redis/data/6383" //配置redis rdb数据保存位置
logfile "/var/log/redis/redis_6383.log" //修改log日志路径
cluster-enabled yes //开启集群 把注释#去掉
cluster-config-file nodes_6383.conf //集群的配置,配置文件首次启动自动生成
cluster-node-timeout 15000 //请求超时15s
appendonly yes //aof日志开启,有需要就开启,它会每次写操作都记录一条日志
[root@cong13 ~]# vim /etc/redis/cluster/6384/redis.conf
daemonize yes //redis后台运行
bind 192.168.1.13 //监听地址
pidfile /var/run/redis_6384.pid //pidfile文件对应端口
port 6384 //端口
dir "/data/redis/data/6384" //配置redis rdb数据保存位置
logfile "/var/log/redis/redis_6384.log" //修改log日志路径
cluster-enabled yes //开启集群 把注释#去掉
cluster-config-file nodes_6384.conf //集群的配置,配置文件首次启动自动生成
cluster-node-timeout 15000 //请求超时15s
appendonly yes //aof日志开启,有需要就开启,它会每次写操作都记录一条日志
启动redis服务
[root@cong13 ~]# redis-server /etc/redis/cluster/6383/redis.conf
[root@cong13 ~]# redis-server /etc/redis/cluster/6384/redis.conf
查看端口
[root@cong13 ~]# netstat -antup | grep 63
添加开机自启动
[root@cong13 ~]# echo "redis-server /etc/redis/cluster/6383/redis.conf" >> /etc/rc.local
[root@cong13 ~]# echo "redis-server /etc/redis/cluster/6384/redis.conf" >> /etc/rc.local
查看进程
[root@cong13 ~]# ps -ef | grep redis #可以看到是以cluster启动
创建cluster集群
redis5.0开始不再使用ruby搭建集群,使用命令 redis-cli
添加集群
[root@cong11 ~]# redis-cli --cluster create 192.168.1.11:6379 192.168.1.12:6381 192.168.1.13:6383 192.168.1.11:6380 192.168.1.12:6382 192.168.1.13:6384 --cluster-replicas 1
--cluster-replicas 1 参数1代表的是一个比例,就是主节点数/从节点数的比例,先写3个主节点,然后写3个从节点,它是按照书写顺序来确定那个是主节点。
如图可以看见正确的打印信息,3主3从,以及每个master分配的信息,最后,输入yes,开始创建集群。
看到OK,说明集群创建成功。
查看集群信息
查看节点信息:
[root@cong11 ~]# redis-cli -h 192.168.1.11 -p 6379 -c
192.168.1.11:6379> cluster nodes
向redis写数据:
a这个Key的槽位在1.13这台redis上。
查看集群信息:
192.168.1.13:6383> cluster info
查看集群完整性:
[root@cong11 ~]# redis-cli --cluster check 192.168.1.11:6379
可以看出来,三个master 中的slots正好分配完16384个槽。
故障切换
模拟主redis服务192.168.1.11:6379故障
执行kill命令杀掉192.168.1.11:6379进程
[root@cong11 ~]# kill 98174
检查集群完整性:
[root@cong11 ~]# redis-cli --cluster check 192.168.1.11:6380
可以看到192.168.1.11:6379的从redis实例192.168.1.12:6382成为了主redis.
再次将192.168.1.11:6379启动:
[root@cong11 ~]# redis-server /etc/redis/cluster/6379/redis.conf
查看集群的完整性:
发现192.168.1.11:6379成为了从redis。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!