redis是一种NoSQL数据库,基于键-值型存储。【全称remote dictionary server,远程字典服务器】 主要提供键-值和数据结构的远程存储功能。
官网地址:https://redis.io/download
数据结构:列表、字典、hash表等。 数据类型:string(字符串,包含整数)、list(列表)、hash(关联数组)、sets(集合)、sorted sets(有序集合)、bitmaps(位图)、hyperloglog。
Redis 性能评估
100 万较小的键存储字符串,大概消耗100M内存。
由于Redis是单线程,如果服务器主机上有多个 CPU,只有一个能够使用,但并不意味着 CPU 会成为瓶颈,因为 Redis 是一个比较简单的 K-V 数据存储,CPU通常不会成为瓶颈的。
在常见的 linux 服务器上,500K(50 万)的并发,只需要一秒钟处理,如果主机硬件较好的情况下,每秒钟可以达到上百万的并发。
读的速度是110000次/s,写的速度是81000次/s
Redis 与 Memcache 对比
Memcache 只能使用内存来缓存对象,若要持久化,需要第三方插件的支持。而 Redis 除了可以使用内存来缓存对像,还可以周期性的将数据保存到磁盘上,对数据进行永久存储。当服务器突然断电或死机后, redis 基于磁盘中的数据进行恢复。
Redis是单线程服务器,只有一个线程来响应所有的请求。Memcache 是多线程的。
Redis 支持更多的数据类型。
下载地址:https://github.com/microsoftarchive/redis/releases
redis3.0.504版本: https://github.com/microsoftarchive/redis/releases/download/win-3.0.504/Redis-x64-3.0.504.zip
双击redis-server即可启动,关闭小黑窗即关闭redis。
使用客户端登录redis,关闭小黑窗就关闭了redis客户端。
redis中文社区:http://www.redis.cn/download.html 这里有安装教程,可以参考下。 安装的是redis-6.0.6版本。
# redis官网下载最新版的redis源码包,并上传到linux服务器。 [root@master local]# cd /usr/local/ [root@master local]# rz [root@master local]# ll redis-6.0.6.tar.gz -rw-r--r-- 1 root root 2228781 8月 29 11:37 redis-6.0.6.tar.gz [root@master local]# tar xzf redis-6.0.6.tar.gz [root@master local]# mv redis-6.0.6 redis [root@master local]# cd redis/ # 源码编译reids,需要gcc版本5以上,我这里升级到9.3.1了。 [root@master redis]# scl enable devtoolset-9 bash # 再次make特别顺利,舒服!!! [root@master redis]# make Hint: It's a good idea to run 'make test' ;) make[1]: 离开目录“/usr/local/redis/src” # 查看redis服务端和客户端版本 [root@master redis]# /usr/local/redis/src/redis-server --version Redis server v=6.0.6 sha=00000000:0 malloc=jemalloc-5.1.0 bits=64 build=39d0c792f232dbb6 [root@master redis]# /usr/local/redis/src/redis-cli --version redis-cli 6.0.6 # redis服务启动后,是一个前台进程,在启动的时候就把该进程放到后台进行。 [root@master ~]# /usr/local/redis/src/redis-server & [root@master ~]# jobs [1]+ 运行中 /usr/local/redis/src/redis-server & # 查看redis占用端口号,默认监听6379端口号 [root@master ~]# ps aux | grep redis root 13500 0.4 0.2 162264 8172 pts/0 Sl 09:19 0:00 /usr/local/redis/src/redis-server *:6379 root 13524 0.0 0.0 112728 992 pts/0 S+ 09:20 0:00 grep --color=auto redis # 设置开机自启 [root@master ~]# mkdir /etc/redis [root@master ~]# cp /usr/local/redis/redis.conf /etc/redis/ [root@master ~]# vim /lib/systemd/system/redis.service [Unit] Description=redis-server After=network.target [Service] Type=forking ExecStart=/usr/local/redis/src/redis-server /etc/redis/redis.conf PrivateTmp=true [Install] WantedBy=graphical.target ============================================================================ Description:描述服务 After:描述服务类别 [Service]服务运行参数的设置 Type=forking是后台运行的形式 ExecStart为服务的具体运行命令 ExecReload为重启命令 ExecStop为停止命令 PrivateTmp=True表示给服务分配独立的临时空间 注意:[Service]的启动、重启、停止命令全部要求使用绝对路径 [Install]运行级别下服务安装的相关设置,可设置为多用户,即系统运行级别为3 multi-user.target 多用户模式,字符界面,系统运行级别3 graphical.target 图形界面模式,系统运行级别5 =============================================================================测试启动:
# 停止redis服务 [root@master ~]# systemctl stop redis.service # 后台启动redis服务 # 这里没有使用systemctl start redis.service启动,是因为redis服务默认是前台启动,无法使用该命令启动redis,要修改配置文件使得redis后台启动才可以使用该命令。2.1后面会有介绍 [root@master ~]# /usr/local/redis/src/redis-server & # 设置开机自启,graphical.target.wants图形化界面开机自启 [root@master ~]# systemctl enable redis Created symlink from /etc/systemd/system/graphical.target.wants/redis.service to /usr/lib/systemd/system/redis.service. # 关机,重新开机 [root@master ~]# shutdown -r now # 可以看到redis仍然启动着。 [root@master ~]# netstat -antup | grep redis tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 9309/redis-server 1redis的功能之一是存储K-V键值数据,故对键的命名设定了一些规则: ①可以使用ASCII码 ②键的长度越长,消耗的空间越多。 ③同库(名字空间),键的名字不可重复。复制键的名字,即修改键中的值。 ④异库,键的名字可以重复。 ⑤键可以实现自动过期。
[root@master ~]# redis-cli 127.0.0.1:6379> set system centos OK 127.0.0.1:6379> get system "centos" 127.0.0.1:6379> set name abong EX 60 OK 127.0.0.1:6379> get name "abong" 127.0.0.1:6379> get name (nil) 127.0.0.1:6379> 有效期: EX 单位秒 PX 单位毫秒redis工作时所有数据都是存储在内存中的,当redis崩溃或者断电时所有数据都会丢失。故redis提供了持久化功能来保证数据的可靠性。redis持久化的实现方式有两种:RDB和AOF。
RDB:存储为二进制格式的数据文件,redis默认的持久化机制。按事先定制的策略,周期性的将数据保存到磁盘。【保存数据本身】
AOF:Append Only File类似mysql二进制日志,记录每一次redis的写操作命令,以顺序IO方式附加在文件的尾部,使用追加方式实现,即附加日志类型的持久化机制。由于记录每一次写操作,则会随着时间长而增大文件的容量,并且有些记录的命令是多余的。但是AOF进程能够自动的去扫描AOF文件,把冗余的日志操作合并成一个,以实现将来一次性数据恢复。【记录写操作日志】
[root@master ~]# vim /etc/redis/redis.conf 321 stop-writes-on-bgsave-error yes # 备份数据时发生错误是否停止 327 rdbcompression yes # 是否压缩存储 336 rdbchecksum yes # 是否对rdb文件做校验码检测。在redis生成rdb文件时会生成校验码,当redis重启或重载时rdb文件时,会对rdb文件进行校验,导致redis启动较慢,但可以判断rdb文件是否报错。 339 dbfilename dump.rdb # rdb文件名 362 dir /var/lib/redis # 定义rdb文件存放路径 [root@master ~]# mkdir /var/lib/redis [root@master ~]# systemctl restart redis # 使用redis客户端执行set操作,然后重启服务器,看是否会生成rdb文件。可以看到是有的。 [root@master ~]# ll /var/lib/redis/dump.rdb -rw-r--r-- 1 root root 139 8月 30 19:51 /var/lib/redis/dump.rdbRedis 的主从复制是自动进行的,并不需要用户的介入,slave 端会自动连接 master 并进行数据同步。如果同步连接时 slave 端短暂的与 master 端断开了连接,那连接恢复后 slave 端会与 master 端再进行一次同步。从而保证数据一致。
redis主从同步原理图:
部署主从redis服务器,按照上面的步骤重新做一台。我这里直接克隆一台,配置如下: master redis:192.168.8.188 slave redis:192.168.8.189
# 开放master端的6379端口 [root@master ~]# firewall-cmd --permanent --zone=public --add-port=6379/tcp success [root@master ~]# firewall-cmd --reload success # slave端配置master端信息,可根据配置向master端发送ping命令 [root@slave ~]# vim /etc/redis/redis.conf 385 replicaof 192.168.8.188 6379 392 masterauth 123456 [root@slave ~]# systemctl restart redis.service [root@slave ~]# redis-cli 127.0.0.1:6379> auth 123456 OK 127.0.0.1:6379> info replication # Replication role:slave # 从redis master_host:192.168.8.188 master_port:6379 master_link_status:up # up表示主从同步已经连接上,down为未连接。 master_last_io_seconds_ago:6 master_sync_in_progress:0 slave_repl_offset:56 slave_priority:100 slave_read_only:1 # slave端只读,1为只读 connected_slaves:0 master_replid:c543ffa1cb0fd6a21f2ac2b73564f6e9e0ba6d36 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:56 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:56 127.0.0.1:6379> exit # master端查看slave端信息 [root@master ~]# redis-cli 127.0.0.1:6379> auth 123456 OK 127.0.0.1:6379> info replication # Replication role:master # 主redis connected_slaves:1 # 有1个从redis正在连接 slave0:ip=192.168.8.189,port=6379,state=online,offset=252,lag=0 # 从redis信息 master_replid:c543ffa1cb0fd6a21f2ac2b73564f6e9e0ba6d36 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:252 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:252 # 测试redis主从复制 [root@master ~]# redis-cli 127.0.0.1:6379> auth 123456 OK 127.0.0.1:6379> set name haha # 创建一个键name,值为haha OK [root@slave ~]# redis-cli 127.0.0.1:6379> auth 123456 OK 127.0.0.1:6379> get name # 可以看到已经复制过来 "haha" 127.0.0.1:6379> exit适用场景:公司的redis主从架构中,如果master端离线,那么所有写操作将无法执行。为了避免此情况发生,redis引入了sentinel(哨兵)机制,当master端挂了,slave端主动变为master端。
sentinel工作原理:sentinel是redis官方提供的一种高可用方案,可以自动监控redis master/slave的运行状态。
①master端宕机,sentinel实例无法访问master端。 ②多个sentinel实例投票选举某个sentinel启动failover。 ③自动更新sentinel实例和slave端配置文件,升级slave端为master端。 ④发送master切换事件(pub/sub事件)消息给jedis client ⑤当jedis client监听到该消息,会将master ip切换到新的master ip继续访问。 这些操作对于调用redis客户端的业务系统而言,是完全透明的。
主观下线:SDOWN,指当前sentinel实例对某个redis服务器做出下线判断。 客观下线:多个sentinel实例对master端做出SDOWN判断,并且通过sentinel的is-master-down-by-addr命令相互交流,得出master端的下线判断,然后开启failover。
主机环境: master redis:192.168.8.192 slave1 redis:192.168.8.188 slave2 redis:192.168.8.193
三台主机都是刚配置好redis,未曾修改过配置文件。如果不是新的redis,哨兵可能无法生效。
# 配置master端 [root@master ~]# vim /etc/redis/redis.conf 69 bind 0.0.0.0 88 protected-mode no 222 daemonize yes [root@master ~]# systemctl restart redis.service # 配置slave1为master端的从服务器 [root@slave1 ~]# vim /etc/redis/redis.conf 69 bind 0.0.0.0 88 protected-mode no 222 daemonize yes 386 replicaof 192.168.8.192 6379 [root@slave1 ~]# systemctl restart redis.service # 配置slave2为master端的从服务器 [root@slave2 ~]# vim /etc/redis/redis.conf 69 bind 0.0.0.0 88 protected-mode no 222 daemonize yes 386 replicaof 192.168.8.192 6379 [root@slave2 ~]# systemctl restart redis.service # 如果无法使用redis-cli命令,要添加环境变量。三台redis主机都要做这个操作。 [root@master ~]# vim /etc/profile.d/redis.sh export PATH=/usr/local/redis/src:$PATH [root@master ~]# chmod +x /etc/profile.d/redis.sh [root@master ~]# source /etc/profile.d/redis.sh # 开放3台redis服务器的6379端口号 [root@master ~]# firewall-cmd --permanent --zone=public --add-port=6379/tcp success [root@master ~]# firewall-cmd --reload success # 登录master、slave1、slave2查看主从复制状态 # 可以看到master_replid都是一样的。 [root@master ~]# redis-cli 127.0.0.1:6379> info replication # Replication role:master # 主redis connected_slaves:2 # 2个有效的从redis连接 slave0:ip=192.168.8.188,port=6379,state=online,offset=210,lag=0 slave1:ip=192.168.8.193,port=6379,state=online,offset=210,lag=0 master_replid:967efa57f35f1272f3caa4d1a41e3d1041ae7547 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:210 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:210 [root@slave1 ~]# redis-cli 127.0.0.1:6379> info replication # Replication role:slave # 从redis master_host:192.168.8.192 master_port:6379 master_link_status:up master_last_io_seconds_ago:10 master_sync_in_progress:0 slave_repl_offset:280 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:967efa57f35f1272f3caa4d1a41e3d1041ae7547 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:280 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:280 [root@slave2 ~]# redis-cli 127.0.0.1:6379> info replication # Replication role:slave # 从redis master_host:192.168.8.192 master_port:6379 master_link_status:up master_last_io_seconds_ago:1 master_sync_in_progress:0 slave_repl_offset:210 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:967efa57f35f1272f3caa4d1a41e3d1041ae7547 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:210 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:183 repl_backlog_histlen:28 # 配置master上的sentinel实例 [root@master ~]# vim /usr/local/redis/sentinel.conf 17 protected-mode no # 开启保护模式,不允许外网访问 21 port 26379 # sentinel实例监听端口26379 26 daemonize yes # 后台运行 84 sentinel monitor mymaster 192.168.8.192 6379 2 # 设置主master的IP地址和端口号,最后的2指2票通过master离线,此时有3个sentinel实例。 125 sentinel down-after-milliseconds mymaster 10000 # ping master端,10s不回复pong或者回复错误则表示master端已经挂了。 141 sentinel parallel-syncs mymaster 1 # 同一时间允许多少台slave端复制新的master端。数字1表示一台一台复制,复制时间较长。数字越大,表示同一时间不可用slave端越多,但复制时间较短。 166 sentinel failover-timeout mymaster 60000 # 若第二个sentinel推荐第一个sentinel去实行failover,当第一个进行failover的sentinel失败后,在60s后第二个sentinel将再次进行failover。 # 把配置好的sentinel文件发送到从redis上 [root@master ~]# scp /usr/local/redis/sentinel.conf root@192.168.8.188:/usr/local/redis/ [root@master ~]# scp /usr/local/redis/sentinel.conf root@192.168.8.193:/usr/local/redis/ # 开放3台redis服务器的26379端口,之前已经开放了6379端口号了。 [root@master ~]# firewall-cmd --permanent --zone=public --add-port=26379/tcp success [root@master ~]# firewall-cmd --reload success # 开启所有的sentinel实例 # redis-sentinel 配置文件 [root@master ~]# redis-sentinel /usr/local/redis/sentinel.conf [root@slave1 ~]# redis-sentinel /usr/local/redis/sentinel.conf [root@slave2 ~]# redis-sentinel /usr/local/redis/sentinel.conf 如果未运行sentinel实例,会出现以下报错: [root@master ~]# redis-cli -p 26379 Could not connect to Redis at 127.0.0.1:26379: Connection refused # 重启所有的redis服务器 [root@master ~]# systemctl restart redis.service [root@slave1 ~]# systemctl restart redis.service [root@slave2 ~]# systemctl restart redis.service模拟故障:
# 可以看到此时的主redis是192.168.8.188,并且主从复制是连接上的。 [root@master ~]# clear [root@master ~]# redis-cli -h 192.168.8.188 192.168.8.188:6379> info replication # Replication role:slave master_host:192.168.8.192 # 主redis master_port:6379 master_link_status:up master_last_io_seconds_ago:0 master_sync_in_progress:0 slave_repl_offset:11796 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:f16b51ffa2b61206d18ce96b349266447f6683d6 # master_replid 第一台主redis的ID master_replid2:0000000000000000000000000000000000000000 master_repl_offset:11796 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:3422 repl_backlog_histlen:8375 # 停止主redis服务 [root@master ~]# systemctl stop redis.service # 再次查看主redis 192.168.8.188:6379> info replication # Replication role:slave master_host:192.168.8.193 # 原来的主redis停止后,从redis升级为新的主redis master_port:6379 master_link_status:up master_last_io_seconds_ago:0 master_sync_in_progress:0 slave_repl_offset:22887 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:8b0b8cf49fd0454ace7f2b13b53aa5e3ceede6a0 master_replid2:f16b51ffa2b61206d18ce96b349266447f6683d6 # 第一台主redis的ID放到了master_replid2,新生成了一个master_replid。 master_repl_offset:22887 second_repl_offset:21314 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:3422 repl_backlog_histlen:19466 # 重新启动原来的主redis [root@master ~]# systemctl start redis.service # 主redis并没有迁移回来。这是正常的。 192.168.8.188:6379> info replication # Replication role:slave master_host:192.168.8.193 master_port:6379 master_link_status:up master_last_io_seconds_ago:0 master_sync_in_progress:0 slave_repl_offset:81535 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:8b0b8cf49fd0454ace7f2b13b53aa5e3ceede6a0 master_replid2:f16b51ffa2b61206d18ce96b349266447f6683d6 master_repl_offset:81535 second_repl_offset:21314 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:3422 repl_backlog_histlen:78114 # 查看下sentinel的信息,可以sentinel正在监听193这台主机。2个slave,3个sentinel。 [root@master ~]# redis-cli -p 26379 127.0.0.1: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.8.193:6379,slaves=2,sentinels=3