快速了解NoSql数据库Redis集群
目录
一 关系型数据库和 NoSQL 数据库
1.1 数据库主要分为两大类:关系型数据库与 NoSQL 数据库
1.2 为什么还要用 NoSQL 数据库呢?
1.3 RDBMS和NOSQL的特点及优缺点:
二 Remote Dictionary Server 简介
2.1 什么是redis
2.2 Redis特性
2.3 Redis应用场景
2.4 缓存的实现流程
三 Redis的安装
3.1 rpm包方式安装
3.2 源码安装
3.3 对其他虚拟机进行源码安装
四 Redis的基本操作
五 Redis 主从复制
5.1 环境配置
5.2 配置主从同步
5.3 主从同步过程
六 Redis的哨兵(高可用)
6.1 Redis哨兵
6.2 哨兵的实验过程
6.3. 在整个架构中可能会出现的问题
七 Redis Cluster(无中心化设计)
7.1 Redis Cluster 工作原理
7.2 创建redis cluster的前提
7.3 部署redis cluster
7.4 redis-cli --cluster 参数说明
7.5. 创建redis-cluster
7.6 集群扩容
7.7 clsuter集群维护
一 关系型数据库和 NoSQL 数据库
1.1 数据库主要分为两大类:关系型数据库与 NoSQL 数据库
关系型数据库 ,是建立在关系模型基础上的数据库,其借助于集合代数等数学概念和方法来处理数据库中的数据主流的 MySQL 、 Oracle 、 MS SQL Server 和 DB2 都属于这类传统数据库。NoSQL 数据库 ,全称为 Not Only SQL ,意思就是适用关系型数据库的时候就使用关系型数据库,不适用的时候也没有必要非使用关系型数据库不可,可以考虑使用更加合适的数据存储。主要分为临时性键值存储(memcached 、 Redis )、永久性键值存储( ROMA 、 Redis )、面向文档的数据库(MongoDB 、 CouchDB )、面向列的数据库( Cassandra 、 HBase ),每种 NoSQL 都有其特有的使用场景及优点。
1.2 为什么还要用 NoSQL 数据库呢?
主要是由于随着互联网发展,数据量越来越大,对性能要求越来越高,传统数据库存在着先天性的缺陷,即单机(单库)性能瓶颈,并且扩展困难。这样既有单机单库瓶颈,却又扩展困难,自然无法满足日益增长的海量数据存储及其性能要求,所以才会出现了各种不同的 NoSQL 产品, NoSQL 根本性的优势在于在云计算时代,简单、易于大规模分布式扩展,并且读写性能非常高
1.3 RDBMS和NOSQL的特点及优缺点:
关系型数据库 | NoSQL数据库 | |
特点 | - 数据关系模型基于关系模型,结构化存储,完整性约束 - 基于二维表及其之间的联系,需要连接、并、交、差、除等数据操作 - 采用结构化的查询语言(SQL)做数据读写 - 操作需要数据的一致性,需要事务甚至是强一致性 | - 非结构化的存储 - 基于多维关系模型 - 具有特有的使用场景 |
优点 | - 保持数据的一致性(事务处理) - 可以进行join等复杂查询 - 通用化,技术成熟 | - 高并发,大数据下读写能力较强 - 基本支持分布式,易于扩展,可伸缩 - 简单,弱结构化存储 |
缺点 | - 数据读写必须经过sql解析,大量数据,高并发下读写性能不足 - 对数据做读写,或修改数据结构时需要加锁,影响并发操作 - 无法适应非结构化存储 - 扩展困难 - 昂贵,复杂 | - join等复杂操作能力较弱 -事务支持较弱 - 通用性差 - 无完整约束复杂业务场景支持较差 |
二 Remote Dictionary Server 简介
中文官网 : https://redis.cn
2.1 什么是redis
Redis (Remote Dictionary Server)
在 2009 年发布,开发者是意大利的萨尔瓦多 · 桑菲利波普( Salvatore Sanfilippo ),他本想为自己的公司开发一个用于替换MySQL 的产品 Redis ,但是没有想到他把 Redis 开源后大受欢迎,短短几年, Redis 就有了很大的用户群体,目前国内外使用的公司众多, 比如 : 阿里 , 百度 , 新浪微博 , 知乎网 ,GitHub,Twitter 等Redis是一个开源的、遵循 BSD 协议的、基于内存的而且目前比较流行的键值数据库 (key-value database),是一个非关系型数据库, redis 提供将内存通过网络远程共享的一种服务,提供类似功能的还有memcached ,但相比 memcached , redis 还提供了易扩展、高性能、具备数据持久性等功能。Redis 在高并发、低延迟环境要求比较高的环境使用量非常广泛
2.2 Redis特性
- 速度快: 10W QPS,基于内存,C语言实现
- 单线程
- 持久化
- 支持多种数据结构
- 支持多种编程语言
- 功能丰富: 支持Lua脚本,发布订阅,事务,pipeline等功能
- 简单: 代码短小精悍(单机核心代码只有23000行左右),单线程开发容易,不依赖外部库,使用简单
- 主从复制
- 支持高可用和分布式
单线程为何如此快?
- 纯内存
- 非阻塞
- 避免线程切换和竞态消耗
2.3 Redis应用场景
- Session 共享:常见于web集群中的Tomcat或者PHP中多web服务器session共享
- 缓存:数据查询、电商网站商品信息、新闻内容
- 计数器:访问排行榜、商品浏览数等和次数相关的数值统计场景
- 微博/微信社交场合:共同好友,粉丝数,关注,点赞评论等
- 消息队列:ELK的日志缓存、部分业务的订阅发布系统
- 地理位置: 基于GEO(地理信息定位),实现摇一摇,附近的人,外卖等功能
2.4 缓存的实现流程
数据读操作流程
三 Redis的安装
官方下载地址: http://download.redis.io/releases/
3.1 rpm包方式安装
[root@redis ~]# yum install redis
已加载插件:langpacks, product-id, search-disabled-repos, subscription-managerThis system is not registered with an entitlement server. You can use subscription-manager to register.
正在解决依赖关系
--> 正在检查事务
---> 软件包 redis.x86_64.0.3.2.12-2.el7 将被 安装
--> 正在处理依赖关系 libjemalloc.so.1()(64bit),它被软件包 redis-3.2.12-2.el7.x86_64 需要
--> 正在检查事务
---> 软件包 jemalloc.x86_64.0.3.6.0-1.el7 将被 安装
--> 解决依赖关系完成依赖关系解决
====================================================================================================================================================
Package 架构 版本 源 大小
====================================================================================================================================================
正在安装:
redis x86_64 3.2.12-2.el7 epel 544 k
为依赖而安装:
jemalloc x86_64 3.6.0-1.el7 epel 105 k事务概要
====================================================================================================================================================
安装 1 软件包 (+1 依赖软件包)总下载量:648 k
安装大小:1.7 M
3.2 源码安装
注意:在一台主机中不能用rpm安装,然后再用源码安装
[root@redis-node1 ~]# ls
redis-7.4.0.tar.gz
[root@redis-node1 ~]# tar zxf redis-7.4.0.tar.gz #解压源码包
[root@redis-node1 ~]# lsredis-7.4.0 redis-7.4.0.tar.gz#安装编译工具[root@redis-node1 redis-7.4.0]# yum install make gcc initscripts.x86_64 -y
#执行编译命令[root@redis-node1 redis-7.4.0]# make[root@redis-node1 redis-7.4.0]# make install
#启动Redis[root@redis-node1 redis-7.4.0]# cd utils/[root@redis-node1 utils]# ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis serverThis systems seems to use systemd. #提示系统使用的是systemd的初始化方式
Please take a look at the provided example service unit files in this directory, and adapt and install them. Sorry![root@redis-node1 utils]# vim install_server.sh #解决报错问题
#_pid_1_exe="$(readlink -f /proc/1/exe)"
#if [ "${_pid_1_exe##*/}" = systemd ]
#then
# echo "This systems seems to use systemd."
# echo "Please take a look at the provided example service unit files in this directory, and adapt and install them. Sorry!"
# exit 1
#fi[root@redis-node1 utils]# ./install_server.sh
[root@redis-node1 utils]# ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis serverPlease select the redis port for this instance: [6379] #端口号
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf] #配置文件Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log] #日志
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379] #数据目录Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server] #命令路径Selected config:
Port : 6379
Config file : /etc/redis/6379.conf
Log file : /var/log/redis_6379.log
Data dir : /var/lib/redis/6379
Executable : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
#配置redis[root@redis-node1 utils]# vim /etc/redis/6379.conf#bind 127.0.0.1 -::1
bind * -::*[root@redis-node1 utils]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...
[root@redis-node1 utils]# netstat -antlupe | grep redis
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 0 34073 7604/redis-server *
tcp6 0 0 :::6379 :::* LISTEN 0 34074 7604/redis-server *
# 查看信息[root@redis-node1 utils]# redis-cli
127.0.0.1:6379> info
3.3 对其他虚拟机进行源码安装
[root@redis-node1 ~]# scp -r redis-7.4.0 root@192.168.10.20:/root
[root@redis-node1 ~]# cd /usr/local/bin/
[root@redis-node1 bin]# ll
total 29444
-rwxr-xr-x 1 root root 6375248 Aug 26 20:35 redis-benchmark
lrwxrwxrwx 1 root root 12 Aug 26 20:35 redis-check-aof -> redis-server
lrwxrwxrwx 1 root root 12 Aug 26 20:35 redis-check-rdb -> redis-server
-rwxr-xr-x 1 root root 7217160 Aug 26 20:35 redis-cli
lrwxrwxrwx 1 root root 12 Aug 26 20:35 redis-sentinel -> redis-server
-rwxr-xr-x 1 root root 16547256 Aug 26 20:35 redis-server[root@redis-node1 bin]# rsync -al * root@192.168.10.20:/usr/local/bin
root@192.168.10.20's password:
[root@redis-node1 bin]#[root@redis-node2 ~]# cd redis-7.4.0/
[root@redis-node2 redis-7.4.0]# ls
00-RELEASENOTES MANIFESTO SECURITY.md
BUGS README.md sentinel.conf
CODE_OF_CONDUCT.md redis.conf src
CONTRIBUTING.md REDISCONTRIBUTIONS.txt tests
deps runtest TLS.md
INSTALL runtest-cluster utils
LICENSE.txt runtest-moduleapi
Makefile runtest-sentinel
[root@redis-node2 redis-7.4.0]# cd utils/
[root@redis-node2 utils]# ls
build-static-symbols.tcl
cluster_fail_time.tcl
corrupt_rdb.c
create-cluster
generate-command-code.py
generate-commands-json.py
generate-fmtargs.py
generate-module-api-doc.rb
gen-test-certs.sh
graphs
hyperloglog
install_server.sh
lru
redis-copy.rb
redis_init_script
redis_init_script.tpl
redis-sha1.rb
releasetools
reply_schema_linter.js
req-res-log-validator.py
req-res-validator
speed-regression.tcl
srandmember
systemd-redis_multiple_servers@.service
systemd-redis_server.service
tracking_collisions.c
whatisdoing.sh[root@redis-node2 utils]# ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis serverPlease select the redis port for this instance: [6379]
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf]
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log]
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379]
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server]
Selected config:
Port : 6379
Config file : /etc/redis/6379.conf
Log file : /var/log/redis_6379.log
Data dir : /var/lib/redis/6379
Executable : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
cp: cannot create regular file '/etc/init.d/redis_6379': No such file or directory
ERROR: Could not copy redis init script to /etc/init.d/redis_6379. Aborting![root@redis-node2 utils]# yum install initscripts.x86_64 -y #解决上面错误办法
[root@redis-node2 utils]# ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis serverPlease select the redis port for this instance: [6379]
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf]
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log]
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379]
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server]
Selected config:
Port : 6379
Config file : /etc/redis/6379.conf
Log file : /var/log/redis_6379.log
Data dir : /var/lib/redis/6379
Executable : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful![root@redis-node2 utils]# vim /etc/redis/6379.conf
#bind 127.0.0.1 -::1
bind * -::*[root@redis-node2 utils]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...
四 Redis的基本操作
#查看配置127.0.0.1:6379> CONFIG GET bind
1) "bind"
2) "* -::*"127.0.0.1:6379> CONFIG GET *
#写入和读取数据127.0.0.1:6379> SET name lee
OK127.0.0.1:6379> GET name
"lee"
127.0.0.1:6379> set name lee ex 5 #过期时间为5s
OK
127.0.0.1:6379> get name
"lee"
127.0.0.1:6379> get name
(nil)#如果没有设定数据过期时间会一直存在, /var/lib/redis/6379/dump.rdb内存快照中127.0.0.1:6379> set name lee
OK127.0.0.1:6379> keys * #查看所有key
1) "name"
#选择数据库 redisa中有0-15个数据库127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> SELECT 0
OK
127.0.0.1:6379> select 16
(error) ERR DB index is out of range
#移动数据127.0.0.1:6379> set name lee
OK
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> get name
(nil)127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get name
"lee"
#改变键名127.0.0.1:6379[1]> rename name id
OK
127.0.0.1:6379[1]> get name
(nil)
127.0.0.1:6379[1]> get id
"lee"
#设定数据过期时间127.0.0.1:6379> set name lee ex 10000
OK
127.0.0.1:6379> get name
"lee"
127.0.0.1:6379> expire name 3
(integer) 1
127.0.0.1:6379> get name
"lee"
127.0.0.1:6379> get name
(nil)
#删除127.0.0.1:6379> set name lee
OK
127.0.0.1:6379> get name
"lee"
127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> get name
(nil)
#持久化保存127.0.0.1:6379> persist name
(integer) 0
#判断key是否存在127.0.0.1:6379> exists name
(integer) 1
127.0.0.1:6379> exists xixi
(integer) 0
#清空当前库127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> get name
(nil)
#清空所有库127.0.0.1:6379[1]> flushall
OK
五 Redis 主从复制
5.1 环境配置
redis-node1 masterredis-node2 slaveredis-node3 slave
注意:在配置多台redis时建议用复制的方式节省编译时间
5.2 配置主从同步
1.修改mastser节点的配置文件
[root@redis-node1 node2 & node3 ~]# vim /etc/redis/6379.conf
protected-mode no #关闭protected模式
[root@redis-node1 node2 & node3 ~]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...
[root@redis-node2 & 3 ~]# vim /etc/redis/6379.conf
replicaof 192.168.10.10 6379
[root@redis-node2 & 3 ~]# /etc/init.d/redis_6379 restart
Stopping ...
Redis stopped
Starting Redis server...
#在mastser节点[root@redis-node1 ~]# redis-cli
127.0.0.1:6379> set name lee
OK
#在slave节点查看[root@redis-node2 ~]# redis-cli
127.0.0.1:6379> get name
"lee"[root@redis-node3 ~]# redis-cli
127.0.0.1:6379> get name
"lee"
5.3 主从同步过程
- slave节点发送同步亲求到master节点
- slave节点通过master节点的认证开始进行同步
- master节点会开启bgsave进程发送内存rbd到slave节点,在此过程中是异步操作,也就是说
- master节点仍然可以进行写入动作
- slave节点收到rdb后首先清空自己的所有数据
- slave节点加载rdb并进行数据恢复
- 在master和slave同步过程中master还会开启新的bgsave进程把没有同步的数据进行缓存
- 然后通过自有的replactionfeedslave函数把未通过内存快照发动到slave的数据一条一条写入到slave中
六 Redis的哨兵(高可用)
实验环境: 我们用主两从来实现 Redis 的高可用架构
6.1 Redis哨兵
Sentinel 进程是用于监控 redis 集群中 Master 主服务器工作的状态,在 Master 主服务器发生故障的时候,可以实现Master 和 Slave 服务器的切换,保证系统的高可用,此功能在 redis2.6+ 的版本已引用, Redis 的 哨兵模式到了2.8 版本之后就稳定了下来。一般在生产环境也建议使用 Redis 的 2.8 版本的以后版本每个哨兵 (Sentinel) 进程会向其它哨兵 (Sentinel) 、 Master 、 Slave 定时发送消息,以确认对方是否 ” 活 ”着,如果发现对方在指定配置时间( 此项可配置 ) 内未得到回应,则暂时认为对方已离线,也就是所谓的 ”主观认为宕机” ( 主观 : 是每个成员都具有的独自的而且可能相同也可能不同的意识 ) ,英文名称:Subjective Down,简称 SDOWN有主观宕机,对应的有客观宕机。当 “ 哨兵群 ” 中的多数 Sentinel 进程在对 Master 主服务器做出 SDOWN 的判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的 Master Server 下线判断,这种方式就是“ 客观宕机 ”( 客观 : 是不依赖于某种意识而已经实际存在的一切事物 ) ,英文名称是:Objectively Down, 简称 ODOWN通过一定的 vote 算法,从剩下的 slave 从服务器节点中,选一台提升为 Master 服务器节点,然后自动修改相关配置,并开启故障转移(failover )Sentinel 机制可以解决 master 和 slave 角色的自动切换问题,但单个 Master 的性能瓶颈问题无法解决 , 类似于MySQL 中的 MHA 功能Redis Sentinel 中的 Sentinel 节点个数应该为大于等于 3 且最好为奇数
- 每10秒每个sentinel对master和slave执行info
- 发现slave节点
- 确认主从关系
- 每2秒每个sentinel通过master节点的channel交换信息(pub/sub)
- 通过sentinel__:hello频道交互
- 交互对节点的“看法”和自身信息
- 每1秒每个sentinel对其他sentinel和redis执行p
6.2 哨兵的实验过程
在所有阶段中关闭 protected-mode no
[root@redis-node1 ~]# cd redis-7.4.0/[root@redis-node1 redis-7.4.0]# cp sentinel.conf /etc/redis/[root@redis-node1 ~]# vim /etc/redis/sentinel.confprotected-mode no #关闭保护模式port 26379 #监听端口
daemonize no #进入不打如后台pidfile /var/run/redis-sentinel.pid #sentinel进程pid文件loglevel notice #日志级别
sentinel monitor mymaster 192.168.10.10 6379 2 #创建sentinel监控监控master主机,2表示必须得到2票sentinel down-after-milliseconds mymaster 30000 #master中断时长,30秒连不上视为[root@redis-node1 ~]# scp /etc/redis/sentinel.conf root@192.168.10.20:/etc/redis/master下线sentinel parallel-syncs mymaster 1 #发生故障转移后,同时开始同步新master数据的slave数量sentinel failover-timeout mymaster 180000 #整个故障切换的超时时间为3分钟
#复制配置文件到其他虚拟机
root@192.168.10.20's password:
sentinel.conf 100% 14KB 13.4MB/s 00:00
[root@redis-node1 ~]# scp /etc/redis/sentinel.conf root@192.168.10.30:/etc/redis/
root@192.168.10.30's password:
sentinel.conf 100% 14KB 13.7MB/s 00:00
[root@redis-node1 ~]#
[root@redis-node1 redis-7.4.0]# redis-sentinel /etc/redis/sentinel.conf7890:X 26 Aug 2024 22:10:12.386 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
7890:X 26 Aug 2024 22:10:12.386 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7890:X 26 Aug 2024 22:10:12.386 * Redis version=7.4.0, bits=64, commit=00000000, modified=0, pid=7890, just started
7890:X 26 Aug 2024 22:10:12.386 * Configuration loaded
7890:X 26 Aug 2024 22:10:12.387 * Increased maximum number of open files to 10032 (it was originally set to 1024).
7890:X 26 Aug 2024 22:10:12.387 * monotonic clock: POSIX clock_gettime
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis Community Edition
.-`` .-```. ```\/ _.,_ ''-._ 7.4.0 (00000000/0) 64 bit
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 26379
| `-._ `._ / _.-' | PID: 7890
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | https://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'7890:X 26 Aug 2024 22:10:12.392 * Sentinel new configuration saved on disk
7890:X 26 Aug 2024 22:10:12.392 * Sentinel ID is 594c3047480c3363e697a01a2c8757ab564343c8
7890:X 26 Aug 2024 22:10:12.392 # +monitor master mymaster 192.168.10.10 6379 quorum 2
7890:X 26 Aug 2024 22:10:12.394 * +slave slave 192.168.10.20:6379 192.168.10.20 6379 @ mymaster 192.168.10.10 6379
7890:X 26 Aug 2024 22:10:12.395 * Sentinel new configuration saved on disk
7890:X 26 Aug 2024 22:10:12.395 * +slave slave 192.168.10.30:6379 192.168.10.30 6379 @ mymaster 192.168.10.10 6379
7890:X 26 Aug 2024 22:10:12.397 * Sentinel new configuration saved on disk
注意:/etc/redis/sentinel.conf 文件在用哨兵程序调用后会更改其配置文件,如果需要重新做需要删掉文件重新编辑
#在开一个 master 节点终端[root@redis-node1 ~]# redis-cli
127.0.0.1:6379> shutdown
not connected>
[root@redis-node2 ~]# redis-cli
127.0.0.1:6379> info replication
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
min_slaves_good_slaves:1
slave0:ip=192.168.10.30,port=6379,state=online,offset=31713,lag=1
master_failover_state:no-failover
master_replid:2a3da82630bcab7d52cb5d3c05309d9213454295
master_replid2:94245e5f70edca32156188cd43c2f8d01dbbe9b8
master_repl_offset:31854
second_repl_offset:20200
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:31854
6.3. 在整个架构中可能会出现的问题
在生产环境中如果 master 和 slave 中的网络出现故障,由于哨兵的存在会把 master 提出去当网络恢复后, master 发现环境发生改变, master 就会把自己的身份转换成 slavemaster 变成 slave 后会把网络故障那段时间写入自己中的数据清掉,这样数据就丢失了。
master 在被写入数据时会持续连接 slave , mater 确保有 2 个 slave 可以写入我才允许写入如果 slave 数量少于 2 个便拒绝写入
# 在 matster 中设定127.0.0.1:6379> config get min-slaves-to-write 2
1) "min-slaves-to-write"
2) "0"
127.0.0.1:6379> config set min-slaves-to-write 2
OK
127.0.0.1:6379> config get min-slaves-to-write
1) "min-slaves-to-write"
2) "2"# 如果要永久保存写到配置文件中 /etc/redis/6379.conf
七 Redis Cluster(无中心化设计)
7.1 Redis Cluster 工作原理
在哨兵 sentinel 机制中,可以解决 redis 高可用问题,即当 master 故障后可以自动将 slave 提升为 master ,从而可以保证redis 服务的正常使用,但是无法解决 redis 单机写入的瓶颈问题,即单机 redis 写入性能受限于单机的内存大小、并发数量、网卡速率等因素。redis 3.0 版本之后推出了无中心架构的 redis cluster 机制,在无中心的 redis 集群当中,其每个节点保存当前节点数据和整个集群状态, 每个节点都和其他所有节点连接
1. 所有 Redis 节点使用 (PING 机制 ) 互联2. 集群中某个节点的是否失效,是由整个集群中超过半数的节点监测都失效,才能算真正的失效3. 客户端不需要 proxy 即可直接连接 redis ,应用程序中需要配置有全部的 redis 服务器 IP4. redis cluster 把所有的 redis node 平均映射到 0-16383 个槽位 (slot) 上,读写需要到指定的 redis-node上进行操作,因此有多少个 redis node 相当于 redis 并发扩展了多少倍,每个 redis node 承担16384/N个槽位5. Redis cluster 预先分配 16384 个 (slot) 槽位,当需要在 redis 集群中写入一个 key -value 的时候,会使用CRC16(key) mod 16384 之后的值,决定将 key 写入值哪一个槽位从而决定写入哪一个 Redis 节点上,从而有效解决单机瓶颈。
节点 A 覆盖 0 - 5460节点 B 覆盖 5461 - 10922节点 C 覆盖 10923 - 16383
Redis cluster 的架构虽然解决了并发的问题,但是又引入了一个新的问题,每个 Redis master 的高可用如何解决?那就是对每个 master 节点都实现主从复制 , 从而实现 redis 高可用性
7.2 创建redis cluster的前提
1. 每个 redis node 节点采用相同的硬件配置、相同的密码、相同的 redis 版本。2. 每个节点必须开启的参数
- cluster-enabled yes #必须开启集群状态,开启后redis进程会有cluster显示
- cluster-config-file nodes-6380.conf #此文件有redis cluster集群自动创建和维护,不需要任何手动操作
3. 所有 redis 服务器必须没有任何数据4. 先启动为单机 redis 且没有任何 key value
7.3 部署redis cluster
[root@redis-node1 ~]# vim /etc/redis/redis.conf
#bind 127.0.0.1 -::1
bind * -::*masterauth "123456" #集群主从认证
requirepass "123456" #redis登陆密码 redis-cli 命令连接redis后要用“auth 密码”进行认证cluster-enabled yes #开启cluster集群功能cluster-config-file nodes-6379.conf #指定集群配置文件cluster-node-timeout 15000 #节点加入集群的超时时间单位是ms[root@redis-node1 ~]# systemctl enable --now redis.service
Created symlink /etc/systemd/system/multi-user.target.wants/redis.service → /usr/lib/systemd/system/redis.service.
[root@redis-node1 ~]# redis-cli #注意:如果不能登录就退出重新进入
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> info# Cluster
cluster_enabled:1
[root@redis-node1 ~]# for i in 20 30 110 120 130; do scp /etc/redis/redis.conf root@192.168.10.$i:/etc/redis/redis.conf; done
root@192.168.10.20's password:
redis.conf 100% 92KB 26.3MB/s 00:00
root@192.168.10.30's password:
redis.conf 100% 92KB 27.4MB/s 00:00
The authenticity of host '192.168.10.110 (192.168.10.110)' can't be established.
ED25519 key fingerprint is SHA256:aPQhrNl0dlmH+S91HwLx/iUxFtRBR8KY1GIdXwaLi40.
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:1: 192.168.10.20
~/.ssh/known_hosts:4: 192.168.10.30
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.10.110' (ED25519) to the list of known hosts.
root@192.168.10.110's password:
redis.conf 100% 92KB 13.8MB/s 00:00
The authenticity of host '192.168.10.120 (192.168.10.120)' can't be established.
ED25519 key fingerprint is SHA256:aPQhrNl0dlmH+S91HwLx/iUxFtRBR8KY1GIdXwaLi40.
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:1: 192.168.10.20
~/.ssh/known_hosts:4: 192.168.10.30
~/.ssh/known_hosts:5: 192.168.10.110
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.10.120' (ED25519) to the list of known hosts.
root@192.168.10.120's password:
redis.conf 100% 92KB 27.7MB/s 00:00
The authenticity of host '192.168.10.130 (192.168.10.130)' can't be established.
ED25519 key fingerprint is SHA256:aPQhrNl0dlmH+S91HwLx/iUxFtRBR8KY1GIdXwaLi40.
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:1: 192.168.10.20
~/.ssh/known_hosts:4: 192.168.10.30
~/.ssh/known_hosts:5: 192.168.10.110
~/.ssh/known_hosts:6: 192.168.10.120
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.10.130' (ED25519) to the list of known hosts.
root@192.168.10.130's password:
redis.conf 100% 92KB 36.8MB/s 00:00
[root@redis-node1 ~]#
7.4 redis-cli --cluster 参数说明
[root@redis-node1 ~]# redis-cli --cluster help
Cluster Manager Commands:create host1:port1 ... hostN:portN # 创建集群--cluster-replicas <arg> # 指定 master 的副本数check <host:port> or <host> <port> # 检测集群信息info <host:port> or <host> <port> # 查看集群信息fix <host:port> or <host> <port> # 修复集群reshard <host:port> or <host> <port> # 在线热迁移集群指定主机的 slots 数据rebalance <host:port> or <host> <port> # 平衡各集群主机的 slot 数量add-node new_host:new_port existing_host:existing_port # 添加主机del-node host:port node_id # 删除主机import host:port # 导入外部 redis 服务器的数据到当前集群
7.5. 创建redis-cluster
[root@redis-node1 ~]# redis-cli --cluster create -a 123456 \
> 192.168.10.10:6379 192.168.10.20:6379 192.168.10.30:6379 \
> 192.168.10.110:6379 192.168.10.120:6379 192.168.10.130:6379 \
> --cluster-replicas 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460 #哈希槽分配
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.10.120:6379 to 192.168.10.10:6379 #主从分配情况
Adding replica 192.168.10.130:6379 to 192.168.10.20:6379
Adding replica 192.168.10.110:6379 to 192.168.10.30:6379
M: e4080469f222490f3dca3dbff733cc816047c6a6 192.168.10.10:6379
slots:[0-5460] (5461 slots) master
M: 5d7aa0ed54e855b1019600fd64a97d51f81c3830 192.168.10.20:6379
slots:[5461-10922] (5462 slots) master
M: d49b90e7d194e6494c02a935c8287d60671d3cb1 192.168.10.30:6379
slots:[10923-16383] (5461 slots) master
S: e1343110403eead3b256e99ceb7e9a5253be50b2 192.168.10.110:6379
replicates d49b90e7d194e6494c02a935c8287d60671d3cb1
S: 9738a76c530a4e1e7007d71c811373c3e52b4dc1 192.168.10.120:6379
replicates e4080469f222490f3dca3dbff733cc816047c6a6
S: 3cb625f3c7a009a8f0d17688c0a9d942954f1ef3 192.168.10.130:6379
replicates 5d7aa0ed54e855b1019600fd64a97d51f81c3830
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join>>> Performing Cluster Check (using node 192.168.10.10:6379)
M: e4080469f222490f3dca3dbff733cc816047c6a6 192.168.10.10:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: d49b90e7d194e6494c02a935c8287d60671d3cb1 192.168.10.30:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: e1343110403eead3b256e99ceb7e9a5253be50b2 192.168.10.110:6379
slots: (0 slots) slave
replicates d49b90e7d194e6494c02a935c8287d60671d3cb1
S: 3cb625f3c7a009a8f0d17688c0a9d942954f1ef3 192.168.10.130:6379
slots: (0 slots) slave
replicates 5d7aa0ed54e855b1019600fd64a97d51f81c3830
S: 9738a76c530a4e1e7007d71c811373c3e52b4dc1 192.168.10.120:6379
slots: (0 slots) slave
replicates e4080469f222490f3dca3dbff733cc816047c6a6
M: 5d7aa0ed54e855b1019600fd64a97d51f81c3830 192.168.10.20:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots... #检查打开的哈希槽位
>>> Check slots coverage... #检查槽位覆盖范围
[OK] All 16384 slots covered. #所有槽位分配完成
[root@redis-node1 ~]##配置文件位置[root@redis-node1 ~]# ll /var/lib/redis/nodes-6379.conf
[root@redis-node1 ~]# redis-cli -a 123456 --cluster check 192.168.10.20:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
192.168.10.20:6379 (5d7aa0ed...) -> 0 keys | 5462 slots | 1 slaves.
192.168.10.10:6379 (e4080469...) -> 0 keys | 5461 slots | 1 slaves.
192.168.10.30:6379 (d49b90e7...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.10.20:6379)
M: 5d7aa0ed54e855b1019600fd64a97d51f81c3830 192.168.10.20:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
M: e4080469f222490f3dca3dbff733cc816047c6a6 192.168.10.10:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: d49b90e7d194e6494c02a935c8287d60671d3cb1 192.168.10.30:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 3cb625f3c7a009a8f0d17688c0a9d942954f1ef3 192.168.10.130:6379
slots: (0 slots) slave
replicates 5d7aa0ed54e855b1019600fd64a97d51f81c3830
S: e1343110403eead3b256e99ceb7e9a5253be50b2 192.168.10.110:6379
slots: (0 slots) slave
replicates d49b90e7d194e6494c02a935c8287d60671d3cb1
S: 9738a76c530a4e1e7007d71c811373c3e52b4dc1 192.168.10.120:6379
slots: (0 slots) slave
replicates e4080469f222490f3dca3dbff733cc816047c6a6
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@redis-node1 ~]# redis-cli -a 123456 --cluster info 192.168.10.20:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
192.168.10.20:6379 (5d7aa0ed...) -> 0 keys | 5462 slots | 1 slaves.
192.168.10.10:6379 (e4080469...) -> 0 keys | 5461 slots | 1 slaves.
192.168.10.30:6379 (d49b90e7...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
[root@redis-node1 ~]# redis-cli -a 123456 cluster info
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:612
cluster_stats_messages_pong_sent:610
cluster_stats_messages_sent:1222
cluster_stats_messages_ping_received:605
cluster_stats_messages_pong_received:612
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:1222
[root@redis-node1 ~]# 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> set key1 value1 #被分配到20的hash槽位上
(error) MOVED 9189 192.168.10.20:6379[root@redis-node2 ~]# 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> set key1 value1
OK
7.6 集群扩容
#添加master[root@redis-node1 ~]# redis-cli -a 123456 --cluster add-node 192.168.10.50:6379 192.168.10.10:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Adding node 192.168.10.50:6379 to cluster 192.168.10.10:6379
>>> Performing Cluster Check (using node 192.168.10.10:6379)
M: e4080469f222490f3dca3dbff733cc816047c6a6 192.168.10.10:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: d49b90e7d194e6494c02a935c8287d60671d3cb1 192.168.10.30:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: e1343110403eead3b256e99ceb7e9a5253be50b2 192.168.10.110:6379
slots: (0 slots) slave
replicates d49b90e7d194e6494c02a935c8287d60671d3cb1
S: 3cb625f3c7a009a8f0d17688c0a9d942954f1ef3 192.168.10.130:6379
slots: (0 slots) slave
replicates 5d7aa0ed54e855b1019600fd64a97d51f81c3830
S: 9738a76c530a4e1e7007d71c811373c3e52b4dc1 192.168.10.120:6379
slots: (0 slots) slave
replicates e4080469f222490f3dca3dbff733cc816047c6a6
M: 5d7aa0ed54e855b1019600fd64a97d51f81c3830 192.168.10.20:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 192.168.10.50:6379 to make it join the cluster.
[OK] New node added correctly.[root@redis-node1 ~]# redis-cli -a 123456 --cluster info 192.168.10.10:6379
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
192.168.10.10:6379 (e4080469...) -> 0 keys | 4096 slots | 1 slaves.
192.168.10.30:6379 (d49b90e7...) -> 0 keys | 4096 slots | 1 slaves.
192.168.10.50:6379 (a9e12ea2...) -> 0 keys | 4096 slots | 0 slaves.
192.168.10.20:6379 (5d7aa0ed...) -> 1 keys | 4096 slots | 1 slaves.
[OK] 1 keys in 4 masters.
0.00 keys per slot on average.
#分配槽位[root@redis-node1 ~]# redis-cli -a 123456 --cluster reshard 192.168.10.10:6379Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.>>> Performing Cluster Check (using node 192.168.10.10:6379)
M: e4080469f222490f3dca3dbff733cc816047c6a6 192.168.10.10:6379
slots:[1365-5460] (4096 slots) master
1 additional replica(s)
M: d49b90e7d194e6494c02a935c8287d60671d3cb1 192.168.10.30:6379
slots:[12288-16383] (4096 slots) master
1 additional replica(s)
S: e1343110403eead3b256e99ceb7e9a5253be50b2 192.168.10.110:6379
slots: (0 slots) slave
replicates d49b90e7d194e6494c02a935c8287d60671d3cb1
S: 3cb625f3c7a009a8f0d17688c0a9d942954f1ef3 192.168.10.130:6379
slots: (0 slots) slave
replicates 5d7aa0ed54e855b1019600fd64a97d51f81c3830
M: a9e12ea2f73166f912a6251089d650c4924bb86c 192.168.10.50:6379
slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
S: 9738a76c530a4e1e7007d71c811373c3e52b4dc1 192.168.10.120:6379
slots: (0 slots) slave
replicates e4080469f222490f3dca3dbff733cc816047c6a6
M: 5d7aa0ed54e855b1019600fd64a97d51f81c3830 192.168.10.20:6379
slots:[6827-10922] (4096 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.How many slots do you want to move (from 1 to 16384 )? 4096What is the receiving node ID? a9e12ea2f73166f912a6251089d650c4924bb86cPlease enter all the source node IDs.Type 'all' to use all the nodes as source nodes for the hash slots.Type 'done' once you entered all the source nodes IDs.Source node #1: all
#添加salve[root@redis-node1 ~]# redis-cli -a 123456 --cluster add-node 192.168.10.150:6379 192.168.10.10:6379 --cluster-slave --cluster-master-id a9e12ea2f73166f912a6251089d650c4924bb86c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Adding node 192.168.10.150:6379 to cluster 192.168.10.10:6379
>>> Performing Cluster Check (using node 192.168.10.10:6379)
M: e4080469f222490f3dca3dbff733cc816047c6a6 192.168.10.10:6379
slots:[1365-5460] (4096 slots) master
1 additional replica(s)
M: d49b90e7d194e6494c02a935c8287d60671d3cb1 192.168.10.30:6379
slots:[12288-16383] (4096 slots) master
1 additional replica(s)
S: e1343110403eead3b256e99ceb7e9a5253be50b2 192.168.10.110:6379
slots: (0 slots) slave
replicates d49b90e7d194e6494c02a935c8287d60671d3cb1
S: 3cb625f3c7a009a8f0d17688c0a9d942954f1ef3 192.168.10.130:6379
slots: (0 slots) slave
replicates 5d7aa0ed54e855b1019600fd64a97d51f81c3830
M: a9e12ea2f73166f912a6251089d650c4924bb86c 192.168.10.50:6379
slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
S: 9738a76c530a4e1e7007d71c811373c3e52b4dc1 192.168.10.120:6379
slots: (0 slots) slave
replicates e4080469f222490f3dca3dbff733cc816047c6a6
M: 5d7aa0ed54e855b1019600fd64a97d51f81c3830 192.168.10.20:6379
slots:[6827-10922] (4096 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 192.168.10.150:6379 to make it join the cluster.
Waiting for the cluster to join>>> Configure node as replica of 192.168.10.50:6379.
[OK] New node added correctly.
7.7 clsuter集群维护
#删除master[root@redis-node1 ~]# redis-cli -a 123456 --cluster del-node 192.168.10.150:6379 5418593c9f88c11c61ec599880c49475d5b1ba5
0
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Removing node 5418593c9f88c11c61ec599880c49475d5b1ba50 from cluster 192.168.10.150:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.#移除要下线主机的哈希槽位[root@redis-node1 ~]# redis-cli -a 123456 --cluster reshard 192.168.10.10:6379Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.>>> Performing Cluster Check (using node 192.168.10.10:6379)
M: e4080469f222490f3dca3dbff733cc816047c6a6 192.168.10.10:6379
slots:[1365-5460] (4096 slots) master
1 additional replica(s)
M: d49b90e7d194e6494c02a935c8287d60671d3cb1 192.168.10.30:6379
slots:[12288-16383] (4096 slots) master
1 additional replica(s)
S: e1343110403eead3b256e99ceb7e9a5253be50b2 192.168.10.110:6379
slots: (0 slots) slave
replicates d49b90e7d194e6494c02a935c8287d60671d3cb1
S: 3cb625f3c7a009a8f0d17688c0a9d942954f1ef3 192.168.10.130:6379
slots: (0 slots) slave
replicates 5d7aa0ed54e855b1019600fd64a97d51f81c3830
M: a9e12ea2f73166f912a6251089d650c4924bb86c 192.168.10.50:6379
slots:[0-1364],[5461-6826],[10923-12287] (4096 slots) master
S: 9738a76c530a4e1e7007d71c811373c3e52b4dc1 192.168.10.120:6379
slots: (0 slots) slave
replicates e4080469f222490f3dca3dbff733cc816047c6a6
M: 5d7aa0ed54e855b1019600fd64a97d51f81c3830 192.168.10.20:6379
slots:[6827-10922] (4096 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? 5d7aa0ed54e855b1019600fd64a97d51f81c3830
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1: a9e12ea2f73166f912a6251089d650c4924bb86c
Source node #2: done