扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
因为redis速度相当快,所以在一台比较好的服务器下,一个外部用户在一秒内可以进行15W次的密码尝试,这意味着需要设定非常强大的密码来防止暴力破解。
创新互联建站是专业的呼兰网站建设公司,呼兰接单;提供网站制作、成都网站设计,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行呼兰网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
可以通过设置密码以及登录redis方式来操作,具体参考
1、Master可以拥有多个slave。
2、多个slave可以连接同一个master外,还可以连接到其他的slave。
3、主从复制不会阻塞master,在同步数据时,master可以继续处理client请求。
4、提供系统的伸缩性。
1、slave与master建立连接,发送sync同步命令。
2、master会开启一个后台进程,将数据库快照保存到文件中,同时master主进程会开始收集新的写命令并缓存。
3、master后台完成保存后,就把文件发送给slave。
4、slave将接收到的master文件保存到磁盘上。
#现在使用同一台机器的不同配置模拟主从复制场景。 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角色,即可知道是主服务或从服务。
#主节点 [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"
#主节点 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
有了主从复制以后,如果想对主从复制服务器进行监控,那么在redis2.6以后提供了一个“哨兵”的机制,在2.6版本中的哨兵为1.0版本并不稳定,会出现各种各种的问题,在redis2.8版本以后的哨兵功能才稳定起来。
顾名思义,哨兵的含义就是监控redis系统的运行状况,其功能主要有两点:
监控主数据库和从数据库是否正常运行。
2、主数据库出现故障时,可以自动将从数据库转换为主数据库,实现自动切换。
一个节点可以被多个哨兵去监控。哨兵跟所有redis节点是没有直接关系的,哨兵只是一个监控程序而已。
(可以使用keepalived(配合nginx使用)代替哨兵,实现高可用。)
#(只配主节点即可)
#配置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
首先是使用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"
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持久化的方式有以下两种。
snapshotting(快照)默认方式,将内存中以快照的方式写入到二进制文件中,默认为dump.rdb,可以通过配置设置自动做快照持久化的方式,我们可以配置redis在N秒内如果超过M个key修改,那么就自动做快照。
快照设置:
save 900 1 #900秒内如果超过1个key被修改,则发起快照保存。下述同理。
save 300 10
save 60 10000
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配置文件说明”。
Redis提供了简单的发布订阅功能。
使用subscribe [频道] 进行订阅监听。
使用publish [频道] [发布内容] 进行发布消息广播。
为了解耦发布者(publisher)和订阅者(subscribe)之间的关系,redis使用了channel(频道)作为两者的中介,发布者将信息直接发布给channel,而channel负责将信息发送给适当的订阅者,发布者和订阅者直接没有相互关系,也不知道对方的存在。
参考网站(包括场景和源码分析):
“http://blog.csdn.net/clh704/article/details/19754939”
“http://www.cnblogs.com/huangxincheng/p/5002794.html”
#开启两个窗口,一个做发布,一个做监听。
#注意事项:发布窗口的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"
#发布部分 [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"
#发布部分 [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”
和大多数NoSql数据库一样,redis同样遵循了key/values数据存储模型。在有些情况下,redis会将key/values保存在内存中以提高数据查询和数据修改的效率,然而这样的做法并非总是很好的选择。鉴于此,我们可以将之进一步优化,即尽量在内存中只保留keys的数据,这样可以保证数据检索的效率,而values数据在很少使用的时候可以被换出到磁盘。
redis未使用linux的虚拟内存机制,而是实现了自己的虚拟内存机制,主要原因有以下两点:
1、linux虚拟内存粒度过大,在linux中使用4KB的页面,对于redis来说太大了,而redis中的绝大多数对象都远远小于这个数值。
2、redis可以把数据交换到磁盘上的时候进行适当的操作,比如压缩,通常保存到磁盘上的对象可以去除指针和对象元数据信息,一般压缩后的对象可以比内存中的对象小10倍,这样可以节省很多的IO操作。
在实际应用中,如果内存中有一个10W条记录的key数据集,而只有10%被经常使用,那么开启虚拟内存的redis将把与较少使用的key相对应的value转移到磁盘上。当客户端请求获取这些value时,他们将被从swap文件中读回,并载入到内存中。也就是说,如果你的数据库中有大量的keys,其中每个key仅仅关联很小的value,那么这种场景就不是非常适合使用虚拟内存。如果数据库中只是包含很少的keys,而每一个key所关联的value确非常大,那么这种场景就适合使用虚拟内存。
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,有鉴于此,你又不希望客户端在访问交换文件之前不得不阻塞一小段时间,如果确实是这样,我想异步方式可能更适合于你的系统。
至于最终选用哪种配置方式,最好的答案将来自于不断的实验和调优。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流