(八)其他组件(redis、zk、dubbo、MQ、ES)
1、redis
redis缓存优势:redis数据结构⽐memcached更丰富,基本可以完全替换
redis社区⽐较活跃,性能也强⼤,也⽀持持久化等功能
结合业务,⽐如常用商品排序用到了有序集合zset
常用结构:String:key-value、hash:存储对象,⼀个key有多个值、list:列表型数据,消息队列等、set:⽆序集合、去重,交集、并集等,⽐如查看共同好友,在社交关系⽅⾯、数据排重等、sroted set:有序集合,去重,做榜单
redis是单线程:基于内存,绝⼤部分请求是纯粹的内存操作,CPU不是Redis的瓶颈,所以单线程就可以,避免了不必要的CPU上下⽂切换和其他竞争条件,⽐如锁操作等;底层是使⽤多路I/O复⽤模型,⾮阻塞IO;Redis6 后⽀持多线程,但是默认不开启;
持久化⽅式:⽀持AOF和RDB持久化
AOF:以⽇志的形式记录写、删除操作,没有查询操作,以⽂本记录, ⽀持秒级持久化、兼容性好;AOF⽂件通常要⼤于RDB⽂ 件,所以恢复⽐RDB慢;
RDB:以指定的时间间隔 将内存中的数据集快照写⼊磁盘,但不能做到实时持久化;⽂件紧凑,体积⼩,RDB在恢复速度⽐AOF的恢复速度要快;
3.2、redis淘汰机制
先进先出First In,First Out:插入队尾,淘汰队首;新访问的数据插⼊FIFO队列尾部,数据在FIFO队列中顺序移动,淘汰FIFO队列头部的数据;
最近最少使⽤ Least recently used:插入队首,淘汰队尾;如果数据最近被访问过,那么将来被访问的⼏率也更⾼;每当缓存数据被访问,则将数据移到链表头部,当链表满的时候,将链表尾部的数据丢弃。
最近不经常使⽤ Least Frequently Used:记录数据频率,按频率排序;根据数据的历史访问频率来淘汰数据,如果数据过去被访问多次,那么将来被访问的频 率也更⾼;把数据加⼊到链表中,按频次排序,⼀个数据被访问过,把它的频次+1,发⽣淘汰的时 候,把频次低的淘汰掉;
3.3、缓存击穿/雪崩
缓存击穿 :缓存过期,缓存中没有但数据库中有的数据;若是热点数据大量访问去查数据库,DB会瞬间压力增大;单一key出现过期;数据不过期/定时刷缓存/首次访问 加锁后续线程循环sleep请求 重刷到缓存;
缓存穿透:查询不存在数据,缓存中没有,去查数据库,导致DB压力大,比如查ID为-1000.到-1的数据;校验数据合理性/缓存存下key-null数据防止二次;
缓存雪崩:多个key出现过期,导致DB瞬间压力大;随机过期时间/定时刷数据/热点永不过期;
优势:数据类型多String、hash、list、set、zset,通过redisObject直接存储;持久化AOF/RDB-默认RDB配置appendonly,RDB可手/自持久化,主流AOF;单线程纯内存操作 速度快;
淘汰策略:先进先出、最近最少使用、最近最不经常使用;
并发问题:redis是C语言开发的,单线程,采用队列 将并发访问变为队列串行;纯内存操作,cpu不是瓶颈,没有上下文切换和资源竞争,也不存在加锁;
分布式锁:
异步队列:list,lpush+lpop+sleep/blpop,
持久化:RDBSave/BGSAVE/RDBLoad;AOF的flush方法;redis序列化协议--客户端+服务器,规定格式请求,执行完毕返回结果;+回复-错误*数组等5种;
集群:单机/ 主从复制--没有降低主库写压力/ 哨兵--监控心跳-故障切换慢会丢失/代理/cluster-无主节点;
redis内存模型:内存分配器,分配总内存,线程内存,内存碎片比率;
实际操作:redis-server;redis-cli+keys/scan/del/exists;treeNMS-占用率/连接数/增删改查;配置文件名称、目录、开启AOF、持久化策略等;Incr一个int报错/1/++1;
新特性:Pub/Sub发布订阅-两个client;Bloom过滤-存在错误/位图数组同样k个hash函数更新1或查1判断;RedisSearch-索引+文档/安装配置,对中文不好;aof定期重写压缩,aof与bgsave混合写;同步磁盘策略;
redis实现原理:字典-字典type/hash/index-字典表size/isused-数据索引表-数据; redis单线程+队列+发配给处理器; 过期处理:定期-每100MS随机抽删除+惰性-请求时判断过期删除; set+eval;
redis集群:ruby环境,大等于6个redis,安装gem包,6节点配置port和集群true,redis-trib的create命令启动;分数据分片0-16383;新节点,不均衡,节点下线,分片迁移;通过meet命令相互通信创建stateNode节点等; redis单线程原子性;语法命令错误才会回滚;半支持事务; 不同key不同槽;
数据一致性:设置超时时间;定时去刷数据;canal伪装成从库去获取binlog;
1.1、常用MQ
MQ优点:解耦系统、异步化、削峰 缺点:系统可⽤性降低、复杂度增⾼、维护成本增⾼
ActiveMQ:历史悠久,⽀持多种语⾔的客户端和协议,⽀持多种语⾔ 吞吐量不⾼,多队列性能低,存在消息丢失,较少使用
Kafka:⾼吞吐量,分布式发布订阅消息,数据较少丢失,⽀持多个⽣产者和消费者,常用于大数据平台; 不⽀持批量和⼴播,⽂档⽐较少, 运维难度⼤,需要掌握Scala
RabbitMQ:Erlang语⾔编写,易⽤性、扩展性、⾼可⽤性等⽅⾯表现不错 源码不容易被掌握
RocketMQ:纯Java开发,具有⾼吞吐量、⾼可⽤性、适合⼤规模分布式系统,⽀持海量堆积, ⽀持指定次数和时间间隔的 失败消息重发,⽀持consumer端tag过滤、延迟消息 新组件资料较少
1.2、发送方式
SYNC同步发送:短信、邮件
ASYNC异步发送:回调成功触发后续流程,下单通知到ERP系统
ONEWAY⽆需要等待响应:耗时短可靠性低,收集日志、操作习惯等
发送⽅式 |
发送 TPS |
发送结果反馈 |
可靠性 |
同步发送 |
快 |
有 |
不丢失 |
异步发送 |
快 |
有 |
不丢失 |
单向发送 |
最快 |
⽆ |
可能丢失 |
延迟消息:Producer将消息发送到消息队列 broker,不希望马上消费,而是等待某个时间点后销消费;--路由信息到上班节点发送
1.3、顺序性、避免重复消费、可靠性
顺序性:消息生产与消费顺序一致;全局有序(较少使用)/局部有序(一组数据被顺序消费,性能高);--订单路由信息;
原理:顺序生产:⼀个topic下⾯有多个queue队列,同个业务id放置到同个queue队列⾥;
顺序消费:使⽤MessageListenerOrderly单线程消费,集群消费时锁住正在消费的消息队列;而不是使用多线程的MessageListenerConcurrently消费;
无法广播,无法异步否则无法严格保持顺序,不能多线程;
避免重复消费:业务实现,redis去重(消息ID,setNX()存在/Incr自增1存在),数据库设计去重表(消息ID做唯一索引)
幂等性:⼀个请求,不管重复来多少次,结果是不会改变的
可靠性:producer端:不采⽤oneway,使⽤同步或者异步⽅式;做好重试,但是重试的Message key必须唯⼀;保存关键日志信息(关键字段,投递时间、投递状态、重试次数、请求体、响应体);
broker端:多主多从架构,多机房;同步双写、异步刷盘 (同步刷盘消息不丢失,可靠性更⾼,但是性能差点,根据业务选择) ;
consumer端:处理完消息后,调⽤ack告诉消息队列消费成功;幂等性处理;保存消费日志信息;
1.4、消息堆积(恢复消费/更快速度去消费,需要4步)
1、Consumer不消费问题:若不消费,则使其恢复正常消费,根据业务需要看是否要暂停;
2、增加Consumer数量:临时topic队列扩容,并提⾼消费者能⼒,增加Consumer节点;
3、临时分发程序:若堆积仍多且数量固定,则从旧topic读取到临时新topic中,新topic的queue数量必须扩容多倍,多个Consumer节点快速消费;--一般queue数量要大于Consumer节点数量
4、堆积消息处理完成后,恢复正常数量,再次检查逻辑或服务;
1.5、延迟发送,二次确认
broker中有多个不同topic分片,每个分片中有多个同一topic的queue; topic在每个broker中都有1个分片,分片中有多个queue;
NameServer-路由注册中心,Broker-消息存储服务器; Broker每30S心跳到NameServer;NameServer每10s清除120s心跳Broker,更新topic的路由信息;Producer每30s去获取路由信息;
broker中保存 提交日志文件、磁盘索引文件、消息消费队列;
重复问题:消息重新发送、消费异常;消费进度本身的不及时;拉取异常后的重新拉取;
MQ的ack机制:重新投递retrytopic,重试多次到死信队列;以group+queue来管理offset消费进度;拉取消费组,从尾/首/某时间点开始消费,只回传最小offset值;卡必消费成功位置;
节点node-索引index-分片shard/type-文件document
写流程:选择某node节点发送请求,节点会根据路由算法转发到主分片,主分片处理完毕再同步备份分片; 路由算法shard=hash(routing) %取余数 number_of_primary_shards索引下主分片数量
原理-近实时搜索refresh是:先写到内存中,同时写translog;每隔1s读取内存创建新阶段,新阶段先写入缓存,再写入磁盘;缓存数据可以直接被查询;flush实现磁盘持久化;
读流程:类似上述流程,只是读是会在 主分片 和 备份分片 之间随机轮训的去读取;
lucene:倒序索引算法;一词对应多文档;字典顺序生序;
translog:事务日志,针对的缓存与内存数据;flush持久化时清空,建磁盘+1log文件;索引文件和日志文件各有一份,冗余; 事务数,偏移量,log号;
1、高并发系统-系统拆分、用redis缓存、MQ交互、分库分表、读写分离、ES
分布式锁:数据库锁方法名建唯一索引;redis的set的key-value-expire,key是业务方法的,value是当前线程单据,解锁时判断value;
2、亿级数据查询
数据库--建立索引,存储过程,
分库-因表多而数据多,根据业务模块,将库拆分成不同的数据库;
分表-单表数据多,拆分表,垂直拆分--拆分字段;水平拆分--按业务按年月去拆分,按照面试官说的业务去拆,mycat中间件;
缓存--使用redis,
搜索引擎--使用ES,canal来伪装成从库线程读取binlog更新ES
3、netty
NIO:IO多路复用/非阻塞IO,用一个线程兼容做下述3件事情;BIO-Accept连接请求、读操作请求、写操作请求,都会等待阻塞;
Netty:网络应用框架;封装了JDK的NIO,提供了高性能的客户端与服务器端;Accept连接请求是一个线程,读写操作请求是另一个线程;
Dubbo的服务提供者、消费者和性能统计节点之间使用 Netty 进行异步/同步通信; RocketMQ 的消息生产者和消息消费者之间也采用 Netty 进行高性能、异步通信;
zab:恢复模式与广播模式;
zk选举流程和同步策略:初始流程-服务器LOOKING状态下,每个服务投票vote(sid, ZID)和自己的self()比较,先value后key取大发出去;Leader变Leading,Follower变Following状态; 新节点/宕机不影响,leader挂了才影响会重选;非观察者全转LOOKING状态; 初始轮次+投票,接收投票 轮次和pk票,变更投票 统计,更改状态; Observer不参与投票和事务提交,提高读性能;
zk基于zab:过半机制+leader提交事务广播到所有follower;quorumPeer.start()磁盘读数据+上下文+选举;run方法有makeLeader()创建;leader.lead()创建StateSummary标记最新事务和提交次数+与Learner单线程长连接+LearnerHander监控新节点;followLeader方法-
Follower.
registerWithLeader()建立长链接5次+
syncWithLeader()去同步数据-清空/删除无效;
TCP4层:网络接口层(物理+数据链路)、网际层、传输层(tcp、udp)、应用层(+会话+表示);
rpc远程调用的服务治理框架;节点间的服务请求;客户端将参数转字节流传给服务端操作再返回结果,涉及到序列化等问题; SOA思想-一个中心同一规范去处理或监控多个系统;
默认dubbo协议,支持http、hessian等协议;以zk、redis做注册中心;已经停止更新; spring-cloud以Eureka注册中心,仅支持http; 通信框架是netty框架;
Hessian:基于http-post,类似于http+自己的序列化,它着重数据仅带简单类型标记,文件小;java序列化-数据、类、继承关系等全部字节流序列化;
默认重试2次;tries+timeout+服务端处理业务;
dubbo原理:解析服务-类似Spring加载bean到容器,解析xml中dubbo标签加载成bean对象转化成url的参数传给protocol节点;暴露服务-通过RegistryProtocol类的export方法先将ip端口+url传到注册中心,再同步到protocol节点暴露服务;引用服务-通过RegistryProtocol的refer查询url并获得提供者引用;消费节点的zkRegistry的saveProperties会缓存全量URL,新服务不行;消费-通过ReferenceConfig的init方法调refer方法生成invoke实例来获取接口;
负载均衡:实现loadbalance接口继承*类,doselect方法,getWeight获取权重方法;随机数/轮训次数/活跃度数组等;
dubbo生产消费,通过xml中,配置
retries 再重试次数/cluster 失败后操作-failfast报错、failsafe忽略等实现容错;
配置loadbalance实现负载均衡
等,默认romdom随机,基本没人修改,还有 权重轮训/hash/最小活跃等;
容错与负载均衡:权重随机-大量均匀/轮训-慢服务卡积累/最小活跃数-调用前后计差越慢越靠后越少/一致性hash-参数一致调同台 服务挂掉去平分;
失败切换-查,失败报错-写;失败忽略;并行调用等单返回;retries/Cluster/forks/LoadBalance
标签:reference id声明服务;service ref引用服务;protocol 协议声明;application应用声明;provider超时声明;
监控:dubbo-admin,可视化页面搜索服务,查看生产消费者信息;
常见问题:No provider available/check registry--服务提供者挂了,或者version没对应上;启动时检查依赖可用,否则报错;Data length too large--返回数据太大,加条件而不是改payload;父子类同名变量覆盖--Hessian去重;