redis 可以做消息中间件(MQ =message queue),通常通过订阅发布模式来实现(消息订阅发布模式),还可以基本数据类型Lists实现(点到点模式,可以使用lpush,lpop 实现消息先进先出)。
A 系统发送数据到 BCD 三个系统,通过接口调用发送。如果 E 系统也要这个数据呢?那如果C 系统现在不需要了呢?A 系统负责人几乎崩溃......A 系统跟其它各种乱七八糟的系统严重耦合,A 系统产生一条比较关键的数据,很多系统都需要 A 系统将这个数据发送过来。如果使用 MQ,A 系统产生一条数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。如果新系统需要数据,直接从MQ 里消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消费即可。这样下来,A 系统压根儿不需要去考虑要给谁发送数据,不需要维护这个代码,也不需要考虑人家是否调用成功、失败超时等情况。就是一个系统或者一个模块,调用了多个系统或者模块,互相之间的调用很复杂,维护起来很麻烦。但是其实这个调用是不需要直接同步调用接口的,如果用 MQ 给它异步化解耦。
A 系统接收一个请求,需要在自己本地写库,还需要在 BCD 三个系统写库,自己本地写库要 3ms,BCD 三个系统分别写库要 300ms、450ms、200ms。最终请求总延时是 3 + 300 + 450 +200 = 953ms,接近 1s,用户感觉搞个什么东西,慢死了慢死了。用户通过浏览器发起请求。如果使用MQ,那么 A 系统连续发送 3 条消息到 MQ 队列中,假如耗时 5ms,A 系统从接受一个请求到返回响应给用户,总时长是 3 + 5 = 8ms。
减少高峰时期对服务器压力。生产者服务器性能非常好,同一时刻能接受大量并发请求(假如并发3000请求),假如消费者服务器性能不好(并发300请求),突然生产者搞了秒杀活动,并发量突然增加,可能让消费者宕机。这时候有了消息中间,生产者直接把消息放入中间件,再由消费者根据自身性能慢慢消费。
发送者(发布者)不是计划发送消息给特定的接收者(订阅者)。而是发布的消息分到不同的频道,不需要知道什么样的订阅者订阅。订阅者对一个或多个频道感兴趣,只需接收感兴趣的消息,不需要知道什么样的发布者发布的。这种发布者和订阅者的解耦合可以带来更大的扩展性和更加动态的网络拓扑。
启动redis服务端:
/usr/redis/bin/redis-server /usr/redis/bin/redis.conf
启动redis客户端:
/usr/redis/bin/redis-cli -h 192.168.140.41
1、模拟订阅者,订阅某一个或者多个管道(订阅2个频道(管道)):
192.168.140.41:6379> subscribe aaa bbb
1)消息类型 2) 频道名称 3)代表我们现在订阅的频道的数量
双击新建会话,再启动redis一个客户端:
/usr/redis/bin/redis-cli -h 192.168.140.41
模拟发布者,发布消息到一个管道:
92.168.140.41:6379> publish aaa 111
观察消费者窗口,会发现出来订阅到消息:
1) 消息类型 2)来源频道的名称 3) 实际消息的内容
2、 发布者模拟多次消息发布:
订阅者会接受到多个频道多条消息
3、多个发布者和订阅者
启动多个会话 模拟多个订阅者:(此处启用两个)
/usr/redis/bin/redis-cli -h 192.168.140.41
192.168.140.41:6379> subscribe aaa ccc
/usr/redis/bin/redis-cli -h 192.168.140.41
192.168.140.41:6379> subscribe bbb ccc
启动多个会话 模拟多个发布者:(此处在模拟一个)
/usr/redis/bin/redis-cli -h 192.168.140.41
192.168.140.41:6379> publish ccc 4444
订阅者会接受到多个频道多条消息
4、数据库(默认分为16个库)和作用域:
发布/订阅与key所在空间没有关系,它不会受任何级别的干扰,包括不同数据库编码。
启动客户端:
/usr/redis/bin/redis-cli -h 192.168.140.41
切换数据库:
select 10
在第11库订阅频道:
192.168.140.41:6379[10]> subscribe aaaa
发布者使用第1库和第3库 发布消息:
192.168.140.41:6379> publish aaaa test1aaaa
(integer) 2
192.168.140.41:6379> select 3
OK
192.168.140.41:6379[2]> publish aaaa test2bbbb
(integer) 2
在第1库和第3库 发布的消息,在第1和10库订阅中都能看到
5、模糊匹配订阅
客户端可以订阅全风格的模式以便接收所有来自能匹配到给定模式的频道的消息
psubscribe p=pattern 模式
启动一个客户端,模拟订阅者:
/usr/redis/bin/redis-cli -h 192.168.140.41
使用psubscribe命令,订阅所有以a开头的频道(不具体订阅频道):
192.168.140.41:6379> psubscribe a*
启动一个客户端,模拟发布者:
/usr/redis/bin/redis-cli -h 192.168.140.41
使用publish命令,向a开头的频道名称上发送消息
redis本身是基于内存存储,平时进行读写数据都是在内存中,直接和内存交互。但是redis支持持久化,把内存数据保存磁盘上,到达持久化的效果。
redis支持的持久化方式有两种:
1) rdb(redis database) 底层将内存中的数据根据条件定时保存到磁盘上。(a=1......);官网:持久化方式能够在指定的时间间隔能对你的数据进行快照存储.
2) aof(append of file) 底层将执行的命令追加日志尾部,当需要恢复数据时,需要重新执行这些命令,数据才会恢复。(set a=1......);官网:记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.
redis server 主进程仍然进行缓存读写,分叉出一个子进程,在满足配置的策略时定时,保存到临时文件,保存完毕后,覆盖原来文件(15分钟,5分钟或者1分钟之前文件)
vim /usr/redis/bin/redis.conf
:196-220 行
Save the DB on disk:
save
Will save the DB if both the given number of seconds and the given
number of write operations against the DB occurred.
根据给定的秒数和 key更新的数量(写操作的次数) 来保存数据
save 900 1 在900秒(15分钟)之内 内存中的所有数据有1个key发生变化 进行一次rdb
save 300 10 在300秒(5分钟)之内 内存中的所有数据有10个key发生变化 进行一次rdb
save 60 10000 在60秒(1分钟)之内 内存中的所有数据有10000个key发生变化 进行一次rdb (redis性能非常好,每秒写的速度可以达到81000次/秒 1分钟 内理论上支持81000*60 =4860000 key发生变化的 )
rdb保存到磁盘文件名称为:
:253 dump.rdb
客户端执行命令时,redis server 会把执行命令 按照配置策略(3钟),写入aof文件中(appendonly.aop)
:699 appendonly yes 开启aof方式 默认没有开始,默认使用 rdb方式
:693 RDB和AOF方式可以同时开启,同时开启时,redis优先使用AOF方式。
aof保存到磁盘文件名称为:
:703 appendonly.aop
:709
Redis supports three different modes:
# no: don't fsync, just let the OS flush the data when it wants. Faster.
从来不执行文件同步 只有当系统主动刷新数据才会。速度最快,最不安全的
# always: fsync after every write to the append only log. Slow, Safest.
每次写命令执行完毕都会追加命令到文件中。速度最慢,最安全的。
# everysec: fsync only one time every second. Compromise.
一秒钟执行一次文件同步。速度适中,安全性适中。
:728-730
# appendfsync always
appendfsync everysec
# appendfsync no
默认方式为 一秒钟同步一次
优点:
缺点:
优点:
缺点:
将一组命令放在同一个事务中进行处理。
Exec (execute):
命令负责触发并执行事务中的所有命令(相当于数据库事务中的commit)
Multi:
开启一个事务(相当于数据库事务中的begin trasication),总是返回OK。 MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC命令被调用时, 所有队列中的命令才会被执行。
Discard:
回滚事务(相当于数据库事务中的rollback)。 当执行 DISCARD 命令时, 事务会被放弃, 事务队列会被清空, 并且客户端会从事务状态中退出。
Watch:
redis使用关键字实现乐观锁(check-and-set)。被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回nil-reply来表示事务已经失败。
启动redis服务端:
/usr/redis/bin/redis-server /usr/redis/bin/redis.conf
启动redis客户端:
/usr/redis/bin/redis-cli -h 192.168.140.41
multi和exec用法
开启一个事务(相当于数据库事务中的begin trasication),总是返回OK
multi和discard用法:
watch乐观锁用法——乐观锁:多线程/多请求时才会发生,当修改某一个数据时,乐观认为其他线程/请求,都不会修改这数据,执行修改业务过程中,不会对该数据加锁,至到最后修改数据的时刻,判断该数据有没有其他线程/请求进行修改,如果被修改,放弃修改,如果没有被修改,执行修改。
启动两个客户端(模拟多线程)
/usr/redis/bin/redis-cli -h 192.168.140.41 在两个会话启动客户端
事务的特殊情况演示(事务中出现错误操作:redis中的回滚效果):
按照传统的数据库事务,有一个操作实行失败,所有事务都会回滚,但redis对事务事务支持不符合我们理解的事务操作。把正确的提交了,错误的报错,并没有把所有操作滚回.
这种做法的优点: