文章目录
- 一、Redis介绍
- 1、介绍
- 2、业务使用场合
- 3、对比 memcached
- 二、源码编译安装
- 三、数据结构类型操作
- 1、String
- 2、Hash
- 3、List
- 4、Set
- 5、zset
- 四、数据持久化操作
- 1、snappshoting(快照)
- 2、append only file
- 3、总结
- 五、主从模式
- 六、哨兵模式
- 1、配置主服务器的 IP 和端口
- 3、启动所有的 Sentinel
- 4、测试 master 宕机
- 5、测试 master 重连
- 七、Redis 集群
- 1、主机规划
- 2、环境初始化
- 3、编译安装
- 4、启动 redis-server 服务
- 5、启动 redis 集群
- 6、测试集群
- 八、安全设置
- 1、设置密码
- 2、限制 IP 访问
一、Redis介绍
1、介绍
Redis(Remote Dictionary Server ),即远程字典服务,由意大利人 antirez (Salvatore Sanfilippo) 开发的一款,内存高速缓存数据库。
它支持丰富的数据结构,比如 String、list(双向链表)、hash(哈希)、set(集合)、sorted set(zset有序集合)
可持久化(保存数据到磁盘中),保证了数据安全
2、业务使用场合
- [Sort Set] 排行榜应用,取 top N 操作,例如 sina 微博热门话题
- [List] 获得最新 N 个数据 或 某个分类的最新数据
- [String] 计数器应用
- [Set] sns (social network site) 获得共同好友
- [Set] 防攻击系统(ip判断)黑白名单等等
3、对比 memcached
- Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。
- Redis 支持 master-slave (主—从)模式应用。
- Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
- Redis 单个 value 存储 string 的最大限制是 512MB,memcached 只能保存 1MB 的数据
- Redis 是单核,memcached 是多核
二、源码编译安装
官方网址:https://redis.io
github: https://github.com/antirez/redis
安装脚本
vi install.sh
#!/bin/bash
yum install -y wget gcc vim
wget https://download.redis.io/releases/redis-5.0.14.tar.gz
tar -zxvf redis-5.0.14.tar.gz
cd redis-5.0.14
make PREFIX=/opt/redis install
cp redis.conf /opt/redis
cp sentinel.conf /opt/redis
echo 'export PATH=$PATH:/opt/redis/bin' >> ~/.bashrc
source ~/.bashrc
# 编写启动脚本
cat > /usr/lib/systemd/system/redis.service << EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
PIDFile=/var/run/redis_6379.pid
ExecStart=/opt/redis/bin/redis-server /opt/redis/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
LimitNOFILE=655360
PrivateTmp=true
Type=notify
User=root
Group=root
[Install]
WantedBy=multi-user.target
EOF
cat > /usr/lib/systemd/system/redis-sentinel.service << EOF
[Unit]
Description=Redis Sentinel
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
PIDFile=/var/run/redis-sentinel.pid
ExecStart=/opt/redis/bin/redis-sentinel /opt/redis/sentinel.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=root
Group=root
[Install]
WantedBy=multi-user.target
EOF
安装
source install.sh
启动 redis.server
systemctl start redis && systemctl enable redis
三、数据结构类型操作
Redis 支持五种数据类型:
- string(字符串)
- hash(哈希)
- list(列表)
- set(集合)
- zset(sorted set:有序集合)
类型 | 简介 | 特性 | 场景 |
String | 二进制安全 | 可以包含任何数据,比如 jpg 图片或者序列化的对象,一个键最大能存储 512M | 大部分场景 |
Hash | 键值对集合,即编程语言中的 Map 类型 | 适合存储对象,并且可以像数据库中 update 一个属性一样只修改某一项属性值 | 存储、读取、修改用户属性 |
List | 链表(双向链表) | 增删快,提供了操作某一段元素的 API | 1、最新消息排行等功能(比如朋友圈的时间线) 2、消息队列 |
Set | 哈希表实现,元素不重复 | 1、添加、删除,查找的复杂度都是O(1) 2、为集合提供了求交集、并集、差集等操作 | 1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据 tag 求交集,大于某个阈值就可以推荐 |
Sorted Set | 将 Set 中的元素增加一个权重参数 score,元素按 score 有序排列 | 数据插入集合时,已经进行天然排序 | 1、排行榜 2、带权重的消息队列 |
数据库
Redis 支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念。
Redis 是一个字典结构的存储服务器,而实际上一个 Redis 实例提供了多个用来存储数据的字典,客户端可以指定将数据存储在哪个字典中。这与我们熟知的在一个关系数据库实例中可以创建多个数据库类似,所以可以将其中的每个字典都理解成一个独立的数据库。
每个数据库对外都是一个从 0 开始的递增数字命名,Redis 默认支持 16 个数据库(可以通过配置文件 databases 16
支持更多,无上限)。客户端与 Redis 建立连接后会自动选择 0 号数据库,不过可以随时使用 SELECT
命令更换数据库,如要选择 1 号数据库:
redis> SELECT 1
OK
redis [1] > GET foo
(nil)
然而这些以数字命名的数据库又与我们理解的数据库有所区别。
- Redis 不支持自定义数据库的名字,每个数据库都以编号命名,开发者必须自己记录哪些数据库存储了哪些数据。
- Redis 也不支持为每个数据库设置不同的访问密码,所以一个客户端要么可以访问全部数据库,要么连一个数据库也没有权限访问。
- 最重要的一点是多个数据库之间并不是完全隔离的,比如
FLUSHALL
命令可以清空一个 Redis 实例中所有数据库中的数据。
综上所述,这些数据库更像是一种命名空间,而不适宜存储不同应用程序的数据。比如可以使用 0 号数据库存储某个应用生产环境中的数据,使用 1 号数据库存储测试环境中的数据,但不适宜使用 0 号数据库存储 A 应用的数据而使用 1 号数据库 B 应用的数据,不同的应用应该使用不同的 Redis 实例存储数据。
1、String
String 是 Redis 最基本的类型,一个 key 对应一个 value。String 类型的值最大能存储 512MB。
String 类型是二进制安全的。意思是 Redis 的 String 可以包含任何数据。比如 jpg 图片或者序列化的对象。
127.0.0.1:6379> SET Name 'liuli'
OK
127.0.0.1:6379> GET Name
"liuli"
127.0.0.1:6379> DEL Name
(integer) 1
127.0.0.1:6379> GET Name
(nil)
2、Hash
Redis hash 是一个键值(key=>value)对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
127.0.0.1:6379> HMSET userInfo name 'liuli' age 25 phone 110
OK
127.0.0.1:6379> HGET userInfo name
"liuli"
127.0.0.1:6379> HGET userInfo age
"25"
127.0.0.1:6379> HGET userInfo phone
"110"
127.0.0.1:6379> HKEYS userInfo
1) "name"
2) "age"
3) "phone"
127.0.0.1:6379> HVALS userInfo
1) "liuli"
2) "25"
3) "110"
127.0.0.1:6379> HGETALL userInfo
1) "name"
2) "liuli"
3) "age"
4) "25"
5) "phone"
6) "110"
3、List
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
127.0.0.1:6379> LPUSH language C
(integer) 1
127.0.0.1:6379> LPUSH language Java
(integer) 2
127.0.0.1:6379> LPUSH language Python
(integer) 3
127.0.0.1:6379> LPUSH language PHP
(integer) 4
127.0.0.1:6379> RPUSH language Node
(integer) 5
127.0.0.1:6379> LRANGE language 0 10
1) "PHP"
2) "Python"
3) "Java"
4) "C"
5) "Node"
4、Set
Redis 的 Set 是 String 类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
127.0.0.1:6379> SADD database redis
(integer) 1
127.0.0.1:6379> SADD database mysql
(integer) 1
127.0.0.1:6379> SADD database oracle
(integer) 1
127.0.0.1:6379> SMEMBERS database
1) "mysql"
2) "oracle"
3) "redis"
5、zset
Redis zset 和 set 一样也是 strin g类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。
zset 的成员是唯一的,但分数(score)却可以重复。
127.0.0.1:6379> ZADD subject 99 math
(integer) 1
127.0.0.1:6379> ZADD subject 68 english
(integer) 1
127.0.0.1:6379> ZADD subject 77 physics
(integer) 1
127.0.0.1:6379> ZADD subject 87 Chinese
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE subject 0 100
1) "english"
2) "physics"
3) "Chinese"
4) "math"
四、数据持久化操作
数据 持久化(数据在服务或者软件重启之后不丢失)
如果数据只存在内存中,肯定会丢失,实现持久化,就需要把数据存储到磁盘中(hdd ssd)
1、snappshoting(快照)
默认 snappshoting 是开启的,有一个备份的频率
通过查看配置文件可以看到
备份文件名称
# The filename where to dump the DB
dbfilename dump.rdb
手动数据备份
127.0.0.1:6379> SAVE
数据恢复 需要先停掉 redis 服务
如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可
2、append only file
开启 aof 后,之前的 redis 里的数据会丢失
# 开启 aof 模式
appendonly yes
# 备份文件
appendfilename "appendonly.aof"
# 备份频率
# always 每操作一次备份一次
# everysec 每秒钟备份一次
# no redis 空闲时备份一次
appendfsync everysec
3、总结
snappshoting 一般的数据持久化使用,效率高,数据迁移方便
aof 适合于备份、数据实时性备份要求更高的情况
五、主从模式
ip | Redis 版本 | 角色 |
192.168.0.11 | 5.0.14 | master |
192.168.0.12 | 5.0.14 | slave1 |
192.168.0.13 | 5.0.14 | slave2 |
注意:主从涉及主机间通讯,要提前开通防火墙的 6379 端口,或者使用命令
systemctl stop firewalld
关闭防火墙
搭建过程见本文的第二步源码编译安装,这里直接修改搭建后的配置文件实现主从
修改所有主机的 redis.conf
配置文件,bind 的 ip 指的是其他的主机需要和这个主机通讯的 ip
# 添加本机网卡绑定的IP
bind 0.0.0.0
# 关闭保护模式
protected-mode no
重启 redis
systemctl restart redis
修改 slave 主机的 redis.conf
配置文件,设置 master redis 信息
# 指定 master 主机的 ip port
replicaof 192.168.0.11 6379
重启 redis
systemctl restart redis
查看 master 同步信息
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.0.13,port=6379,state=online,offset=28,lag=1
slave1:ip=192.168.0.12,port=6379,state=online,offset=28,lag=1
master_replid:d48302fed4894b3267a8bab3276a0342cb93d1d1
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:28
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:28
查看 slave 同步信息
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:192.168.0.11
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:70
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:d48302fed4894b3267a8bab3276a0342cb93d1d1
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70
六、哨兵模式
哨兵模式是一种特殊的模式,首先 Redis 提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待 Redis 服务器响应,从而监控运行的多个 Redis 实例。
这里的哨兵有两个作用
- 通过发送命令,让 Redis 服务器返回监控其运行状态,包括主服务器和从服务器。
- 当哨兵监测到 master 宕机,会自动将 slave 切换成 master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。
然而一个哨兵进程对 Redis 服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。
ip | Redis 版本 | 角色 | 端口 |
192.168.0.11 | 5.0.14 | master、Sentinel | 6379、26379 |
192.168.0.12 | 5.0.14 | slave1、Sentinel | 6379、26379 |
192.168.0.13 | 5.0.14 | slave2、Sentinel | 6379、26379 |
特别注意:使用 Redis 哨兵模式,最少需要 3 个节点(一主多从结构)
1、配置主服务器的 IP 和端口
在 slave
从服务器上,修改 sentinel.conf
配置文件,设置主服务器的 IP 和端口,并且加上权值为2,这里的权值,是用来计算我们需要将哪一台服务器升级升主服务器。
注意:这里只配置两个 slave 服务器即可
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 192.168.0.11 6379 2
3、启动所有的 Sentinel
systemctl start redis-sentinel && systemctl enable redis-sentinel
4、测试 master 宕机
将 master 服务器关机后
重新查看两个 slave 的主从情况,发现 192.168.0.12 已经成为 master 服务器了
- 192.168.0.12
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.0.13,port=6379,state=online,offset=9157,lag=1
master_replid:e4c7fe2a464f81699f72ad63276fa042fcfcca12
master_replid2:1d1bab9ef29471bf516a86c75f33944fbf3fa205
master_repl_offset:9157
second_repl_offset:8426
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:9157
- 192.168.0.13
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:192.168.0.12
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:9157
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:e4c7fe2a464f81699f72ad63276fa042fcfcca12
master_replid2:1d1bab9ef29471bf516a86c75f33944fbf3fa205
master_repl_offset:9157
second_repl_offset:8426
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:9157
5、测试 master 重连
将 master 主机开机后,重新启动 redis 服务,查看主从情况,以 slave 的身份加入集群
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:192.168.0.12
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:24902
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:e4c7fe2a464f81699f72ad63276fa042fcfcca12
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:24902
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:19681
repl_backlog_histlen:5222
七、Redis 集群
Redis 高可用在负载均衡的同时兼顾了高可用的特性,所以是企业中常用的一种架构,集群架构至少要三台 master 服务器,本文采用了三主三从的架构。
1、主机规划
注:实际运维工作中,大概需要3台机器,每台机器2个节点。但需详细规划主从关系,尽量不要把一组主从放在同一台服务器中。
IP | 端口 | 角色 | 配置文件 |
192.168.1.6 | 7001 | Master | redis_7001.conf |
7002 | Slave | redis_7002.conf | |
192.168.1.7 | 7003 | Master | redis_7003.conf |
7004 | Slave | redis_7004.conf | |
192.168.1.8 | 7005 | Master | redis_7005.conf |
7006 | Slave | redis_7006.conf |
2、环境初始化
- 2.1 最大可打开文件数
vi /etc/security/limits.conf
追加如下内容
* soft nofile 65535
* hard nofile 65535
- 2.2 TCP监听队列
echo 'net.core.somaxconn = 32767' >> /etc/sysctl.conf
立即生效
sysctl -w net.core.somaxconn=32767
- 2.3 关闭防火墙
systemctl stop firewalld.service && systemctl disable firewalld.service
3、编译安装
yum install -y wget gcc vim && \
wget https://download.redis.io/releases/redis-5.0.14.tar.gz && \
tar -zxvf redis-5.0.14.tar.gz && \
cd redis-5.0.14 && \
make PREFIX=/opt/redis install && \
mkdir /opt/redis/{logs,conf,data} && \
echo 'PATH=$PATH:/opt/redis/bin' >> ~/.bashrc && \
source ~/.bashrc
生成配置文件,通过修改 PORT 值,生成不同的配置文件
export PORT=7001
cat > /opt/redis/conf/redis_$PORT.conf << EOF
# redis 端口
port $PORT
# 启用集群模式
cluster-enabled yes
# 集群配置文件
cluster-config-file /opt/redis/conf/cluster_nodes_$PORT.conf
# 集群中的节点最大不可用时长
cluster-node-timeout 5000
# 数据目录
dir /opt/redis/data/
# 数据文件名
dbfilename dump_$PORT.rdb
# 指定是否在每次更新操作后进行日志记录
appendonly yes
# 指定更新日志文件名
appendfilename appendonly_$PORT.aof
# 日志文件路径
logfile /opt/redis/logs/redis_$PORT.log
# pid 文件路径
pidfile /opt/redis/redis_$PORT.pid
# 后台运行
daemonize yes
# 非保护模式
protected-mode no
EOF
4、启动 redis-server 服务
# 依次将六个全部启动
/opt/redis/bin/redis-server /opt/redis/conf/redis_7001.conf
5、启动 redis 集群
该命令一台主机设置即可,主机按照三主、三从的顺序
redis-cli \
--cluster create \
192.168.1.6:7001 192.168.1.7:7003 192.168.1.8:7005 \
192.168.1.6:7002 192.168.1.7:7004 192.168.1.8:7006 \
--cluster-replicas 1
Redis 会自动交叉主机绑定主从关系(输入 yes
确认)防止一组主从在同一台主机上
>>> 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.1.7:7004 to 192.168.1.6:7001
Adding replica 192.168.1.8:7006 to 192.168.1.7:7003
Adding replica 192.168.1.6:7002 to 192.168.1.8:7005
M: e3bfb1bb0f86db12a7585f1321b1e4e6d647a14d 192.168.1.6:7001
slots:[0-5460] (5461 slots) master
M: 38d64c4cc0497b93eca30ecd6de027b9460df4dd 192.168.1.7:7003
slots:[5461-10922] (5462 slots) master
M: 2076ca0bb1ac06179a099ca9ff772e7da0fc01df 192.168.1.8:7005
slots:[10923-16383] (5461 slots) master
S: a503b676025bbecb2847283f5a7c7c47cc8d1cdd 192.168.1.6:7002
replicates 2076ca0bb1ac06179a099ca9ff772e7da0fc01df
S: de199f4d804c665a9e71b306ce408d88f93983e9 192.168.1.7:7004
replicates e3bfb1bb0f86db12a7585f1321b1e4e6d647a14d
S: 3b041b0ba18393d36596d94e701e35817b5a1dda 192.168.1.8:7006
replicates 38d64c4cc0497b93eca30ecd6de027b9460df4dd
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.1.6:7001)
M: e3bfb1bb0f86db12a7585f1321b1e4e6d647a14d 192.168.1.6:7001
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: 38d64c4cc0497b93eca30ecd6de027b9460df4dd 192.168.1.7:7003
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: de199f4d804c665a9e71b306ce408d88f93983e9 192.168.1.7:7004
slots: (0 slots) slave
replicates e3bfb1bb0f86db12a7585f1321b1e4e6d647a14d
S: 3b041b0ba18393d36596d94e701e35817b5a1dda 192.168.1.8:7006
slots: (0 slots) slave
replicates 38d64c4cc0497b93eca30ecd6de027b9460df4dd
M: 2076ca0bb1ac06179a099ca9ff772e7da0fc01df 192.168.1.8:7005
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: a503b676025bbecb2847283f5a7c7c47cc8d1cdd 192.168.1.6:7002
slots: (0 slots) slave
replicates 2076ca0bb1ac06179a099ca9ff772e7da0fc01df
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
6、测试集群
# 随意连接一个 redis 节点,设置一个 key,发现 redis 将该 key 值存放到 192.168.1.7 主机上
[root@localhost ~]# redis-cli -c -h 192.168.1.6 -p 7001
192.168.1.6:7001> set name liuli
-> Redirected to slot [5798] located at 192.168.1.7:7003
OK
关闭 192.168.1.7
主机模拟故障
# 发先 key 已经漂移到 192.168.1.8 主机上了
[root@localhost ~]# redis-cli -c -h 192.168.1.8 -p 7005
192.168.1.8:7005> get name
-> Redirected to slot [5798] located at 192.168.1.8:7006
"liuli"
八、安全设置
1、设置密码
修改 redis.conf 文件
# 设置密码为 passwd123
requirepass passwd123
重启 redis 后登录,使用 auth
密码登录
127.0.0.1:6379> KEYS *
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth passwd123
OK
127.0.0.1:6379> KEYS *
1) "id"
注意:如果开启了密码限制,搭建主从需要在 slave 配置
masterauth <master-password>
选项中填写 master 的密码
2、限制 IP 访问
修改 redis.conf 文件,打开配置 IP 限制
bind 127.0.0.1 (允许访问服务器的IP)
重启 redis 服务,生效