AKF扩展立方
X轴扩展
在负载均衡之后运行应用的多个拷贝。这是最简单最常用的扩展方式。
缺陷:
- 每个拷贝需要访问所有的数据,对缓存机制要求很高,数据库很可能成为瓶颈。
- 不会减少日益增长的开发复杂度。
Y轴扩展
把整个应用切分为不同的服务,每个服务负责一个或少量几个关系相近的函数。
有好几种解耦拆分方式。一种是按照动词分割,一种是按照名词分割。
以购物网站为例:按照动词分割就是按照操作分割,服务1只负责购买流程,服务2只负责售后流程,服务3只负责广告投放流程;
按照名词分割就是按照对象类型分割,服务1只负责商品信息;服务2只负责用户信息。
两种扩展经常是同时使用的!
微服务化就是Y轴扩展的一个重要方式。
Z轴扩展
Z轴扩展和X轴扩展很像,但是在Z轴扩展中,每个服务只跑特定的一部分代码或数据集。
Z轴扩展一般用来扩展数据库。(数据库分片)
在做某些查询的时候,查询指令被送给每一个分片,然后分别查询,最终获得的结果聚合之后返回。
做写入的时候,只需要按照分片键,找到对应的实例进行写入即可。
Z轴扩展的优势:
- 每个服务器只处理一部分数据
- 优化了缓存的利用率,减少内存使用和I/O
- 增强了事务的扩展性
- 故障隔离
劣势:
- 增加了整体的复杂度。
- 需要实现分片机制。万一有重新分片的需求的话,令人头大。
- 增加复杂度的同事,并没有降低开发的复杂度,这个需要Y轴扩展配合解决。
SOA
英文全称:service-oriented architecture,这不是一种特定的技术,而是一种分布式计算的软件设计方法。它是一个组件模型,它将应用程序的不同服务通过这些服务之间定义好的接口联系起来。接口是采用中立的方式进行定义的,通用性高,可以独立在不同的硬件平台、操作系统和编程语言上进行使用。这使得构建在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。(引用维基百科)
以下指导原则是开发、维护和使用SOA的基本原则:
- 可重复使用,高交互操作性。
- 通用的匹配开放标准,对各厂商的产品兼容性高。
- 服务的识别和分类,提供和发布,监控和跟踪
传统微服务(Micro-service)框架
问题
- 语言碎片化
字节跳动的在线服务编程语言比较分散,除了常见的Go和Python之外,还有Node.js, C++, Java, Rust, R等语言。
我们知道,要实现一个完善的微服务框架,需要有服务发现、负载均衡、超时控制、熔断、限流、访问控制、并发控制、流量调度等复杂的功能。
在微服务框架体系下,这些功能需要使用每种语言实现一遍,这将会导致巨大的开发成本和维护成本。
而由于语言本身的差异,各种服务治理规则无法完全对齐。
譬如:
- 以Python的进程模型,很难提供并发数限制的能力
- C++的流量分流策略与其他语言不一致
- 更新困难
推动用户升级框架往往是一件非常困难的事情,用户有可能还会持续使用你一年一前发布的框架代码。
当某个框架版本发现重大Bug的时候,要推动相关服务升级到修复后的版本是一件非常困难的事情。
当需要推动一个全链路新功能的时候,譬如自定义分流,我必须推动整个链路的上下游全部升级,才能最终把整个功能上线。
假设推动了一半业务升级后,又发现了一个严重的Bug,那将是一场噩梦! - 协议多样化,难兼容
对于RPC来说,Thrift的不同版本之间是不兼容的,Thrift和FBThrift有一定的差异;
线上的流量是HTTP, Thrift, gRPC, MySQL等协议并存。
流量的协议不一样,但很多流量管理的需求却是类似的,如超时配置、跨机房流量调度等,开发者很想对不同的协议施加统一的管理能力。
当然,以协议本身的复杂混乱程度,仅靠服务化框架是很难统一管理的。 - 服务治理消耗巨大
以Python为例,Python是一种解释性语言,它的性能是向来被人诟病的。上述超时控制、熔断、限流等一系列服务治理规则用python实现一遍,资源消耗非常高。
一般地,python服务中,用于处理各种服务治理部分的CPU消耗,占总CPU消耗的50%以上。 - 业务侵入性强
框架向业务程序注入了很多与业务无关的代码。
业务开发者在分析自己的服务的时候,可能会发现有很多服务治理相关的并发线程,对于业务的研发和性能优化有很多干扰。
头条service mesh
背景&目的
传统微服务架构问题
- 各语言框架, 服务治理策略各自开发,导致重复开发、策略不一致问题
- 已有框架的迭代更新受限于业务的配合程度,迭代更新困难
- 服务治理策略迭代和新功能支持受限于架构和更新速度
- 不支持多语言、多协议,无框架语言无法使用架构组提供的基础服务
- MySQL, 81nginx等SaaS服务希望使用微服务框架的部分能力
目的
- 服务框架与业务解耦,框架的升级完全自主可控,不再依赖业务方
- 多协议支持且可扩展,最大化框架的覆盖度
- 统一、中心化的服务发现和治理方案,与语言和框架无关
- 业务可灵活自定义服务发现、服务治理规则并快速应用到线上
- 统一的监控、告警、日志和tracing解决方案,为智能运维系统提供支持
- 与现有服务框架的兼容、平滑升级
- 支持新的RPC框架和SaaS(MySQL, Redis, HTTP)等快速、低成本接入和平滑迁移
- 支持线上、线下等多套环境,方便服务的开发和线上测试
市面上mesh分析
- Istio架构分析
- 蚂蚁金服SOFA Service Mesh分析
- 京东Service Mesh分析
- ucloud的Service Mesh分析
架构&设计
总体结构
- Client SDK
提供给Service Mesh的使用方,以SDK的方式集成于业务代码或直接作为工具使用,来获得Service Mesh平台的服务能力。与用户业务紧耦合。 - Control Panel
以Web服务的方式提供给使用方,供业务方对基于Mesh的服务进行服务治理操作。通过统一抽象和灵活定制,与业务方的业务逻辑松耦合。 - Monitor Panel
基于与公司现有监控、告警服务的整合,提供在Service Mesh场景下的服务监控、日志、tracing等能力 - Data Panel
请求代理转发,应用Control Panel的服务治理规则,为Monitor Panel提供数据
数据流
头条service mesh系统整体架构
- Mesh-Proxy
- 提供流量代理转发功能
- 支持多协议,协议插件化
- 通过过滤器, 实现服务治理策略
- 支持监控统计、tracing、ACL
- Control Panel
- 将来自MS服务治理平台的控制数据转换为Mesh-Proxy的规则数据并存储至ETCD
- 定期备份ETCD/Consul中的相关数据,用于对ETCD/Consul的fallback
- 定期与其它机房的Data-Control Server进行数据同步, 应对跨地区请求
- 为MS platform的服务治理提供数据源
- MS platform
- Service Mesh服务信息管理界面
- 提供熔断、限流、降级等服务治理配置界面
- 提供tracing界面
- 提供日志检索界面
- 元信息服务
- 提供一个Service Mesh服务部署所需要的所有信息: 基础配置、镜像配置、k8s POD配置等
- 提供服务的配置信息,包括服务所使用的框架、协议、部署地区、环境类型等, 用于流量调度和服务升级状态查询
mesh proxy
- Input Transcoder
协议分为Transport和protocol, 此处仅关注Transport层协议
请求协议转换模块, 提供对不同请求协议的支持。只要这些协议能提供用于流量调度的基础信息及用于服务治理、智能运维(日志/监控)相关的可选信息,均可以作为Mesh-Proxy的输入请求。
当前支持HTTP1.1/2、raw Thrift(Pie/Kite框架使用)、raw TCP(MySQL、Redis等使用),也可支持扩展协议。 - Input Queue
输入请求队列,用于抽象不同协议经转换后的消息。消息的结构为: 路由信息+服务治理信息+日志/监控信息+业务数据。
通过请求队列,支持Mesh-proxy作为ingress proxy时对后端服务的过载保护
当请求队列满时,可以反馈给主调方减小调用流量 - Route
路由模块, 基于请求中的路由信息,与服务发现模块交互,查找备选的目标cluster列表和endpoint列表。
对于ingress proxy, 直接将请求路由至本地后端服务。 - Service Govern
根据route中的目标cluster列表和endpoint列表,结合服务治理策略、负载均衡策略选择本次调用的目标地址。将请求添加目标地址后放入Output Queue - Output Queue
输出请求队列,用于缓冲待发送的请求
与目标服务的Mesh-Proxy的Input Queue配合完成过载保护 - Output Transcoder
根据待发送后端的Transport协议,将Output Queue中的消息转换为目标协议并发送
对于新协议,通过插件的方法提供与现有协议的转换函数来完成适配
服务发现与治理
- Mesh Proxy
- 在proxy在服务发现和服务治理模块中,通过UDI(uni-data interface, 统一数据接口), 获取所需要的服务cluster信息、endpoint信息、load balance信息、service govern信息等
- UDI对外使用gRPC协议进行通信,并通过ETCD、Metrics、Consul、Log、MySQL-Auth等中间件与实际的后端进行通信
- UDI内部对不同类型的信息有内存缓存, 用于减少查询次数
- UDI支持在ETCD/Consul down掉时,自动切换至Data-Control Server进行查询
- 对于非本机房的查询请求,UDI直接请求Data-Control Server进行查询
- Service Discovery & Govern Config
- 服务发现、流量调度、负载均衡、服务治理相关信息由Control Panel提供。详细的接口和策略见”服务治理问题梳理和优化方案”
- Metrics和LogAgent用于收集日志和监控信息
- Control Panel
- 根据请求和调用方的信息,结合服务治理规则,给出被调的endpoints集合及相关信息,由mesh-proxy去应用
- 接收来自服务治理平台(MS)的服务治理规则并存储至ETCD或数据库(MySQL)
- 定期同步备份Consul/ETCD中的数据(用于容灾)
- 定期与其它机房的Data Control Server同步已备份的数据,用于跨机房请求加速和fallback
saas支持(mysql,81nginx)
- 对MySQL的支持
- 通过Mesh-Proxy filter支持MySQL的请求接管
- MySQL通过UDI+MySQL-Auth中间件支持MySQL的鉴权
- MySQL的统计、日志、tracing等功能复用框架提供的功能
- 对81nginx的支持
- mesh支持HTTP协议
- 作为python/golang HTTP服务的前置服务,以sidecar的方式存在
- 支持统一的metrics/log/logid
- 支持统一的限流(python和golang都存在大QPS下限制不住的风险)
HA
- control panel容灾
control panel是中心化的有状态服务, 依赖底层数据存储(MySQL, ETCD)和Consul服务发现。同时接受来自mesh-proxy的请求和MS服务治理平台的请求。- 数据层的容灾
(1) ETCD/Consul数据定时备份
(2) 出现故障时,由control panel接管服务注册和规则数据存储 - 服务层的容灾
(1) 多机部署提供水平扩展能力
(2) 多机房部署, 通过TLB进行切换
(3) mesh-proxy提供对control panel结果的缓存,当control panel挂掉时,缓存不再更新
- 数据层的容灾
- mesh-proxy容灾
本机mesh-proxy挂掉时,服务可通过动态配置,切换到其他机器的proxy
grpc & thrift
区别:
Grpc
- Grpc 是高性能,通用的开源RPC框架,基于HTTP/2协议标准
- Grpc 以protobuf作为LDL(接口描述语言),通过protoc来编译框架代码
- 支持 C, C++, Node.js, Python, Ruby, Objective-C,PHP and C#
Thrift
- Thrift是一种可伸缩的跨语言服务的RPC软件框架。它结合了功能强大的软件堆栈的代码生成引擎,以建设服务,高效、无缝地在多种语言间结合使用
- Thrift 以thrift 作为LDL
- 支持C、C++ 、C# 、D 、Delphi 、Erlang 、Go 、Haxe 、Haskell 、Java 、JavaScript 、node.js 、OCaml 、Perl 、PHP 、Python 、Ruby 、SmallTalk
- 使用Thrift:Hadoop、HBase、Cassandra、Scribe、LastFM、Facebook、 Evernot
什么时候应该选择gRPC而不是Thrift
需要良好的文档、示例
喜欢、习惯HTTP/2、ProtoBuf
对网络传输带宽敏感
什么时候应该选择Thrift而不是gRPC
需要在非常多的语言间进行数据交换
对CPU敏感
协议层、传输层有多种控制要求
需要稳定的版本
不需要良好的文档和示例