redis
redis如何保证原子性?
1 incr是原子操作的, 直接用redis的incr实现read和write的打包原子操作,就不会出现读了一半,然后被别人篡改了。 像批量设置多个值的场景可以用mset,批量获取多个值的mget,与incr相对应的decr,这些都是原子的。
2 即使redis支持很多原子命令,但是还是无法满足所有场景,于是redis在2.6之后开始支持开发者编写lua脚本传到redis中,使用lua脚本的好处就是:
减少网络开销,通过lua脚本可以一次性的将多个请求合并成一个请求。
原子操作,redis将lua脚本作为一个整体,执行过程中,不会被其他命令打断,不会出现竞态问题。
复用,客户端发送的lua脚本会永远存在redis服务中。
redis部署的方式有哪些?
单机模式
主从模式
哨兵模式
集群模式
redis以上的部署方式有哪些优势、弊端?
单机模式:
- 优点
部署简单 - 缺点
可支持的并发量少
主从模式:
- 优点:
1 能够为后续的高可用机制打下基础
2 在持久化的基础上能够将数据同步到其他机器,在极端情况下做到灾备的效果
3 能够通过主写从读的形式实现读写分离提升Redis整体吞吐,并且读的性能可以通过对从节点进行线性扩容无限提升 - 缺点:
1 全量数据同步时如果数据量比较大,在之前会导致线上短暂性的卡顿。
2 一旦主节点宕机,需要人工干预从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预。
3 写入的QPS性能受到主节点限制,虽然主从复制能够通过读写分离来提升整体性能,但是只有从节点能够做到线性扩容升吞吐,写入的性能还是受到主节点限制木桶效应,整个Redis节点群能够存储的数据容量受到所有节点中内存最小的那台限制,比如一主两从架构:master=32GB、slave1=32GB、slave2=16GB,那么整个Redis节点群能够存储的最大容量为16GB 。
哨兵模式:数据的分布都是去中心化,可支持的读并发有限
- 优点:
1 解决了之前主从切换需要人工干预问题,保证了一定意义上的高可用 - 缺点:
1 全量数据同步仍然会导致线上出现短暂卡顿
2 写入QPS仍然受到主节点单机限制,对于写入并发较高的项目无法满足需求
3 仍然存在主从复制时的木桶效应问题,存储容量受到节点群中最小内存机器限制
集群模式:
redis分布式锁的底层原理
setnx,如果
redis使用过程中遇到的一些问题
缓存雪崩:短时间redis的key失效,所有的请求直接到数据库。
解决办法:设置key随机消失的时间。
缓存击穿:热key失效
解决办法:1 设置永不过期;
缓存穿透:使用不存在的key查询
解决办法:1、设置ip白名单,防止黑客攻击;2、对空值进行缓存
rocketMQ
如何保证消息的可靠性(不丢失)
保证消息的不丢失,主要从三个方面:生产端、broker端、消费端处理。
- 生产端
在生产阶段,主要通过请求确认机制,来保证消息的可靠传递。
1、同步发送的时候,要注意处理响应结果和异常。如果返回响应OK,表示消息成功发送到了Broker,如果响应失败,或者发生其它异常,都应该重试。
2、异步发送的时候,应该在回调方法里检查,如果发送失败或者异常,都应该进行重试。
3、如果发生超时的情况,也可以通过查询日志的API,来检查是否在Broker存储成功。 - broker端
存储阶段,可以通过配置可靠性优先的 Broker 参数来避免因为宕机丢消息,简单说就是可靠性优先的场景都应该使用同步。
1、消息只要持久化到CommitLog(日志文件)中,即使Broker宕机,未消费的消息也能重新恢复再消费。
2、Broker的刷盘机制:同步刷盘和异步刷盘,不管哪种刷盘都可以保证消息一定存储在pagecache中(内存中),但是同步刷盘更可靠,它是Producer发送消息后等数据持久化到磁盘之后再返回响应给Producer。
3、Broker通过主从模式来保证高可用,Broker支持Master和Slave同步复制、Master和Slave异步复制模式,生产者的消息都是发送给Master,但是消费既可以从Master消费,也可以从Slave消费。同步复制模式可以保证即使Master宕机,消息肯定在Slave中有备份,保证了消息不会丢失。 - 消费端
Consumer保证消息成功消费的关键在于确认的时机,不要在收到消息后就立即发送消费确认,而是应该在执行完所有消费业务逻辑之后,再发送消费确认。因为消息队列维护了消费的位置,逻辑执行失败了,没有确认,再去队列拉取消息,就还是之前的一条。
消息积压如何处理
发生了消息积压,这时候就得想办法赶紧把积压的消息消费完,就得考虑提高消费能力,一般有两种办法:
-
消费者扩容:如果当前Topic的Message Queue的数量大于消费者数量,就可以对消费者进行扩容,增加消费者,来提高消费能力,尽快把积压的消息消费玩。
-
消息迁移Queue扩容:如果当前Topic的Message Queue的数量小于或者等于消费者数量,这种情况,再扩容消费者就没什么用,就得考虑扩容Message Queue。可以新建一个临时的Topic,临时的Topic多设置一些Message Queue,然后先用一些消费者把消费的数据丢到临时的Topic,因为不用业务处理,只是转发一下消息,还是很快的。接下来用扩容的消费者去消费新的Topic里的数据,消费完了之后,恢复原状。
如何保证不重复消费
对分布式消息队列来说,同时做到确保一定投递和不重复投递是很难的,就是所谓的“有且仅有一次” 。 RocketMQ择了确保一定投递,保证消息不丢失,但有可能造成消息重复。
处理消息重复问题,主要有业务端自己保证,主要的方式有两种:业务幂等和消息去重。
-
业务幂等:第一种是保证消费逻辑的幂等性,也就是多次调用和一次调用的效果是一样的。这样一来,不管消息消费多少次,对业务都没有影响。
-
消息去重:第二种是业务端,对重复的消息就不再消费了。这种方法,需要保证每条消息都有一个惟一的编号,通常是业务相关的,比如订单号,消费的记录需要落库,而且需要保证和消息确认这一步的原子性。
具体做法是可以建立一个消费记录表,拿到这个消息做数据库的insert操作。给这个消息做一个唯一主键(primary key)或者唯一约束,那么就算出现重复消费的情况,就会导致主键冲突,那么就不再处理这条消息。
如何实现顺序消息
顺序消息是指消息的消费顺序和产生顺序相同,在有些业务逻辑下,必须保证顺序,比如订单的生成、付款、发货,这个消息必须按顺序处理才行。
顺序消息分为全局顺序消息和部分顺序消息,全局顺序消息指某个 Topic 下的所有消息都要保证顺序;
部分顺序消息只要保证每一组消息被顺序消费即可,比如订单消息,只要保证同一个订单 ID 个消息能按顺序消费即可。