配置中心、消息队列、分布式服务链路跟踪

配置中心

配置中心定义

配置中心目的

配置中心选型

开源配置中心

选型对比

配置中心是AP模型?

比如将超时时间从100毫米修改为200毫米
1秒后生效还是1分钟生效都没有关系
无非是用户体验的问题

1秒之后还是多久之后 这是准实时
非实时(没有延迟)

最好方案:携程阿波罗

用阿波罗的公司

基础模型

配置中心首页

添加/修改配置

客户端获取

通过注解方式也可以获取

核心概念

新建集群

添加namespace

获取自定义的namespace

添加配置项

逻辑架构图

Eureka通过ZK进行调度

1、用户访问Web管理页面(Admin Service服务) 修改配置
2、Admin Service renew通知ZK(即创建一个文件)
3、Config Service监听ZK(即监听这个文件)
4、Config Service获取最新配置缓存到本地
5、Config Service通知Client 让它获取最新的配置
6、Client从ConfigService获取最新配置

实际部署会将Config Service、Eureka、Meta Server放在同一个JVM进程中

JVM进程 无状态 冗余部署很多份

一个机房部署一个JVM进程;不同机房连接同一个数据库

为什么选择Eureka

阿波罗客户端实现原理

伪长连接

不同场景的可用性

自研配置中心思路

  • 需求

APP粒度即项目粒度

  • 参考架构
用Redis的服务发布订阅也可以

小提示

1、阿波罗不支持加密
可以通过配置中心对配置加密
在客户端解密的方式实现
2、心跳实现方式:tcp长连接、ping、发包

消息队列

定义

应用场景

消息队列模型

  • 订阅主题

一对多

  • P2P

一对一

消息队列组成

1、
Producer:MQ Client
Consumer:MQ Client
Broker: MQ Server

2、所有的mq支持的通讯协议都是tcp

传统协议(基本不会用)

1、开源的IM都是基于XMPP协议
本质基于XMIO协议 比较大 基本上不太会用

2、自定义协议比如二进制私有协议
qq微信都是基于二进制协议(高效、基于tcp socket传输)

消息队列设计考虑点

高级特性设计

1、大部分mq发送方不需要去重
2、kafka 分布式事务中会保证去重
3、rocketmq、rabitmq 只保证至少发一次
4、a、主动去拉: 轮询(Long Polling) 基本所有mq都是这种方式
   b、长连接: mq server主动推

开源MQ技术选型

  • RabbitMQ
  • ZeroMQ、ActiveMQ
rabbitmq 用的不多
zero mq 业界用的也不多
  • Redis、Kafka
redis 数据量大的时候入队列很慢
kafka 高可靠 偶尔丢1、2条没关系 比如日志
  • RocketMQ
1、原生版本对时序消息的高可用保证不好 一旦其中一台挂了 就不可用了
2、基于开源做高可用方案
3、在rocketmq中堆积上亿消息没有任何压力
  • NSQ
不支持有序消息
  • beanstalked
不足以称为工业级产品 因为有单点故障
优势是支持任意时刻延迟消息

RocketMQ架构

1、broker就是server端
2、一组broker中有主从节点
3、NameNode根据topic名字拿到消费者列表 让消费者监听消费 
4、消费者监听的是Master Broker

开源版本仅支持主从模式 不能主从切换

1、一旦主broker挂了 从broker并不会提升为主;主挂了 就没有办法消费了
2、slave仅仅做backup 消费方也是从主上消费数据
3、对于任何一个topic至少有2个broker

对非时序消息

对消息的写入顺序没有要求的

1、broker1所在服务器是ip1,borker2所在服务器是ip2,ip1和ip2都注册到注册中心
2、客户端通过注册中心选择borker1进行写入消息 通过Master Broker写入 比如里面有1000条消息
3、如果broker1中的Master Broker挂掉了
4、客户端只消费了900条消息 还剩100条没有消费
5、注册中心将broker2作为写入节点 在broker2中的Master Broker中继续写1001...
6、等broker1中的Master Broker重启了之后 客户端再消费剩下的100条数据

存储模型

1、消息队列服务存的是每个消息对应的偏移量和大小

2、commitlog是磁盘文件

3、类似于commitlog的index(包含offerset)

4、读取队列 拿到索引 通过索引到commitlog找到消息

5、写commitlog完全是顺序写

通过MMap内存映射实现CommitLog和消息队列Consume Queue完全一致

MMap:一块硬盘 完全映射到内存中 写内存即是写磁盘

刷盘策略

  • 异步刷盘
机器重启 消息可能会丢失
  • 同步刷盘
防止数据丢失 性能会受影响
磁盘SSD 性能还可以的

严格时序消息如何保证高可用

单机单线程 Master-Slave模式 如果Master挂了 会发送失败,同时也不能消费
RocketMQ自身高可用方案
自研方案

开源版本不支持主从切换,基于开源版本,如何让其支持高可用?

1、三个nameserver调用zk的create创建文件接口 谁创建成功谁就是主 将该文件放到主节点的namespace下面 2个从节点监听该文件
2、broker监听zk就知道了哪个nameserver是主节点
3、broker主从心跳上报给nameserver主节点
4、nameserver主节点数据同步给其他2个从节点
5、broker主从是在配置中配的
6、broker主挂了
broker和ns心跳就没了 就知道它挂了
ns下发命令 将broker从变成主
7、ns主将新的broker主同步给其他的ns从
客户端就会获取到新的broker主
客户端直接写到新的broker主
8、如果ns主挂了
它的ha是由zk保证
9、3个ns 创建文件 其中一个创建成功
另外2个从ns watch这个文件
如果主挂了 文件也会消失
另外2个从会再创建文件竞选主节点
10、每一个ns 都会注册到zk上
ns主从zk上获取还有几个从节点
然后再定期推送给从节点
11、ns主从是通过zk写文件方式实现
broker主从通过ns主选择
12、ns之间没有强一致性协议
broker主从切换了之后 心跳给ns
ns主通知ns从 tcp接口通知
可能会出现路由信息短暂不一致
ns主同步其他2个从 最终一致性

RocketMQ物理部署

很多rocketmq集群共用一套nameserver

消息可靠性

1、发送失败 写错误日志 报警
2、消费失败 可以基于某一个id进行回溯 因为消费offset保存在本地或保存到broker中
3、rocketmq 用的是netty nio模式
4、rocketmq是long pulling拉模式做的
5、topic 模式 下游全量消费
队列模式 下游是随机的 连上来消费一个 
6、如果主从网络挂了
刷盘策略 可以同步或异步
异步也没关系 网络挂了 从同步数据有延迟
若开启同步强一致性
主刷到盘上 再同步到从上
7、一主一从tps可达到上万
8、客户端消费 不需要关注负载均衡
客户端只要去连server ,server就会顺序分发
9、topic下面有group群组概念
一个topic允许多个服务监听
比如a服务有5个节点 能保证a服务的其中一个节点能消费到

分布式请求跟踪系统

微服务现状

微服务请求调用路径

解决方法

开源产品

1、cat更多是监控 不能算分布式请求跟踪系统
2、SkyWalking(APM) 应用程序管理 不仅仅是分布式请求跟踪系统
3、pinpoint 是韩国搜索门户开源

设计需求

1、通过javaagent拦截器start(事前拦截器) end(事后拦截器)方法(AOP)收集metrics 对业务无感知

2、日志生成好之后 放在hadoop中 再进行并行的海量日志的分析

3、每次请求都生成全局唯一的 请求层次和深度

设计目标

使用场景

调用链跟踪

  • 一次调用耗时
  • 多次调用链路分析
  • 日/月维度统计分析

调用链路分析

在回归测试的时候不需要测试全部链路 只需要测它依赖链路就好了

调用来源分析

调用链路统计

监控请求调用量

可以通过正则表达式来指定要监控的接口路径

架构设计

1、应用节点要引入jar包进行收集
对应用程序本身极小侵入为好
2、metrics 本地socket即UDP进行通讯
3、trace日志收集agent实际上是一个golang程序
4、先收集到本地 1分钟再发往集群
减少应用程序节点和集群节点之间通讯次数
5、trace服务器只需要对数据流做格式化处理
分三个工作流进行处理(汇总、重组调用链、es实时请求耗时(不需要分析))
6、hadoop通过mapreduce进行日志分析
7、页面数据分析 一天总体耗时 通过离线方式计算出来
8、trace数据实时分析 spark streaming、flink(推荐)来做的

最关键id如何生成

1、请求链唯一标识 (TraceID)
2、时序标识(SequenceID)
3、深度标识(DepthID)
1、进程内传递 在request请求包中

2、定长header + 变长body
请求的唯一标示放在定长header中

2、时序id只和当前节点有关系和其他节点没有关系 可以放在本地threadlocal中

ID体系设计

在网关调用的时候 时序id记录在threadlocal中深度id会继承上面一个继续往下调用
点的个数其实就是深度
比如第一开始调用是0.1 接着是0.1.1 
首先是继承上层的0.1然后加.
时序从1开始

技术选型

链路采集一定会有丢失 UDP协议传输
对数据可靠性要求不高

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注