1.redis
常用数据类型:
String 最常用
List
Set 可以全局去重
布隆过滤器 防止缓存击穿
部署方式:
单机部署
哨兵模式
一个主节点和多个从节点,主节点用来写,从节点用来读,主节点会同步数据给从节点,每个节点防止单点再使用备用服务器
缺点就是每个服务器的数据一样,很浪费内存空间,并且有脑裂问题,就是主节点因为网络等原因连接不上,认为他挂了然后再选举一个,然后原来的又恢复了,导致数据不一致。
集群模式
集群模式是把redis分成固定数量的插槽,然后每台服务器分配不同的插槽,数据是不一样的,访问也快速,缺点是有单点问题,而且其中有一台挂了导致整个不可用,所以还需要添加备用节点
redis为什么快:
因为基于内存的,以及是单线程操作,不用考虑锁或者上下文切换问题
而且是使用多路io复用模型。。。讲几种io模型
redis的数据同步方式:
从服务器启动的时候会发送一个psync命令给主库要求进行同步数据,master会再起一个线程来进行生成rdb快照进行传输到从库,
从库解析加载到内存,然后主库在传输的时候如果还新的数据写入,会把这部分数据写入缓冲区,再继续传给从服务器,这时候数据就全了。如果这个过程中链接中断会自动重连
redis持久化方式:
持久化有rdb和aof两种方式
rdb就周期性的同步,每隔一段时间生成快照保存成一个文件代表这个时间点的数据,代表某一时间段缺点就是可能会丢数据,以及同步的时候如果文件比较大可能会卡顿。
aof是实时的把操作写到日志里,类似mysql的binlog,缺点是aof的日志文件比rdb的大,如果有问题恢复的没那么快
这两种是可以同时开启的,如果真正出现问题了,我们可以拿rdb的日志文件来进行恢复到某个时间点,因为间隔时间同步一次的,还会缺一些数据,然后可以从aof的日志进行补全。
redis的内存回收策略:
Redis的删除有定期删除和惰性删除2种
定期删除是redis每100秒就会抽取一些设置了过期时间的key来判断是否过期,过期了就删除,但是这个只是随机抽取不是全量遍历所以有一些还是没有删除
所以有了惰性删除,就是等到你get这个key的时候再检查是否过期,如果过期就返回空并且把这个key删了
不过还有问题,如果你一直不get就一直不会删除了,内存就会越堆越多,然后就会触发redis的内存淘汰机制,当内存不足以加入新的数据时候,有几种策略:报错,或者随机删除一个,这些策略,但我们一般常用的是删除一个最近最少使用的。
redis做秒杀锁:
商品或者优惠券之类的比如只有5个,但有100个人同时抢,如何保证?
主要逻辑是数量-1这里,最简单的方法就是加syc,但是这样会锁住所有商品,而且分布式情况下也行不通,所以需要分布式锁,
可以用redis的setnx方法的原子性来实现,而且可以优化一下锁的粒度不是锁住所有商品,而且锁住当前这个商品就行,具体做法比如把这个商品的id作为锁set到redis里,set成功的说明拿到了锁,其他人等待。
redis做分布式锁会有其他问题,比如执行过程中抛出异常锁没释放,需要try cahch起来进行释放锁
还有极端情况下,执行到一般 服务器挂了,也没能释放锁,所以需要设置锁的超时时间,并且要主要设置锁的超时时间不能太短,
比如你设置2秒,然后你执行出了问题,cpu,Load太高啊,或者数据库问题,或者下游有问题执行了3秒,锁提前释放了,别的线程进来了,就会出现并发问题。
2.dubbo
服务暴露的时候 组装服务的参数 包括 方法名 参数类型 参数值 版本号等,封装成一个invoke存到map里,然后向注册中心进行注册
然后调用这个服务的时候消费者从注册中心拿到ip地址列表,使用dubbo协议进行二进制流的方式传输到对方服务器,但实际我们调用的方法是调用的代理类
然后代理类再用Client进行远程调用,调用的时候会进行序列化,在多台机器多个ip的情况下就涉及到负载算法
一般有权重随机,轮询,最少活跃,hash等算法,而且调用的方式也有同步异步,同步就是等待结果,异步的话就是先直接返回,但是传过去有一个唯一id,等服务放处理完了,就能用这个id找回原点进行回调。
然后再说说服务方收到了这个方法调用,该怎么做,首先会把这个请求处理任务丢到线程池来执行,真正开始执行的时候也是调用的代理类来进行,
解析反序列化消息体,我们暴露服务的时候不是封装了invoke存到map里吗,然后现在再根据key拿出来,进行调用 ok
负载算法:
轮询
hash
权重
最少活跃
随机
失败策略:
默认这台挂了马上换另一台
快速失败,抛出异常
先返回空,再启用线程定时调用
序列化方式:
Java自带的序列化
Hessian2 是默认的
Fst
netty:
dubbo的远程调用是基于netty来进行网络通信的,因为netty快,netty基于nio (说说io模型), 以及零拷贝还有Reactor多线程模型
3.消息队列
作用:
肖峰填谷:在大促的时候大量的请求服务器没法一下子处理,所以需要消息队列来存储来慢慢消费
解耦:比如订单状态要告诉系统A,调他接口告诉他状态改了,然后又来系统B,你也要告诉他,这时候就可以用消息队列,把状态往消息队列一丢,各个系统订阅就ok了,当然你提供接口给他们主动调来获取状态也行,但是会增加自己应用的压力。
异步:很好理解,我们调别人的接口,需要等待返回结果,降低吞吐量,如果不要求实时返回或者另一种方式通知结果的话,往消息队列一丢 搞定
常用消息队列:
Kafka:用于大数据以及日志收集较多,消费者主动拉取消息,分为多个broker保证高可用,但是缺点就是都是命令没有界面,以及因为保证高可用复制多份数据,上百个topic的时候性能下降
rocketMq:基于java开发的,使用较多,通过主从配置支持高可用。
rabbitMq :吞吐量万级,比上面2个有所不如,但是小型企业够用,上手简单效率快
如何保证消息不丢失:
发送时丢失的话,可能发送时候报错了,拿到错误对应处理,重试或者抛出异常
在消息服务器丢失,消息服务器挂了,消息没了,开启持久化
消费时丢失,有一些消息队列是默认丢给你就完事了,就当作成功了不会重试,如果你执行的时候报错了,这个消息也就丢了,所以需要开启返回成功了才是真的成功
如何保证消息顺序:
消息队列只能保证消息发出的顺序,但消费的顺序是无法保证的,比如你发出消息未收货,再发出消息已发货
可能已发货先消费到了就会出现问题,所以只能自己在程序进行处理,比如加状态机进行状态强制校验(画一画状态机)
如何保证消息不重复消费:
在分布式情况下,多台服务器都订阅了这个消息,如果通过广播的方式每一台都收得到
如何保证只有一台成功消息,那就需要分布式锁进行幂等,可以用redis,或者数据库,zookeeper来作为锁都可以
消息队列服务器挂了怎么办:
每个消息队列对自己的高可用的实现方式不一样,但是思想都是主备进行数据同步,通过注册中心一台挂了拿另一台
4.注册中心
分布式cap理论:
C: 一致性,所有节点数据同步
A: 可用性,保证每一次的调用是可用的
P:分区容错性,挂了不影响整个
A跟C是不可兼得的,所以每个注册中心都有自己所秉持的理念
常用注册中心:
nacos 可以通过配置切换AP和CP,并且支持配置中心,现在集成springCloud这一套非常好用,使用时注意数据配置持久化到数据库,不然会丢失。
zookeeper 秉持CP的理论,保证所有节点数据一致,简单点说就是我给你的机器是肯定对的,但是可能慢一点,因为zookeeper的选举机制会比较满,期间不能注册。
eruka 秉持AP理念,保证高可能,你一访问我就给你返回,但是给你的服务器可能不能用了,你自己试试,不行你再跟我说,eruka目前社区也不维护了。
5.分布式事务
在分布式系统中,比如应用A改了状态需要同步应用B,其中一个执行失败了会导致状态不同步,所以需要分布式事务来进行操作
2PC、3PC概念
2PC:就是把多个本地事务分为2个阶段提交,第一阶段告诉他们,准备好了没,保证能连接的通,然后再通知开始有了结果再通知比如A失败了
通过一个中间协调者来进行一起成功或者一起回滚,但是这个协调者会有单点问题,还有堵塞问题,我A执行好了,一直在等你B的结果。
3PC: 引入了超时机制以及多了一段提交,解决堵塞问题
TCC概念
自己编写代码来进行提交和回滚的逻辑方案,然后自己编写逻辑来协调双方的提交和回滚
消息队列处理
分布式事务都是会降低吞吐量,所以强制性要求不高的话,可以使用消息队列进行处理
保证最终一致:状态消息丢出去,不用管了,总会消费的,消费失败也会重试,重试还失败需要人工排查原因了
保证可靠一致:应用A用本地事务更改状态并且发送消息,应用B监听这个消息后也执行自己的事务
如果A失败了,A自己回滚消息也没发出啥都没改变
如果B失败了,发出一条失败消息,A跟B都监听这个消息然后进行回滚
极端情况下,执行到一般,服务挂了 失败消息没发出,就需要定时调用接口去查询执行结果了,
Seata
阿里开源的分布式事务中间件
AT模式(业务侵入小) ,基于数据库分布式事务AX协议进行统一,缺点是吞吐量低
TCC模式 通过注册注册该服务是事务参与者
6.sentinel限流
限流: 在大促期间,为了保证自己的服务不被外部或者上游的流量击倒,需要对流量进行限制
降级:指的是能提前预知的,早一步的控制手段,比如知道准备大促了,关闭一些不必要的接口,关闭一些报表生成的定时器,把保存日志放到消息队列等
熔断:指的是如果有不可预知的突发情况,作最坏的打算,降低最小的损失,比如自己挂了,为了不拖累上游服务,直接快速返回失败,不要一直转圈圈把上游也拖垮了,熔断设置一定阈值触发,也能设置一定阈值恢复
sentinel提供页面对服务进行限流控制,需要在配置文件配置注册到sentinel服务器上
sentinel需要进行持久化