-
Redis的支持的数据类型
String:最大512MB Hash:哈希 List:列表 Set:集合 zset:有序集合
Redis持久化方式,
RDB(Redis Database)定时持久化备份RDB文件,数据量大的情况下启动比较快,性能比AOF高。备份还原方便,缺点就是会丢数据,因为是定时备份的(性能要求高时可选用)
AOF(Append-only file)有三种配置,实时always+每秒everysec+不同步no 虽然效率低,但是保证了数据的完整性(数据完整性要求高时可选用,牺牲性能保证数据完整性)
Redis的高可用方案: Master + Slave + Sentinel 1 + Sentinel 2
缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。
如何避免:
- 做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期
- 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
- 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
缓存穿透:用户攻击者想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
解决方案:
1.可以使用redis的set做一个key集合,将不存在的key请求拦截
2.缓存空对象。 就是即使数据库中也没有的数据,用null值存起来,然后设置一个有效期或定期清理
3.布隆过滤器
-
MQ消息队列
优点:在这个场景中,A 系统跟其它各种乱七八糟的系统严重耦合,A 系统产生一条比较关键的数据,很多系统都需要 A 系统将这个数据发送过来。A 系统要时时刻刻考虑 BCDE 四个系统如果挂了该咋办?要不要重发,要不要把消息存起来?
概括讲就是:解耦、异步、削峰
缺点:系统可用性会降低 & 系统复杂性增加
- MQ组成(结构):
- Broker:消息服务器,作为server提供核心服务
- Producer:消息生成者,业务的发起方,负责生产消息传输给Broker
- Concumer消息消费者,业务的处理方,负责从Broker获取消息,并进行业务处理
- Topic:发布-订阅模式下的消息汇集地,实现消息广播(发送给不同的订阅者)
- Queue:队列,PTP模式下,特定生产者向特定queue发送消息,消费者订阅特定的queue完成消息的接收
- Message:消息体
-
模式:
-
点对点,使用queue
-
发布-订阅 使用topic
如何解决重复读问题?
kafka有个offset的概念,添加全局唯一的id。messageId。消费的时候判断messageId是否消费过,没有则进行消费,结束后保存messageId至已消费队列。如果有,则放弃消费消息
保证消息队列消费的幂等性
比如数据写库,可以先根据主键查一下,如果这数据都有了,就update
比如写redis,那没问题,因为每次都是set,天然幂等性
如果不是上面两个场景,那做的稍微复杂一点,需要让生产者发送每条数据的时候,里面加一个全局唯一的id,类似订单id之类的东西,然后消费到了后,先根据这个id去比如redis里查一下,之前消费过吗?如果没有消费过,就处理,然后这个id写redis。如果消费过了,那就别处理了,保证别重复处理相同的消息即可。
还有比如基于数据库的唯一键来保证重复数据不会重复插入多条,重复数据拿到了以后我们插入的时候,因为有唯一键约束了,所以重复数据只会插入报错,不会导致数据库中出现脏数据
如何保证消息不丢失?
rabbitmq提供事务功能:可以保证消息传输可靠性(原子性)发现消息丢失,则会回滚
开启confirm模式 在生产者那里设置开启confirm模式后,每次写消息都会分配一个唯一的id,然后如果写入了rabbitmq中,rabbitmq会回传一个ack消息,告诉你说这个消息ok了。如果rabbitmq没能处理这个消息,会回调你一个nack接口,告诉你这个消息接收失败,你可以重试。而且你可以结合这个机制自己在内存里维护每个消息id的状态,如果超过一定时间还没接收到这个消息的回调,那么你可以重发