1 redis简介
为了提高网站响应速度,企业会将热点数据保存在内存中而不是直接从后端数据库中读取。大型网站应用,热点数据往往巨大,几十G上百G是很正常的事,这种情况下,就需要用到缓存服务器,通过缓存服务器承载大部分用户请求,小部分用户请求交给后端服务器处理,如此一来,就可以大大提高用户访问的速度,提升用户使用体验。
常用的缓存服务器有:
memcache
redis
Redis 是一种开源(BSD 许可)内存中数据结构存储,用作数据库、缓存、消息代理和流引擎。
为了实现最佳性能,Redis 使用 内存数据集。根据您的使用案例,Redis 可以通过定期将数据集转储到磁盘或将每个命令附加到基于磁盘的日志来持久保存您的数据。如果您只需要功能丰富的网络内存缓存,您还可以禁用持久性。
Redis 支持异步复制,具有快速非阻塞同步和自动重新连接以及网络分割上的部分重新同步。
2 redis集群
redis集群分类
集群是一组相互独立、通过高速网络互联的计算机,它们构成了一个组,并以单一系统的模式加以管理。一个客户与集群相互作用时,集群就像是一个独立的服务器。集群配置是用于提高可用性和可缩放性。
redis集群是一个由多个主从节点群组成的分布式服务集群,它具有复制、高可用和分片特性。
redis集群有三种集群模式:
1.主从模式
2.哨兵(Sentinel)模式
3.Cluster模式
在服务开发中,单机都会存在单点故障的问题,即服务部署在一台服务器上,一旦服务器宕机服务就不可用,所以为了让服务高可用,分布式服务就出现了,将同一服务部署到多台机器上,即使其中几台服务器宕机,只要有一台服务器可用服务就可用。
redis也是一样,为了解决单机故障引入了主从模式,但主从模式存在一个问题:master节点故障后服务,需要人为的手动将slave节点切换成为maser节点后服务才恢复。redis为解决这一问题又引入了哨兵模式,哨兵模式能在master节点故障后能自动将salve节点提升成master节点,不需要人工干预操作就能恢复服务可用。
但是主从模式、哨兵模式都没有达到真正的数据sharding(分布式)存储,每个redis实例中存储的都是全量数据,所以redis cluster就诞生了,实现了真正的数据分片存储。
1.主从模式
redis单节点虽然有通过RDB和AOF持久化机制能将数据持久化到硬盘上,但数据是存储在一台服务器上的,如果服务器出现硬盘故障等问题,会导致数据不可用,而且读写无法分离,读写都在同一台服务器上,请求量大时会出现I/O瓶颈。
为了避免单点故障 和 读写不分离,Redis 提供了复制(replication)功能实现master数据库中的数据更新后,会自动将更新的数据同步到其他slave数据库上。
通过数据复制,Redis 的一个 master 可以挂载多个 slave,而 slave 下还可以挂载多个 slave,形成多层嵌套结构。所有写操作都在 master 实例中进行,master 执行完毕后,将写指令分发给挂在自己下面的 slave 节点。slave 节点下如果有嵌套的 slave,会将收到的写指令进一步分发给挂在自己下面的 slave。
通过多个 slave,Redis 的节点数据就可以实现多副本保存,任何一个节点异常都不会导致数据丢失,同时多 slave 可以 N 倍提升读性能。master 只写不读,这样整个 master-slave 组合,读写能力都可以得到大幅提升。
//主从模式优缺点:
1、优点: 主从结构具有读写分离,提高效率、数据备份,提供多个副本等优点。
2、不足: 最大的不足就是主从模式不具备自动容错和恢复功能,主节点故障,集群则无法进行工作,可用性比较低,从节点升主节点需要人工手动干预。
普通的主从模式,当主数据库崩溃时,需要手动切换从数据库成为主数据库:
在从数据库中使用SLAVE NO ONE命令将从数据库提升成主数据继续服务。
启动之前崩溃的主数据库,然后使用SLAVEOF命令将其设置成新的主数据库的从数据库,即可同步数据。
2.哨兵模式
主从同步/复制的模式,当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用,这时候就需要哨兵模式登场了。
哨兵模式是从Redis的2.6版本开始提供的,但是当时这个版本的模式是不稳定的,直到Redis的2.8版本以后,这个哨兵模式才稳定下来。
哨兵模式核心还是主从复制,只不过在相对于主从模式在主节点宕机导致不可写的情况下,多了一个竞选机制:从所有的从节点竞选出新的主节点。竞选机制的实现,是依赖于在系统中启动一个sentinel(哨兵)进程。
哨兵本身也有单点故障的问题,所以在一个一主多从的Redis系统中,可以使用多个哨兵进行监控,哨兵不仅会监控主数据库和从数据库,哨兵之间也会相互监控。每一个哨兵都是一个独立的进程,作为进程,它会独立运行。
//哨兵模式的作用
监控所有服务器是否正常运行:通过发送命令返回监控服务器的运行状态,除了监控主服务器、从服务器外,哨兵之间也相互监控。
故障切换:当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换master。同时那台有问题的旧主也会变为新主的从,也就是说当旧的主即使恢复时,并不会恢复原来的主身份,而是作为新主的一个从。
//哨兵模式优缺点
优点:
1、哨兵模式是基于主从模式的,解决主从模式中master故障不能自动切换故障的问题。
缺点:
1、哨兵模式下每台 Redis 服务器都存储相同的数据,很浪费内存空间;数据量太大,主从同步时严重影响了master性能。
2、哨兵模式是中心化的集群实现方案,每个从机和主机的耦合度很高,master宕机到salve选举master恢复期间服务不可用。因为投票选举结束之前,谁也不知道主机和从机是谁,此时Redis也会开启保护机制,禁止写操作,直到选举出了新的Redis主机。
3、哨兵模式始终只有一个Redis主机来接收和处理写请求,写操作还是受单机瓶颈影响,没有实现真正的分布式架构。
3.Cluster模式
主从模式或哨兵模式每个节点存储的数据都是全量的数据,数据量过大时,就需要对存储的数据进行分片后存储到多个redis实例上。此时就要用到Redis Sharding技术。
redis在3.0上加入了 Cluster 集群模式,实现了 Redis 的分布式存储,也就是说每台 Redis 节点上存储不同的数据。cluster模式为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器,内存/QPS不受限于单机,可受益于分布式集群高扩展性。
Redis Cluster是一种服务器Sharding技术(分片和路由都是在服务端实现),采用多主多从,每一个分区都是由一个Redis主机和多个从机组成,片区和片区之间是相互平行的。Redis Cluster集群采用了P2P的模式,完全去中心化。
官方推荐,集群部署至少要 3 台以上的master节点,最好使用 3 主 3 从六个节点的模式。Redis Cluster集群具有如下几个特点:
1、集群完全去中心化,采用多主多从;所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
2、客户端与 Redis 节点直连,不需要中间代理层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
3、每一个分区都是由一个Redis主机和多个从机组成,分片和分片之间是相互平行的。
4、每一个master节点负责维护一部分槽,以及槽所映射的键值数据;集群中每个节点都有全量的槽信息,通过槽每个node都知道具体数据存储到哪个node上。
redis cluster主要是针对海量数据+高并发+高可用的场景,如果你的数据量很大,那么建议就用redis cluster,数据量不是很大时,使用sentinel就够了。redis cluster的性能和高可用性均优于哨兵模式。
Redis Cluster采用虚拟哈希槽分区而非一致性hash算法,预先分配一些卡槽,所有的键根据哈希函数映射到这些槽内,每一个分区内的master节点负责维护一部分槽以及槽所映射的键值数据。
单机部署
//安装依赖包
[root@mysql ~]# yum -y install wget make gcc gcc-c++ net-tools tar
//wget下载redis安装包
[root@mysql ~]# wget https://download.redis.io/redis-stable.tar.gz
--2024-08-08 09:01:37-- https://download.redis.io/redis-stable.tar.gz
Resolving download.redis.io (download.redis.io)... 45.60.125.1
Connecting to download.redis.io (download.redis.io)|45.60.125.1|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3626624 (3.5M) [application/octet-stream]
Saving to: ‘redis-stable.tar.gz’
redis-stable.tar.g 100%[===============>] 3.46M 452KB/s in 8.2s
2024-08-08 09:01:47 (434 KB/s) - ‘redis-stable.tar.gz’ saved [3626624/3626624]
//解压后进行编译安装
[root@mysql ~]# tar -zxvf redis-stable.tar.gz
[root@mysql ~]# cd redis-stable/
[root@mysql redis-stable]# make
[root@mysql redis-stable]# make install
//修改配置文件
//Linux操作系统对大部分申请内存的请求都回复yes, 以便能运行更多的程序。 因为申请内存后, 并不会马上使用内存, 这种技术叫做overcommit。
0:表示内核将检查是否有足够的可用内存。如果有足够的可用内存,内存申请通过,否则内存申请失败,并将错误返回给应用程序。
1:表示内核允许超量使用内存直到用完为止
2:表示内核决不过量使用内存,即系统整个内存地址空间不能超过swap+50%的RAM(运行内存)值,50%是overcommit_ratio的默认值,此参数同样支持修改。
Redis建议把这个值设置为1, 是为了让fork操作能够在低内存下也执行成功。
[root@mysql redis-stable]# vim /etc/sysctl.conf
vm.overcommit_memory = 1
[root@mysql redis-stable]# sysctl -p
vm.overcommit_memory = 1
//THP透明大页面,尽管THP的本意是为提升性能,但某些数据库厂商还是建议直接关闭THP。否则可能导致性能下降,内存锁,甚至系统重启等问题。
[root@mysql redis-stable]# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
[root@mysql redis-stable]# echo never > /sys/kernel/mm/transparent_hugepage/enabled
[root@mysql redis-stable]# cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
//使redis在后台运行需要修改配置文件/etc/redis/redis.conf,将daemonize值设为yes
默认情况下,redis连接是不需要经过认证的,而redis承载了企业大部分的请求流量,如果不经过认证很有可能在互联网上遭受攻击,所以需要在配置文件中为redis设置密码认证,且密码最好随机生成,保证没有规律可言。
[root@localhost ~]# vim /etc/redis/redis.conf
[root@mysql ~]# mkdir /etc/redis
[root@mysql redis-stable]# cp redis.conf /etc/redis/
[root@mysql redis-stable]# cd /etc/redis/
[root@mysql redis]# vim redis.conf
daemonize yes
requirepass foobared
//启动服务,进行验证
[root@mysql redis]# redis-server /etc/redis/redis.conf
[root@mysql redis]# ps -ef | grep redis
root 7627 1 0 09:17 ? 00:00:00 redis-server 127.0.0.1:6379
root 7636 1621 0 09:17 pts/1 00:00:00 grep --color=auto redi
[root@mysql redis]# redis-cli
127.0.0.1:6379> auth foobared
OK
127.0.0.1:6379> set name tom
OK
127.0.0.1:6379> get name
"tom"
127.0.0.1:6379> exit
[root@mysql ~]# redis-cli -h 127.0.0.1 -p 6380
127.0.0.1:6380> auth foobared
OK
127.0.0.1:6380> get age
"18"
127.0.0.1:6380> exit
redis主从
//将当前目录下.conf文件复制到6379.conf 6380.conf文件
[root@mysql]# cd /etc/redis/
[root@mysql redis]# cp redis.conf 6379.conf
[root@mysql redis]# mv redis.conf 6380.conf
[root@mysql redis]# vim 6379.conf
masterauth foobared //密码
[root@mysql redis]# vim 6380.conf
port 6380 //端口
replicaof 127.0.0.1 6379 //主机IP
masterauth foobared ///密码
//启动服务
[root@mysql redis]# redis-server /etc/redis/6379.conf
[root@mysql redis]# redis-server /etc/redis/6380.conf
[root@mysql redis]# ps -ef | grep redis
root 7694 1 0 09:25 ? 00:00:00 redis-server 127.0.0.1:6379
root 7701 1 0 09:25 ? 00:00:00 redis-server 127.0.0.1:6380
root 7708 1621 0 09:25 pts/1 00:00:00 grep --color=auto redi
//进行验证
[root@mysql redis]# redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> auth foobared
OK
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> get age
"18"
127.0.0.1:6379> exit
[root@mysql ~]# redis-cli -h 127.0.0.1 -p 6380
127.0.0.1:6380> auth foobared
OK
127.0.0.1:6380> get age
"18"
127.0.0.1:6380> exit
redis哨兵
//进入到redis-stable中将sentinel.conf文件复制出来
[root@mysql ~]# cd redis-stable/
[root@mysql redis-stable]# cp sentinel.conf /etc/redis/
更改配置文件
[root@mysql redis-stable]# cd /etc/redis/
[root@mysql redis]# vim sentinel.conf
protected-mode no //保护模式
daemonize yes
sentinel monitor mymaster 127.0.0.1 6379 1 //哨兵监护主库
sentinel auth-pass mymaster foobared //主库密码
//启动服务
[root@mysql redis]# redis-sentinel
[root@mysql redis]# redis-sentinel /etc/redis/sentinel.conf
[root@mysql redis]# ps -ef | grep redis
root 7694 1 0 09:25 ? 00:00:00 redis-server 127.0.0.1:6379
root 7701 1 0 09:25 ? 00:00:00 redis-server 127.0.0.1:6380
root 7783 1 0 09:34 ? 00:00:00 redis-sentinel *:26379 [sentinel]
root 7796 7714 0 09:34 pts/2 00:00:00 grep --color=auto redi
//验证
[root@mysql redis]# ps -ef | grep redis
root 7694 1 0 09:25 ? 00:00:01 redis-server 127.0.0.1:6379
root 7701 1 0 09:25 ? 00:00:01 redis-server 127.0.0.1:6380
root 7783 1 0 09:34 ? 00:00:01 redis-sentinel *:26379 [sentinel]
root 7801 1621 0 09:43 pts/1 00:00:00 redis-cli -h 127.0.0.1 -p 6379
root 7805 7714 0 09:45 pts/2 00:00:00 grep --color=auto redis
//模拟主库环境宕机
[root@mysql redis]# kill -9 7694
[root@mysql redis]# ps -ef | grep redis
root 7701 1 0 09:25 ? 00:00:01 redis-server 127.0.0.1:6380
root 7783 1 0 09:34 ? 00:00:01 redis-sentinel *:26379 [sentinel]
root 7801 1621 0 09:43 pts/1 00:00:00 redis-cli -h 127.0.0.1 -p 6379
root 7807 7714 0 09:46 pts/2 00:00:00 grep --color=auto redi
[root@mysql redis]# redis-cli -h 127.0.0.1 -p 6380
127.0.0.1:6380> auth foobared
OK
127.0.0.1:6380> info replication
Error: Server closed the connection
not connected> info replication
NOAUTH Authentication required.
127.0.0.1:6380> info replication
NOAUTH Authentication required.
127.0.0.1:6380> exit
[root@mysql redis]# redis-cli -h 127.0.0.1 -p 6380
127.0.0.1:6380> auth foobared
OK
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:70f3d59f1a25cb58da17d9328db43857ce7cb7f8
master_replid2:74517a3f7fe9127e4e71d5e092f4409169aaad37
master_repl_offset:53948
second_repl_offset:48207
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:53948
127.0.0.1:6380> exit
//模拟主库环境恢复
[root@mysql redis]# redis-server /etc/redis/6379.conf
[root@mysql redis]# ps -ef | grep redis
root 7701 1 0 09:25 ? 00:00:02 redis-server 127.0.0.1:6380
root 7783 1 0 09:34 ? 00:00:02 redis-sentinel *:26379 [sentinel]
root 7828 1 0 09:49 ? 00:00:00 redis-server 127.0.0.1:6379
root 7872 7714 0 09:53 pts/2 00:00:00 grep --color=auto redi
[root@mysql redis]# redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> auth foobared
OK
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_read_repl_offset:76854
slave_repl_offset:76854
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:70f3d59f1a25cb58da17d9328db43857ce7cb7f8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:76854
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:57806
repl_backlog_histlen:19049