Neo's Blog

不抽象就无法深入思考
不还原就看不到本来面目!

0%

微服务系列-概览

单体到微服务

为什么要转向微服务架构(收益)

  1. 系统扩展性不足(例如,因为DB连接问题导致无法持续扩容)
  2. 迭代效率低。如果是预估到业务在飞速增长,那就别犹豫,一定要提前考虑微服务的拆分。
  3. 系统编译、部署成本高
  4. 如果在设计架构的时候,发现需要很多异构的技术栈,那也要考虑下微服务。

转向微服务架构需要克服什么困难(成本)

  1. 技术基础设施要求比较高(如果公司技术基础设施非常完备,对应的业务起初就设计的非常复杂,那么也别犹豫,起手就上微服务。)
  2. 工程拆分挑战比较大,实现时容易为了拆分而拆分。

拆分原则

从单体到微服务,也许可以有一个过度:工程的拆分

微服务拆分的大原则

  1. 单一服务内的高内聚、低耦合,单一职责
  2. 拆分粒度:先粗拆,后细拆(伴随业务复杂度的变多,或者对业务的理解程度加深)
  3. 拆分过程中,要避免影响业务的日常功能迭代—按照依赖顺序,挨个拆分
  4. 确保服务接口定义有可扩展性
  5. 避免环形依赖问题(通过分层,例如业务层、数据访问层)

业务优先,组织结构,质量维度

SRP Single Responsibilty 单一指责原则
CCP Common Closure Principle 共同闭包原则,包中包含的所有类应该是同类的变化的一个集合,也就是说,如果对包作出修改,需要调整的类应该都在这个包之内。

你的团队成员结构是什么样的,你的架构就会长成啥样。

团队按照业务边界来拆分;确保团队不要太大

因为微服务就是为了减少研发成本,而包括沟通成本。

服务拆分带来的问题

  1. 接口调用耗时增加
  2. 如何知道调用哪个服务?服务注册中心
  3. 服务治理体系:熔断、限流、降级、超时控制等
  4. 问题排查困难(分布式链路追踪)

微服务组件

API网关

入口网关:隔离客户端与微服务,协议转换、安全策略、认证、限流、熔断等

出口网关:调用外部API,统一认证,授权、授权、访问控制等

性能:IO多路复用、异步非阻塞、线程池

设计要点:性能、扩展性(责任链模式)

隔离性:针对接口对线程池进行分类

服务注册与发现

zookeeper, consul, euraker

负载均衡

RoundRobin, Hash, Weight

熔断、限流
配置实时下发
客户端

配置项的读取-变更推送如何实现:

  1. 轮询 + 摘要 (简单,实时性略差)
  2. 长轮询 + 版本号(复杂,实时性好一些)

client的高性能实现逻辑:

  1. DoubleBufferedData, 数据分前台和后台
  2. 读拿到自己所在线程的thread-local读写锁,执行查询逻辑后释放锁。
  3. 同时只有一个写:修改后台数据,切换前后台,挨个获得所有thread-local锁并立刻释放,结束后再改一遍新后台(老前台)。

一个小原则:配置系统的旁路化,不要因为配置系统挂了,你的程序启动不了;
可以做两层缓存:内存缓存、文件保存

服务端

不同的配置类型:节点类型 》机房类型 》 全局配置

配置项的存储-配置系统的高可用

核心指标在于可用性!!!5个9?

对接调用链追踪 (Jager)

trace_id + span_id来标识链路的调用关系。

对trace_id采样,而不要随机采样。

span 基本工作单元,一次链路调用(可以是RPC,DB等没有特定的限制)创建一个span,通过一个64位ID标识它,uuid较为方便,span中还有其他的数据,例如描述信息,时间戳,key-value对的(Annotation)tag信息,parent_id(基于parent_span_id来维护树形结构)等,其中parent-id可以表示span调用链路来源。

trace_id 类似于 树结构的Span集合,表示一次完整的跟踪,从请求到服务器开始,服务器返回response结束,跟踪每次rpc调用的耗时,存在唯一标识trace_id。比如:你运行的分布式大数据存储一次Trace就由你的一次请求组成。

Annotation 注解,用来记录请求特定事件相关信息(例如时间),一个span中会有多个annotation注解描述。通常包含四个注解信息:

监控系统

监控哪些内容

监控系统架构

方案:普罗米修斯、Graphna

APM:端到端的监控体系

如何防止消息被篡改:对消息体 + 消息头 进行加密,生成一个签名
如何对数据进行加密:

使用非对称加密的公钥对 “对称加密的私钥-OriginPrivate“ 进行加密,得到SecretPrivate
然后服务端利用非对称加密的私钥,对 SecretPrivate进行解密,得到OriginPrivate

然后再使用OriginPrivate对加密之后的消息体(SecretContext)进行解密,得到Contenxt

监控哪些东西:网络卡顿率、做某件事情的失败率等

考虑暂存 + retry来应对网络状况不佳的情况

自动化全链路压测系统

压测的原则-尽量模拟真实情况;压测的注意点:
(1)使用线上数据与线上数据
(2)使用线上流量(流量拷贝)
(3)流量应该从尽量靠近用户的CDN发起

如何搭建:
(1)流量的隔离(区分压测流量与正式流量)
(2)风险控制(尽量避免压测对正常用户的影响)

自动化全链路压测系统

压测数据的产生:
拷贝真实流量(可以从访问日志、可以抓取某个端口的数据等)
打上压测标签
放在合适的机房(尽量接近用户)
数据隔离:
针对读请求,针对某些不能压测(例如推荐、数据分析等)的组件进行mock
对于写请求,把流量产生的数据写入影子库(数据库-拷贝一份库表和数据;缓存-加压测前缀;ES-多搞一份索引)
压力测试的实施
持续放大,做好系统过载的识别(例如超时率、resp time等)

你的支持是我坚持的最大动力!