YAZONG 我的开源

总结redis第三部分(安全性、主从、哨兵、事物、持久化、发布与订阅、虚拟内存)

  ,
0 评论0 浏览

八、redis的安全性

因为redis速度相当快,所以在一台比较好的服务器下,一个外部用户在一秒内可以进行15W次的密码尝试,这意味着需要设定非常强大的密码来防止暴力破解。

可以通过设置密码以及登录redis方式来操作

九、redis主从复制

9、1简介

1、Master可以拥有多个slave。

2、多个slave可以连接同一个master外,还可以连接到其他的slave。

3、主从复制不会阻塞master,在同步数据时,master可以继续处理client请求。

4、提供系统的伸缩性。

9、2主从复制过程

1、slave与master建立连接,发送sync同步命令。

2、master会开启一个后台进程,将数据库快照保存到文件中,同时master主进程会开始收集新的写命令并缓存。

3、master后台完成保存后,就把文件发送给slave。

4、slave将接收到的master文件保存到磁盘上。

9、3主从复制配置

#现在使用同一台机器的不同配置模拟主从复制场景。
root@redis conf]# pwd 
/application/redis/conf
[root@redis conf]# ls
appendonly.aof dump.rdb  redis.conf
[root@redis conf]# cd ..
[root@redis redis]# cp -a conf conf-slave
#下述为从节点
[root@redis redis]# cd conf-slave/
[root@redis conf-slave]# ls
appendonly.aof dump.rdb  redis.conf
 
#设置从节点端口
port 6380
#设置从节点中的文件名和路径配置为XX-slave的形式
logfile /application/redis/logs/redis-slave.log
dir /application/redis/conf-slave/
 
#配置主节点的IP和端口  slaveof 10.0.0.11 6379
#配置主节点的密码(redis4.0主节点的redis.conf也要配置)   masterauth redis
 
#设置防火墙关闭状态
[root@redis conf-slave]# /etc/init.d/iptables stop
[root@redis conf-slave]# /etc/init.d/iptables status
iptables: Firewall is not running.
 
#可使用info查看role角色,即可知道是主服务或从服务。

9、4分别启动redis主从节点测试

#主节点
[root@redis ~]# redis-server/application/redis/conf/redis.conf
[root@redis ~]# lsof -i:6379
COMMAND    PIDUSER   FD   TYPE DEVICE SIZE/OFF NODE NAME
redis-ser 2456 root   4u  IPv6  16205     0t0  TCP *:6379 (LISTEN)
redis-ser 2456 root   5u  IPv4  16207     0t0  TCP *:6379 (LISTEN)
[root@redis ~]# cd /application/redis/logs/
[root@redis logs]# ll
total 1780
-rw-r--r-- 1 root root 1751493 Dec  8 02:09 redis.log
-rw-r--r-- 1 root root  59765 Dec  8 02:09 redis-slave.log
[root@redis logs]# tailf redis.log 
2456:M 08 Dec 02:08:46.338 - Accepted 10.0.0.11:17586
2456:M 08 Dec 02:08:47.345 - Accepted 10.0.0.11:17587
2456:M 08 Dec 02:08:48.352 - Accepted 10.0.0.11:17588
2456:M 08 Dec 02:08:49.076 - 0 clients connected (0slaves), 758544 bytes in use
 
#从节点
[root@redis ~]# redis-server/application/redis/conf-slave/redis.conf 
[root@redis ~]# lsof -i:6380
COMMAND    PIDUSER   FD   TYPE DEVICE SIZE/OFF NODE NAME
redis-ser 2460 root   4u  IPv6  16216     0t0  TCP *:6380 (LISTEN)
redis-ser 2460 root   5u  IPv4  16218     0t0  TCP *:6380 (LISTEN)
[root@redis ~]# cd /application/redis/logs/
[root@redis logs]# ll
total 1724
-rw-r--r-- 1 root root 1741206 Dec  8 02:06 redis.log
-rw-r--r-- 1 root root  15808 Dec  8 02:06 redis-slave.log
 
#从节点日志如果出现下述情况的话,那么需要把redis.conf文件中的bind 127.0.0.1注释掉。这种情况在多台机器中会出现,现在单台机器模拟是不会出现的,因为redis采用的安全策略是默认只允许本地访问,所以现在在同一台机器中测试就不用注释掉,redis.conf的具体参数参考“4、3、4redis.conf文件配置说明”。
[root@redis logs]# tailf redis-slave.log 
2460:S 08 Dec 02:09:49.164 # Error condition on socketfor SYNC: Broken pipe
2460:S 08 Dec 02:09:50.168 - 0 clients connected (0slaves), 758544 bytes in use
2460:S 08 Dec 02:09:50.180 * Connecting to MASTER10.0.0.11:6379
2460:S 08 Dec 02:09:50.181 * MASTER <-> SLAVE syncstarted
2460:S 08 Dec 02:09:50.181 * Non blocking connect forSYNC fired the event.
#可以发现从节点没有连接成功,那么需要设置从节点对应的redis.conf文件的bind值。
[root@redis conf-slave]# lsof -i:6380
COMMAND    PIDUSER   FD   TYPE DEVICE SIZE/OFF NODE NAME
redis-ser 2460 root   4u  IPv6  16216     0t0  TCP *:6380 (LISTEN)
redis-ser 2460 root   5u  IPv4  16218     0t0  TCP *:6380 (LISTEN)
[root@redis conf-slave]# redis-cli -a shutdown -p 6380shutdown
[root@redis conf-slave]# lsof -i:6380
[root@redis conf-slave]# pwd
/application/redis/conf-slave
bind 127.0.0.1
 
 
#主节点设置值
[root@redis ~]# redis-cli -a redis -p 6379
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set name nameval
OK
127.0.0.1:6379> get name
"nameval"
[root@redis logs]# pwd
/application/redis/logs
[root@redis logs]# tailf redis.log
2506:M 08 Dec 02:21:33.242 - Accepted 127.0.0.1:36324
2506:M 08 Dec 02:21:33.584 - 1 clients connected (1slaves), 1848864 bytes in use
2506:M 08 Dec 02:21:38.616 - DB 0: 1 keys (0 volatile) in4 slots HT.
127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> keys *
1) "name2"
 
 
#从节点获取值
[root@redis ~]# redis-cli -a redis -p 6380 
127.0.0.1:6380> keys *
(empty list or set)
127.0.0.1:6380> keys *
1) "name"
127.0.0.1:6380> get name
"nameval"
2512:S 08 Dec 02:19:28.089 * Background AOF rewritefinished successfully
2512:S 08 Dec 02:19:28.089 - Background AOF rewritesignal handler took 236us
2512:S 08 Dec 02:19:32.915 - 1 clients connected (0slaves), 779440 bytes in use
2512:S 08 Dec 02:21:38.716 - DB 0: 1 keys (0 volatile) in4 slots HT.
2512:S 08 Dec 02:21:38.717 - 2 clients connected (0slaves), 800536 bytes in use

**#**注意从节点是没有写操作的,只有读操作

127.0.0.1:6380> del name
(error) READONLY You can't write against a read onlyslave.
127.0.0.1:6380> keys *
1) "name2"
 
#通过监控查看
#主节点做监控
[root@redis logs]# redis-cli -a redis -p 6379 monitor
OK
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> keys *
(empty list or set)
[root@redis logs]# redis-cli -a redis -p 6379 monitor
OK
1481135598.941742 [0 127.0.0.1:36324]"flushall"
1481135634.460910 [0 127.0.0.1:36324]"keys""*"
127.0.0.1:6379> set name nameval
OK
127.0.0.1:6379> get name
"nameval"
[root@redis logs]# redis-cli -a redis -p 6379 monitor
OK
1481135697.418957 [0 127.0.0.1:36324]"set""name""nameval"
1481135698.642795 [0 127.0.0.1:36324]"get""name"
 
#从节点做监控
[root@redis conf-slave]# redis-cli -a redis -p 6380monitor
OK
127.0.0.1:6380> keys *
(empty list or set)
[root@redis conf-slave]# redis-cli -a redis -p 6380monitor
OK
1481135598.306657 [0 10.0.0.11:6379] "PING"
1481135598.947041 [0 10.0.0.11:6379] "flushall"
1481135608.370998 [0 10.0.0.11:6379] "PING"
1481135618.428639 [0 10.0.0.11:6379] "PING"
1481135628.493744 [0 10.0.0.11:6379] "PING"
1481135638.562807 [0 10.0.0.11:6379] "PING"
1481135648.730527 [0 10.0.0.11:6379] "PING"
1481135658.800544 [0 10.0.0.11:6379] "PING"
1481135663.809136 [0 127.0.0.1:62476]"keys""*"
1481135668.860633 [0 10.0.0.11:6379] "PING"
[root@redis conf-slave]# redis-cli -a redis -p 6380monitor
OK
1481135688.972458 [0 10.0.0.11:6379] "PING"
1481135697.422176 [0 10.0.0.11:6379]"set""name""nameval"
1481135699.036100 [0 10.0.0.11:6379] "PING"
127.0.0.1:6380> keys *
1) "name"
127.0.0.1:6380> get name
"nameval"
[root@redis conf-slave]# redis-cli -a redis -p 6380monitor
OK
1481135747.385987 [0 127.0.0.1:62476]"keys""*"
1481135749.378369 [0 10.0.0.11:6379] "PING"
1481135750.203089 [0 127.0.0.1:62476]"get""name"
1481135759.444582 [0 10.0.0.11:6379] "PING"

9、5查看主从节点信息

#主节点
127.0.0.1:6379> info Replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=2256,lag=0
master_repl_offset:2256
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:2255
 
# Replication是通过info查看节点信息中的一部分
 
#从节点
127.0.0.1:6380> info Replication
# Replication
role:slave
master_host:10.0.0.11
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:2326
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

十、哨兵模式

10、1简介

有了主从复制以后,如果想对主从复制服务器进行监控,那么在redis2.6以后提供了一个“哨兵”的机制,在2.6版本中的哨兵为1.0版本并不稳定,会出现各种各种的问题,在redis2.8版本以后的哨兵功能才稳定起来。

顾名思义,哨兵的含义就是监控redis系统的运行状况,其功能主要有两点:

监控主数据库和从数据库是否正常运行。

2、主数据库出现故障时,可以自动将从数据库转换为主数据库,实现自动切换。

一个节点可以被多个哨兵去监控。哨兵跟所有redis节点是没有直接关系的,哨兵只是一个监控程序而已。

(可以使用keepalived(配合nginx使用)代替哨兵,实现高可用。)

10、2操作步骤

#(只配主节点即可)

**#**配置sentinel.conf

[root@redis redis-3.2.5]# pwd
/home/lly/tools/redis-3.2.5
#拷贝到从节点目录下
[root@redis redis-3.2.5]# cp sentinel.conf/application/redis/conf-slave/
[root@redis redis-3.2.5]# cp /application/redis/conf-slave/sentinel.conf/application/redis/conf-slave/sentinel.conf.ori
[root@redis redis-3.2.5]# vim/application/redis/conf-slave/sentinel.conf
sentinel monitor mymaster 127.0.0.1 6379 1  #名称,IP,端口,投票选举次数建议为1,多台机器记得设置master的内网IP(内部系统交互用内网IP,外部访问提供外网IP)。
sentinel down-after-milliseconds mymaster 5000  #设置5000毫秒检测一次,默认1秒
sentinel failover-timeout mymaster 900000
sentinel parallel-syncs mymaster 2
sentinel auth-pass mymaster redis       #主节点密码(节点redis.conf中未配置密码,那么此步省略)

**#**测试第一步

#启动哨兵模式,注意下面的命令中不要加-a redis –p 6380
[root@redis conf-slave]# redis-server sentinel.conf--sentinel &
 
[root@redis ~]# lsof -i:26379
COMMAND    PIDUSER   FD   TYPE DEVICE SIZE/OFF NODE NAME
redis-ser 2650 root   4u  IPv6  19430     0t0  TCP *:26379 (LISTEN)
redis-ser 2650 root   5u  IPv4  19432     0t0  TCP *:26379 (LISTEN)
 
#查看哨兵相关信息
[root@redis ~]# redis-cli -p 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=127.0.0.1:6379,slaves=1,sentinels=1
 
#主节点日志
[root@redis ~]# tailf /application/redis/logs/redis.log
1481137928.553897 [0 127.0.0.1:36329] "PING"
1481137929.589836 [0 127.0.0.1:36329] "PING"
1481137929.763963 [0 127.0.0.1:36329]"PUBLISH""__sentinel__:hello""127.0.0.1,26379,a14563baa663afc1c2e06ee3cb07f222c220fd7b,0,mymaster,127.0.0.1,6379,0"

**#**测试第二步

#关闭主节点
[root@redis ~]# redis-cli -a redis -p 6379 shutdown
#从节点日志
[root@redis conf-slave]# tailf/application/redis/logs/redis-slave.log
2574:S 08 Dec 03:15:16.629 * MASTER <-> SLAVE syncstarted
2574:S 08 Dec 03:15:16.629 # Error condition on socketfor SYNC: Connection refused
2574:M 08 Dec 03:15:17.016 * Discarding previously cachedmaster state.
2574:M 08 Dec 03:15:17.016 * MASTER MODE enabled (userrequest from 'id=5 addr=127.0.0.1:62481 fd=7 name=sentinel-a14563ba-cmd age=320idle=0 flags=x db=0 sub=0 psub=0 multi=3 qbuf=0 qbuf-free=32768 obl=36 oll=0omem=0 events=r cmd=exec')
2574:M 08 Dec 03:15:17.020 # CONFIG REWRITE executed withsuccess.
2574:M 08 Dec 03:15:17.048 * 1 changes in 900 seconds.Saving...
2574:M 08 Dec 03:15:17.050 * Background saving started bypid 2712
2712:C 08 Dec 03:15:17.067 * DB saved on disk
2712:C 08 Dec 03:15:17.068 * RDB: 6 MB of memory used bycopy-on-write
2574:M 08 Dec 03:15:17.150 * Background saving terminatedwith success
2574:M 08 Dec 03:15:17.980 - Client closed connection
2574:M 08 Dec 03:15:17.981 - Client closed connection
2574:M 08 Dec 03:15:18.069 - Accepted 127.0.0.1:62499
2574:M 08 Dec 03:15:18.070 - Accepted 127.0.0.1:62500
2574:M 08 Dec 03:15:20.671 - DB 0: 1 keys (0 volatile) in4 slots HT.
2574:M 08 Dec 03:15:20.672 - 2 clients connected (0slaves), 800816 bytes in use
2574:M 08 Dec 03:15:25.705 - DB 0: 1 keys (0 volatile) in4 slots HT.
2574:M 08 Dec 03:15:25.705 - 2 clients connected (0slaves), 800800 bytes in use
 
#查看此时的哨兵信息
[root@redis ~]# redis-cli -p 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=127.0.0.1:6380,slaves=1,sentinels=1
 
#原从节点info信息(现在是主节点)
127.0.0.1:6380> info Replication
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
 
#原主节点info信息(现在是从节点)
127.0.0.1:6379> info Replication
Could not connect to Redis at 127.0.0.1:6379: Connectionrefused
not connected>

**#**测试第三步

#启动原主节点(现在是从节点)
[root@redis ~]# redis-server/application/redis/conf/redis.conf
 
#查看哨兵切换日志,从节点切换到了原主节点6379
[root@redis conf-slave]# redis-server sentinel.conf--sentinel &
2650:X 08 Dec 03:15:17.980 #+failover-end master mymaster 127.0.0.1 6379
2650:X 08 Dec 03:15:17.980 #+switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
2650:X 08 Dec 03:15:17.981 *+slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
2650:X 08 Dec 03:18:07.759 *+convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
 
#原主节点日志(现在是从节点)
[root@redis ~]# tailf /application/redis/logs/redis.log
2574:M 08 Dec 03:18:08.674 * Background saving terminatedwith success
2574:M 08 Dec 03:18:08.679 * Synchronization with slave127.0.0.1:6379 succeeded
2574:M 08 Dec 03:18:11.903 - DB 0: 1 keys (0 volatile) in4 slots HT.
2574:M 08 Dec 03:18:11.903 - 3 clients connected (1slaves), 1891152 bytes in use
2574:M 08 Dec 03:18:16.932 - DB 0: 1 keys (0 volatile) in4 slots HT.
2574:M 08 Dec 03:18:16.932 - 3 clients connected (1slaves), 1891136 bytes in use
 
#原主节点info信息(现在是从节点)变成从节点信息
not connected> 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_repl_offset:2061
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
 
#原从节点info信息(现主节点),变成了主节点信息
127.0.0.1:6380> info Replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6379,state=online,offset=5736,lag=0
master_repl_offset:5736
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:5735

十一、事务

10、1redis简单事务一

首先是使用multi打开事务,然后进行设置,这时设置的数据都会放入队列里进行保存,最后使用exec执行,把数据依次存储到redis中,可以使用discard方法取消事务。

#multi
标记一个事务块的开始。随后的指令将在执行EXEC时作为一个原子执行。
返回值
simple-string-reply: 始终为OK
 
#exec
执行事务中所有在排队等待的指令并将链接状态恢复到正常当使用WATCH 时,只有当被监视的键没有被修改,且允许检查设定机制时,EXEC会被执行
返回值
multi-bulk-reply: 每个元素与原子事务中的指令一一对应当使用WATCH时,如果被终止,EXEC 则返回一个空的应答集合
 
#discard
刷新一个事务中所有在排队等待的指令,并且将连接状态恢复到正常。
如果已使用WATCH,DISCARD将释放所有被WATCH的key。
返回值
status-reply:所有返回都是 OK
 
#watch(锁定key,直到执行了multi/exec命令)
标记所有指定的key 被监视起来,在事务中有条件的执行(乐观锁)。
返回值
simple-string-reply: 总是 OK。
 
#unwatch(取消事务命令)
刷新一个事务中已被监视的所有key。
如果执行EXEC 或者DISCARD, 则不需要手动执行UNWATCH 。
返回值
simple-string-reply: 总是 OK。
 
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> get age
"11"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> exec
1) (integer) 12
127.0.0.1:6379> get age
"12"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get age
"12"
 
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> get age
"13"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> exec
1) (integer) 14
2) "14"
127.0.0.1:6379> unwatch
OK
127.0.0.1:6379> get age
"14"
 
127.0.0.1:6379> get age
"14"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> unwatch
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> exec
1) (integer) 15
2) OK
3) "15"
 
127.0.0.1:6379> watch age
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> unwatch
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get age
"15"

10、2redis简单事务二

Redis的事务不能保证同时成功或失败进行提交或回滚,所以redis的事务目前还是比较简单的(程序中一般是不会使用redis事务的)。

127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> get age
"15"
127.0.0.1:6379> set name nameval
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr age
QUEUED
#注意incr name并没报错,是在执行exec命令时报错,这个incr命令在java中调用是报错的。
127.0.0.1:6379> incr name
QUEUED
#下述虽然报错,但是事务已提交,name没有改变。如果下述执行discard命令中断事务的话,对所有的值都不会有影响。
127.0.0.1:6379> exec
1) (integer) 16
2) (error) ERR value is not an integer or out of range
127.0.0.1:6379> get age
"16"
127.0.0.1:6379> get name
"nameval"

十二、持久化机制

Redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到硬盘来保证持久化。Redis持久化的方式有以下两种。

12、1快照RDB文件方式

snapshotting(快照)默认方式,将内存中以快照的方式写入到二进制文件中,默认为dump.rdb,可以通过配置设置自动做快照持久化的方式,我们可以配置redis在N秒内如果超过M个key修改,那么就自动做快照。

快照设置:

save 900 1 #900秒内如果超过1个key被修改,则发起快照保存。下述同理。

save 300 10

save 60 10000

12、2AOF文件方式

append-only file(缩写aof)的方式(有点类似于oracle日志),由于快照方式是在一定时间间隔做一次,所以可能发生redis意外down的清苦康就会丢失最后一次快照后的所有修改的数据,aof比快照方式有更好的持久化性,是由于在使用aof时,redis会将每一个收到的写命令都通过write函数追加到命令中,当redis重启启动时会重新执行文件中保存的写命令来在内存中重建这个数据库的内容。Aof文件不是立即写到磁盘上,可以通过配置文件修改强制写到硬盘中。

aof设置:
appendonly yes //启动aof持久化方式有三种修改方式。
appendfsync always //受到写命令就立即写入到磁盘中,效率最慢,但是保证完全的持久化。(比如页面写入慢,可能就是这种造成的,可加服务器处理)
appendfsync everysec //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中。
appendfsync no //完全依赖操作系统,性能最好,不进行同步,系统去操作,持久化没保证。

RDB文件和AOF文件只开其中一种即可

上述内容都是在redis.conf文件中配置的,redis.conf的参数解释详情参考“4、3、4redis.conf配置文件说明”。

十三、发布与订阅消息

13、1简介

Redis提供了简单的发布订阅功能。

使用subscribe [频道] 进行订阅监听。

使用publish [频道] [发布内容] 进行发布消息广播。

为了解耦发布者(publisher)和订阅者(subscribe)之间的关系,redis使用了channel(频道)作为两者的中介,发布者将信息直接发布给channel,而channel负责将信息发送给适当的订阅者,发布者和订阅者直接没有相互关系,也不知道对方的存在。

Screenshot20200105总结redis第三部分安全性主从哨兵事物持久化发布与订阅虚拟内存你可以选择不平凡51CTO博客.png

参考网站(包括场景和源码分析):

http://blog.csdn.net/clh604/article/details/19754939”

http://www.cnblogs.com/huangxincheng/p/5002794.html”

13、2操作

13、2、1一个发布,一个监听

#开启两个窗口,一个做发布,一个做监听。

#注意事项:发布窗口的publish后面的名称channel1一定要跟监听窗口中subscribe后面的名称channel1保持一致,不然不能监听到消息。

#发布窗口
[root@redis logs]# redis-cli
127.0.0.1:6379> publish channel1 testmessage1
(integer) 1#接收到发布信息的监听个数
127.0.0.1:6379> publish channel1 testmessage2
(integer) 1
127.0.0.1:6379> publish channeltest testmessage
(integer) 0
 
#监听窗口
127.0.0.1:6379> subscribe channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
#注意监听的信息是3个一组
1) "message"
2) "channel1"
3) "testmessage1"
#注意监听的信息是3个一组
1) "message"
2) "channel1"
3) "testmessage2"

13、2、2一个发布,多个监听

#发布部分
[root@redis logs]# redis-cli
127.0.0.1:6379> publish channel1 message1
(integer) 2
127.0.0.1:6379> publish channel1 message2
(integer) 2
 
#监听部分
[root@redis ~]# redis-cli
127.0.0.1:6379> subscribe channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message"
2) "channel1"
3) "message1"
1) "message"
2) "channel1"
3) "message2"
 
[root@redis conf]# redis-cli
127.0.0.1:6379> subscribe channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message"
2) "channel1"
3) "message1"
1) "message"
2) "channel1"
3) "message2"

13、2、3多个发布,多个监听

#发布部分
 
[root@redis logs]# redis-cli
127.0.0.1:6379> publish channel1 message11
(integer) 2
127.0.0.1:6379> publish channel1 message12
(integer) 2
 
[root@redis ~]# redis-cli
127.0.0.1:6379> publish channel2 message21
(integer) 2
127.0.0.1:6379> publish channel2 message22
(integer) 2
 
#监听部分
[root@redis ~]# redis-cli
127.0.0.1:6379> subscribe channel1 channel2
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "subscribe"
2) "channel2"
3) (integer) 2
1) "message"
2) "channel1"
3) "message11"
1) "message"
2) "channel2"
3) "message21"
1) "message"
2) "channel1"
3) "message12"
1) "message"
2) "channel2"
3) "message22"
 
[root@redis conf]# redis-cli
127.0.0.1:6379> subscribe channel1 channel2
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "subscribe"
2) "channel2"
3) (integer) 2
1) "message"
2) "channel1"
3) "message11"
1) "message"
2) "channel2"
3) "message21"
1) "message"
2) "channel1"
3) "message12"
1) "message"
2) "channel2"
3) "message22"

十四、虚拟内存的使用

下述内容参考文档

http://ifeve.com/redis-mem/”

http://blog.csdn.net/xinguimeng/article/details/43884893”

http://www.cnblogs.com/stephen-liu74/archive/2012/04/04/2366803.html”

14、1简介

和大多数NoSql数据库一样,redis同样遵循了key/values数据存储模型。在有些情况下,redis会将key/values保存在内存中以提高数据查询和数据修改的效率,然而这样的做法并非总是很好的选择。鉴于此,我们可以将之进一步优化,即尽量在内存中只保留keys的数据,这样可以保证数据检索的效率,而values数据在很少使用的时候可以被换出到磁盘。

redis未使用linux的虚拟内存机制,而是实现了自己的虚拟内存机制,主要原因有以下两点:

1、linux虚拟内存粒度过大,在linux中使用4KB的页面,对于redis来说太大了,而redis中的绝大多数对象都远远小于这个数值。

2、redis可以把数据交换到磁盘上的时候进行适当的操作,比如压缩,通常保存到磁盘上的对象可以去除指针和对象元数据信息,一般压缩后的对象可以比内存中的对象小10倍,这样可以节省很多的IO操作。

14、2应用场景

在实际应用中,如果内存中有一个10W条记录的key数据集,而只有10%被经常使用,那么开启虚拟内存的redis将把与较少使用的key相对应的value转移到磁盘上。当客户端请求获取这些value时,他们将被从swap文件中读回,并载入到内存中。也就是说,如果你的数据库中有大量的keys,其中每个key仅仅关联很小的value,那么这种场景就不是非常适合使用虚拟内存。如果数据库中只是包含很少的keys,而每一个key所关联的value确非常大,那么这种场景就适合使用虚拟内存。

14、3虚拟内存配置

1、在配置文件中添加以下配置项,以使当前Redis服务器在启动时打开虚存功能。

vm-enabled yes

2、在配置文件中设定Redis最大可用的虚存字节数。如果内存中的数据大于该值,则有部分对象被换出到磁盘中,其中被换出对象所占用内存将被释放,直到已用内存小于该值时才停止换出。

vm-max-memory (bytes)

Redis的交换规则是尽量考虑"最老"的数据,即最长时间没有使用的数据将被换出。如果两个对象的age相同,那么Value较大的数据将先被换出。需要注意的是,Redis不会将Keys交换到磁盘,因此如果仅仅keys的数据就已经填满了整个虚存,那么这种数据模型将不适合使用虚存机制,或者是将该值设置的更大,以容纳整个Keys的数据。在实际的应用,如果考虑使用Redis虚拟内存,我们应尽可能的分配更多的内存交给Redis使用,以避免频繁的换入换出。

3、在配置文件中设定页的数量及每一页所占用的字节数。为了将内存中的数据传送到磁盘上,我们需要使用交换文件。这些文件与数据持久性无关,Redis会在退出前会将它们全部删除。由于对交换文件的访问方式大多为随机访问,因此建议将交换文件存储在固态磁盘上,这样可以大大提高系统的运行效率。

vm-pages 134217728

vm-page-size 32

在上面的配置中,Redis将交换文件划分为vm-pages个页,其中每个页所占用的字节为vm-page-size,那么Redis最终可用的交换文件大小为:vm-pages * vm-page-size。由于一个value可以存放在一个或多个页上,但是一个页不能持有多个value,鉴于此,我们在设置vm-page-size时需要充分考虑Redis的该特征。

4、在Redis的配置文件中有一个非常重要的配置参数,即:

vm-max-threads 4

该参数表示Redis在对交换文件执行IO操作时所应用的最大线程数量。通常而言,我们推荐该值等于主机的CPU cores。如果将该值设置为0,那么Redis在与交换文件进行IO交互时,将以同步的方式执行此操作。

对于Redis而言,如果操作交换文件是以同步的方式进行,那么当某一客户端正在访问交换文件中的数据时,其它客户端如果再试图访问交换文件中的数据,该客户端的请求就将被挂起,直到之前的操作结束为止。特别是在相对较慢或较忙的磁盘上读取较大的数据值时,这种阻塞所带来的影响就更为突兀了。然而同步操作也并非一无是处,事实上,从全局执行效率视角来看,同步方式要好于异步方式,毕竟同步方式节省了线程切换、线程间同步,以及线程拉起等操作产生的额外开销。特别是当大部分频繁使用的数据都可以直接从主内存中读取时,同步方式的表现将更为优异。

如果你的现实应用恰恰相反,即有大量的换入换出操作,同时你的系统又有很多的cores,有鉴于此,你又不希望客户端在访问交换文件之前不得不阻塞一小段时间,如果确实是这样,我想异步方式可能更适合于你的系统。

至于最终选用哪种配置方式,最好的答案将来自于不断的实验和调优。


标题:总结redis第三部分(安全性、主从、哨兵、事物、持久化、发布与订阅、虚拟内存)
作者:yazong
地址:https://blog.llyweb.com/articles/2016/12/11/1578156738950.html