前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【服务治理】服务治理漫谈

【服务治理】服务治理漫谈

作者头像
吃橙子的狐狸
发布2021-12-06 15:50:23
2.8K0
发布2021-12-06 15:50:23
举报
文章被收录于专栏:橙子架构杂谈

【服务治理】服务治理漫谈

0. 前言

本文是服务治理领域专题的第一篇,并不希望也无法大包大揽将所有的点都覆盖到,更意在从一些更贴近我们实际工作的角度来进行更抽象层次的剖析,更多分享的是我认为重要或者有意思的一些方法论和逻辑推演过程。这能给我们后续无论是业务应用还是基础技术领域的服务治理提供一些参考。

1. 什么是服务治理

在一切的最开始,我们先来问自己一个问题,什么叫做服务治理?网上有很多关于服务治理的定义,维基百科也有着对应的定义。林林总总,有宏观的也有细节的。而在本文中,我尝试为其进行另一个维度上的简单定义:

服务治理,即以组织、业务和系统三者为核心要素建立连接,在此基础上实现服务系统的正向打通和逆向反馈。

1.1 三要素

  • 组织 组织即人。服务不可能独自存在,我们在进行治理的过程中,往往过度重视面向业务的用户体验,而会忽视掉在这个技术生态上另外一个非常重要的服务对象—技术人员。大家往往更专注于如何设计出一个高性能高可扩展的系统,而冷落了技术人员在这之中的诉求。一个良好的服务治理的判断标准,即要在服务好普通用户的同时,也需要让在这生态之上的技术同学得到归属感。
  • 业务 业务即产品。毋庸置疑,技术是为业务服务的。空谈技术本身没有意义。所以我们需要保持对业务敏锐的洞察力和前瞻意识,这样才能设计出一个演化式的合理服务架构。比如业务流量很低且还处于快速试错阶段,而你却上了一整套的高并发的解决方案,这就本末倒置了。大部分技术同学天然会有“秀技术肌肉”的冲动,这是正常的,但作为架构师,需要合理控制组织的欲望,结合业务实际进行处理,才能达到一个良好的服务治理的状态。
  • 系统 系统层面上,也即我们最常谈及服务治理时候会关注的点。如何做一个可靠、高性能、自动化、可扩展且能够快速迭代的系统出来响应业务的需求呢?良好的服务治理要求我们能够结合组织和业务实际,进行系统层面的控制。这样也是下列章节中会重点提及的内容。
在这里插入图片描述
在这里插入图片描述

如上图所示,三要素之间会相互影响,良好的服务治理能够让三者相互促进优化迭代,不合理的服务治理将导致三者相互拉扯、冲突,乃至降低士气和效率并影响最后的公司产出。所以服务治理,从来就不单纯只是系统、技术的问题,也涵盖着人和事情的要素。

1.2 系统层面的正向打通和逆向反馈

在系统层面的服务治理的范畴,相关的介绍有很多,比如业内享有盛誉的阿里开源框架 Dubbo(目前已入 Apache)中的相关图表的呈现:

在这里插入图片描述
在这里插入图片描述

可以看出在一个复杂的网络拓扑场景中,我们需要对这个服务网进行各种各样的治理,来确保这个网在技术层面能够尽可能地维持健康和有效。但如何去归纳我们到底需要什么样的服务治理呢?如下图所示:

在这里插入图片描述
在这里插入图片描述

在系统层面,我们认为:

服务治理其实是由流量的正向打通和逆向反馈所构成的一个环

正向打通,即如何将流量打通,这也是对于一个服务本身最基本的要求。我们于是需要思考:

  1. 如何做跨服务通讯,Rest 还是 Rpc ?序列化用 json 还是 pb ?能支持什么协议?是否支持多协议转换?
  2. 如何做服务注册/发现,用 Eureka、Zookeeper、etcd、Consul、Nacos?
  3. 如何做负载均衡,用软负载,还是硬负载?负载算法用 RR、Random、一致性哈希?
  4. 如何做路由筛选,捞一百个,还是 IDC 优先,还是类似 Envoy 这样的防恐慌机制或者干脆来个类似 Dubbo 的脚本花活?
  5. 如何做授权鉴权,是否需要 TLS,是否需要黑白名单,是否要验签,用什么加密算法,机器如何互信? ……

逆向反馈,则是代表我们如何基于各种基于流量进来后观察到的数据,来进行系统性地决策(一般是负反馈)我们的服务网需要做哪些事情才能让整张网持续处于健康状态。于是,我们思考,

  1. 如何扛住流量洪峰,削峰、限流?怎么限流?信号量、令牌桶、漏桶、固定窗口计数、滑动窗口计数、线程隔离?
  2. 如何正确处理异常,及时熔断?一键降级?级联决策关闭入口?
  3. 如何让系统可观察,监控、报警、分布式链路追踪?选择 Cat、Zabbix、Falcon、Prometheus、Zipkin、Skywalking?
  4. 如何提升资源效率,采用容器,Kvm?Docker?Swarm?K8s?Mesos?Openstack?
  5. 如何定义一个服务的健康度,SLA?RTO?RPO?健康度量模型? ……

2. 服务治理的发展史

我们都知道,服务的发展是由单块应用,服务水平分层,服务纵向切割,乃至后续微服务思想的兴起,**“两个星期”重构法则和“两张披萨”**团队等眼花缭乱的服务拆分方法论充塞你的耳目。这都是些常见的论调,但不是本章节阐述的重点。本章节更关注的是服务治理发展拆分过程中,所必然要面对的一个核心问题—“服务拆分后,之间如何产生联系?”也即:

如何形成复杂服务节点的网络?

限于篇幅,我们来简单回顾下针对该问题的几个重要思潮。

2.1 Server Proxy

在这里插入图片描述
在这里插入图片描述

我姑且称之为集中式代理阶段。该阶段也是最朴素的解决方案,多采用集中式的单点服务集群来承担较多服务治理的功能。比如集中式部署 Lvs、Nginx、Haproxy、Tengine、Mycat、Atlas、Codis等等,就是最常见的方式。这种方式的优势在于便于功能的集中维护,且语言无关,上手成本低,所以其实在大中小公司特别是创业公司里面拥有大量受众。但其带来的问题也很明显,以最风靡的域名+Http Rest调用 + Nginx组合套装为例,调用链路需要经过 DNS(DNS cache)、KeepAlived、(Lvs)、Nginx 几层。超长的调用链路路和多个单点系统,将会在服务规模上升时引发稳定性和性能问题。在丁丁租房和美团就多次发生类似的单点故障。丁丁租房曾经因为 Nginx、DNS以及 Codis-Proxy故障而导致过大面积的业务影响。美团的 DNS、MGW 等都遭遇过类似问题,其进一步因此而推出去内网Http调用转为Thrift直连的技术项目。总体来看,其必然有用武之地,其更适合初创公司,或者特别强调跨语言的应用场景,Server Proxy 都可作为一个快速上手的解决方案以供使用。但在使用时候,需要对其缺陷有着清晰认识以便于在后续演化中做出正确决策。

2.2 Smart Client

在这里插入图片描述
在这里插入图片描述

朴素直接的 Server Proxy 带给我们便利的同时,也带给我们大量的问题,而这个时候,为了应对这类问题,Smart Client 快速崛起并绽放出其强大的生命力。我们姑且称之为框架化阶段,该阶段为了解决 Server Proxy 所存在的单点长链路的问题,替代以直连的方式来构建两个节点之间的联系。这一步到位地解决了单点长链路的问题,且能够在直连的基础上,进行更大的性能优化和稳定性的抬升。代表开源产品(服务框架 or Rpc 框架)有比如 Uber 的 Ring-pop、阿里的 Dubbo、蚂蚁的 Sofa-Rpc、当当的 Dubbox、微博的 Motan、点评的 Pigeon/Zebra、百度的brpc/Stargate、Grpc、Thrift等。大的思路即两个:

  1. 硬的不行,那就转为软的。硬件式的服务治理行不通,那么就转到软件式的服务治理。
  2. 远的不行,那就转为近的。远端集中式部署的方式行不通,那么就拉到和我应用进程里面部署。

如此一来,Server Proxy思潮中的诸多弊病就被一一化解了。

鼓吹了很久 Smart Client 的优点,那他不存在问题吗?必然还是存在的,而且问题也十分明显和突出。

  1. 第一方面,我们知道,微服务领域的气质是趋向自治的。Smart Client 也被成为富客户端,而采取这种方式将很严重地限制我们在技术栈上的选择,换一个语言就需要重新实现一遍基本所有的治理能力,及其之后带来的多套语言下成本增长的维护升级成本,这个对于绝大部分公司来说都是难以承受的负担。Uber 不得不针对 Ring-pop 推出 node 和 go 版,微博的 Motan 也推出了多个语言版本,Grpc、Thrift也没能逃出这个命运。而现在大部分的公司都会混合两种以上的语言进行实际的开发。所以这个问题也必须要进行正视。
  2. 第二方面,Smart Client 采用重 SDK 的方式嵌入应用进程进行共存,这将使得服务治理的运维工作和业务应用的维护完全搅到一起。这在现实的工作场景中,给服务治理的运维难度抬升了几个量级,服务治理团队不得不被迫面对多个版本并存的架构代码,以及推行一个版本可能需要半年以上的噩梦。

当然,尽管有以上问题,但是由于目前没有特别成熟的替代方案,Smart Client 目前仍然在高并发大流量的业务场景中占据着主流地位。如果语言能够尽可能收敛的场景也可以使用,比如可以采用 Java 版的 Smart Client,并对于不高的Nodejs流量采用Http Rest 加上域名的方式来做折中的服务治理。

2.3 Local Proxy

Server Proxy 和 Smart Client 都有着无法回避的问题,那么还有其他的解决方案吗?为了回应这一个问题,Local Proxy 应运而生,既然集中式部署有单点问题,富客户端又有耦合的问题,那么为什么不取一个折中呢?这时候的思路就变为:

就近进行进程级别治理。即采用本地进程级别代理的方式,既可以规避集中式单点部署的问题,又可以回避语言相关和应用耦合的问题。

这个思路开始逐步风靡,非常多的治理方案也在这个思想下如雨后春笋冒出。 airbnb 的 SmartStack 采用了四件套完成了整个核心的服务串联治理过程,是一个朴素解决方案。

在这里插入图片描述
在这里插入图片描述

而携程 OSP 也采用类似方式来进行处理,和 airbnb 的差别主要在于将 Synapse 和 Haproxy 的功能整合为了一个 Proxy 来替代。

在这里插入图片描述
在这里插入图片描述

在云领域里面,由于跨语言和运维效率被放在了更为重要的角度来审视,这种思想更是占据了主导的地位,Mesos+Marathon的云架构中,也有类似方案,采用Haproxy进行路由,中控节点会刷新对应的路由信息。

在这里插入图片描述
在这里插入图片描述

Google 亲儿子 K8s 也是如此,考虑到了 Proxy 的性能问题,进行了折中处理,采用 Iptables 规则注入的方式进行转发(当然,这种方式也有不可回避的问题)

在这里插入图片描述
在这里插入图片描述

这些方式都有其对应的问题,但是最大的一个问题即:

如何解决其带来的性能下滑。无论 iptables 或者采用 agent 来进行治理、转发、通讯,都会面临着一个绕不过去的问题,在高流量高并发的场景下,其对性能的损耗有多少?相比于众多已经装备有富客户端直连的应用来说,性能的差距有多大?目前已知的部分产品,在高流量下QPS和RT都有着不小的损耗,有的解决方案甚至能够达到20%的性能损耗,这明显在很多场景下是无法接受的。

这时候,Local Proxy 的最后一个杀器 — Servicemesh正式被推上风口浪尖,2018年也被称为 Servicemesh 元年。我认为,其理念如下:

在这里插入图片描述
在这里插入图片描述

1. 牺牲一定的性能和资源,换取服务治理理整体的⾼高度⾃自治和可运营 2. 执⾏行行和控制分离,数据平⾯面和控制平⾯面切割 3. 虚拟化、标准化、产品化,定义规范。

Servicemesh 从杂乱无章,百家齐放的 Local Proxy 思潮中解放出来,提出了更系统地思考。本文无意对 Servicemesh 做更多概念性的描述,网上已经有相当多类似的文章,此处限于篇幅不展开。于是,有多家巨头合作的 Istio(其本来目的是为了帮助应用更好地上云)的珠玉在前,其他公司也纷纷基于/参考Isito做出自己的解决方案:

  1. 阿里基于 golang 重写了 Envoy 并在这基础上构建了 Sofa-Mosn/Pilot,
  2. 下沉了 Istio 中颇受诟病的 Mixer 的限流能力,
  3. 腾讯基于 Envoy 进行改造整合内部的 TSF 服务框架,
  4. 美团基于 Envoy 改造整合内部的 Octo 服务框架,
  5. 微博基于 Motan-Go 研制出 Motan-Mesh,整合了自己的服务治理体系,
  6. 华为的 ServiceComb 也是类似的做法, Mixer完全下沉,
  7. Twitter推出 Conduit,基于Rust,也将Mixer完成下沉,
  8. 猫眼参考了 Envoy/Sofa-Mosn 的架构,自研了Maoyan-Mesh。 ……

但是,Servicemesh 仍然有几个问题没解决,除了仍然绕不开的性能问题外,目前也有越来越多的人在进行mesh反思一个问题:

控制面板和数据面板切割的标准是什么?是不是过于理想化了?

这个问题目前见仁见智,此处不展开。虽然 Servicemesh 目前还在起步阶段,很多问题也还在摸索中,但是从微服务领域发展的趋势来看,上文所述的 Servicemesh 的三个理念与其不谋而合,必然是未来的大势所趋。

2.4 总结

这一章回顾了服务治理的发展历程,经历了三个大阶段的思潮,我们回归初心,可以看到每个阶段的方案其实都有其适用和不适用的场景,没有最好的方案,只有最合适的方案。我们也可以沿着这三个阶段的思考逻辑发现,其实对于服务的治理,也是处于一个反复摸索、纠结,螺旋上升的过程。

3. 我们需要什么样的服务治理

我们了解了什么是服务治理、服务治理是怎么演变发展的,这时候,我们不禁会想,我也要做服务治理!但是,请先停一下,请先问一下自己,我们需要什么样的服务治理?

这个问题很好回答,同时也很难回答。简单来说,这取决于三要素的发展现状。取决于你的组织、业务和系统的健康度、匹配度和成熟度。但这个形而上的“道”,如何转换成形而下的“器”,确是需要结合实际场景case by case去思考的,没有标准答案。

你可以说 All In One 的巨无霸工程在创业初期短平快的组织结构和业务试错情况下能够快速发挥作用, 也可以说虽然洋葱架构如此多的层次让你剥开之后只想哭但是能够在特定的组织结构下起到微妙的平衡, 你也可以说你暂时并不需要弹性不需要高性能因为权衡起来性价比不高, 你甚至可以说不需要微服务因为运维成熟度完全跟不上。 ……

发现没有,所以,这才是对架构师而言有趣而有挑战的地方,服务治理从广义上来说,并不是一个技术问题,而是一个有趣的哲学问题。架构师需要利用其前瞻和洞察的能力,引领团队走向正确的方向,而不是一味纠结于是不是没有响应好所有的诉求,是不是没有遵循所谓的最佳实践。这么考虑一下,如果世界上只有一种颜色,只有一种解法,那未免也太无聊了吧,这个世界的有趣不正在与你养出的那只充满了“迫不得已”而又“正该如此”的薛定谔的猫吗?

4. 应用领域的指导原则

4.1 四个问题

网上有很多关于应该怎么拆分服务的文章,更多偏向技术层面。此处不加以赘述,我们讨论四个问题,也是经常困扰我们的四个重要问题:

应该在什么阶段进行拆分? 如前面提及的,考虑下你的业务迭代速度是否会引起系统所有权和使用权的竞争,进一步反向制约迭代的效率;考虑下是不是大应用导致你技术升级优化和资源的使用上困难重重;考虑下公司的运维水平和团队成员的素质是不是能够支撑起更细粒度的微服务体系结构。你考虑清楚了这三点,你就知道你是否应该进行拆分了。

应该按照什么维度来拆? 大原则上来说,按照业务领域进行拆分即可。在领域之内,进行分层拆解,将接入层、逻辑层和数据层复杂到一定程度的时候进行横向拆解。《微服务设计》一书中,提到了“限界上下文”的概念来让系统和业务边界进行对齐也是类似的道理。

服务拆分到多小算小? 有一个说法是“确保两个星期之内能够重构”。这和敏捷开发理论中的“重构式迭代”不谋而合,不过我觉得这种理论有待商榷,在大量的实际场景中不是很适用。我比较认同的是另一个说法—“足够小就行”。没有唯一的衡量标准,这个取决于你的业务发展速度,业务复杂度,技术栈异构程度。很多人的倾向是,更愿意对一些功能在不明确后续发展的时候,尽量能不拆就不拆。这同样也是我的建议。另外建议,确保一个服务只有一个团队在维护,这能避免大量的问题。当你发现有多个团队在维护的时候,说明你可能需要拆分了。

微服务团队需要多大? 亚马逊创始人贝佐斯的“两个披萨”原则基本适用,该原则为“每个内部团队都应该足够小,两个比萨饼就能解决伙食问题”。这样团队更容易具备战斗力和凝聚力,也能拥有更好的效率和对未来的应变能力。

4.2 组织边界的两个原则

服务治理三大要素中,我认为组织(即人)是最为重要的一个因素,也能够对其他两个因素起更显著影响作用的因素。如下两个定律在业内鼎鼎大名:

1. 康威第一定律:组织沟通方式会通过系统设计表达出来。 2. 咨询第二定律:不管一开始看起来什么样,它永远是人的问题。

人是复杂的动物,你必然会发现,脱离组织结构来谈最佳的系统设计是不切实际的。无论我们的初心多么的纯粹,希望两个组织结构一起协同做一件类似的事情,最后你基本都会发现,会做成两件事情,或者你将拥有一个跨多团队的n层洋葱圈架构。你可以动用行政的方式让多团队按照你的设想精密地共同完成一件你画好蓝图的大系统,但是往往最后的代价就是跌入谷底的效率和员工幸福感。

所以首当其冲,我们应该倡导组织边界和系统边界/业务边界对齐。比如当你不得不面对分布式异地办公的服务治理场景时,考虑尽可能地让每个办公区的团队承担独立业务的服务系统。这也是 Amazon 和 Netflix 等公司所践行的原则。

5. 技术领域的指导原则

面向技术领域,这个问题比处理上面的问题要更直接而明确,我们挑选其中四个方向来铺开分析:

  1. 可运营
  2. 高可用
  3. 高性能
  4. 自动化与标准化

5.1 可运营

我们认为可运营的核心在于可观察,以及在观察之后的可控制

5.1.1 可观察 — 监控报警

可运营的前提和核心即可观察,这即进一步要求我们需要有足够立体的监控报警能力来支撑。这也很大程度决定了我们服务生态体系的想象力。

一般划分的维度,我们可以自底向上划分为:基础设施级监控、系统级监控、业务级监控、产品级监控。每个层级的监控都有自己的关注核心和逻辑,基础设施级的监控比如运维层面会更关注机器 CPU、MEM、磁盘 IO、网卡 IO 、CDN 速度、多IDC延时等。系统级监控更关注单应用内,如JVM使用、堆栈、线程情况,抛异常 case、弹性指标、TPS、RT 等,以及跨应用的调用链路健康情况。业务级监控更偏业务导向,如下单人数、库存余量、支付数、退款数、UGC 增量等等和业务直接关联的指标;而产品级监控则会从产品整体去进行核心产品指标的定义,比如产品留存率、页面转化率、营销支付转化率、认证人数、认购单数等等。比较常见的监控报警产品有 Falcon、Zabbix、Nagios、Cat、Prometheus 等。

日志也是监控的一环,业界有开源的解决方案 ELK,但 ELK 本身存在很大的优化空间,所以很多公司都会基于 ELK 或者基于他的采集模型做定制化开发。

需要特别提到的是,需要正视四个层级的立体式监控情况下可能引发的报警风暴问题,这就需要能够有决策中枢进行报警的分析、关联和聚合,并且可以提供对应的ACK机制,这则是一个长期的建设过程。

5.1.2 可控制 — 指令下发

除了可观察外,可运营的另一关键就是能够动态下发指令或配置,这样才能真正意义上实现可控制的目标。一般来说:

  1. 基础架构/运维层面偏向于使用 puppet、ansible 之类的批量下发工具来进行指令、配置、安装包之类的动态下发。但 ansible 由于权限过大的问题,使用时候要慎重。
  2. 而在中间件层面,更多采用配置中心、注册中心来进行下发。下发的方式,可以是推、拉或者推拉结合的方式来进行。二者的底层存储选型其实比较类似的,所以也有一些共性问题需要注意。比如你考虑一下,你做好迎接 Zookeeper 给你带来的 watch 事件丢失以及重度 SDK 引入潜在风险的挑战了吗?你做好 etcd 很难扩展且无法做多中心的心里准备了吗?你做好接受 Consul 虽然天然支持多中心但是事件监听弱得让人无力吐槽的心里准备了吗?你做好 Eureka 过分强调 AP 而可能带来的极端情况下各种异常 case 吗?你甚至,是不是有种想要自己简单实现配置中心和注册中心的冲动?那么你想好对 CAP 的权衡,想好几大核心操作如何实现,想好如何设计推拉模型了吗?

5.2 高可用

高可用即如何让你的服务保持弹性,或者也有文章称之“反脆弱”。在我看来,高可用出现的目的即为应对故障,沿着故障的生命周期,我们也同样将高可用的领域划分为事前治理事后治理两大阶段。

5.2.1 事前治理

在故障发生之前,我们能做哪些事情,即称之为事前治理。我们认为,在这个阶段主要的技术上的措施有两个:

  1. 基于经验的环境重塑-压测演练。成熟的分布式服务环境,大部分的严重问题都会出在高流量的场景下。所以我们最好的方式就是构造这样的环境,在业务高峰来之前,先进行对应的压测演练,以进行问题的试探。健全的压测体系强依赖于分布式链路系统在全链路中传递压测标,这样业务、中间件和基础设施才能识别流量类型,并进行对应的处理,比如 Kafka 可以对压测标隔离出单独的 Topic,数据库中间件可以对压测标隔离出压测影子表。
  2. 避免失败的方式就是经常失败-故障演练。我们知道压测只是一种基于经验的环境重塑,希望通过不断试探系统在高压下的反应来检测出潜在的风险。而根据“墨菲定律”我们知道,如果有事情变坏的可能,那它总会发生。特别是在大量节点并存的网状服务拓扑中,这种概率就会不断被抬升。避免失败的方式就是经常失败,所以我们需要主动模拟各种故障来检验我们系统的弹性。Netflix 的“猴子大军”可以随机模拟进程故障、机房故障,阿里也基于强弱依赖的理论进行了故障演练的丰富实践。如果想做一套故障演练系统,那么阿里开源的 Sandbox 就非常适合对Java进程来做这件事情。
5.2.2 事后治理

在故障发生之后,我们能做些什么呢?归纳来看,最核心的无非就是限流、熔断、隔离、降级。限流熔断可以基于线程数控制、信号量控制、固定窗口计数、滑动窗口计数、令牌桶计数、漏桶计数等等的方式来进行流量的限制,单机限流熔断相对简单,Google 的 Guava Ratelimiter 就是一种很好的实践,整合了令牌桶和漏桶的方式,对于需要预热和不需要预热的场景都做了充分支持,Hystrix 也提供了数种限流、熔断和隔离的方式。当然限制之后,如何恢复也是一大问题。是要阶梯式恢复,还是时间窗口恢复,还是需要验证码恢复,都存在着很多的使用场景,不复赘述。

但是,如果放在分布式的环境下,这个问题将会变得复杂得多,比如是否要做富 SDK?比如是否要在 SDK 中引入其他中间件比如 Redis?比如采集数据的延时问题可能引发的误判如何解决?分布式环境下我们能信任什么数据?

目前比较主流的分布式环境下的限流熔断仍然采用的富客户端的方式来实现。猫眼基于自身现状和诉求,采取的则是轻 SDK + 重 Server 的方式来进行。基本所有的决策都在 Server 端进行。通过这种方式,实现了与业务较大程度上的解耦,并且为以后的联合决策提供先决条件。

5.3 高性能

如何才能让我们的服务保持高性能状态?加缓存、做静态化、预热、做异步、搞并行、业务优化、服务分级分流、硬件加速之类的就不赘述了。晚上很多类似的文章,而我这边比较感兴趣的,也主要想和大家讨论的是,服务治理框架的一大核心—底层通讯层面上,如何才能做到高性能?这就离不开几个法宝:

5.3.1 直连

连接方式上,直连带来的性能优势毋庸置疑。大部分的分布式服务框架都会采用直连的方式进行服务间的通讯。

5.3.2 高性能序列化

在高并发情况下,序列化有可能会成为你的性能热点。适当时候考虑下 pb、json、gson 或者自定义的序列化协议。自定义的序列化协议需要考虑如何压缩空间,并能够便于框架的提取解析,比如蚂蚁金服的 Bolt 协议里约定的魔数、固定头、变长头、包体等的方法论就是一个很好的例子。

5.3.3 Zero-Copy

Zero-Copy 是一个大杀器,在 Nginx、Netty(不是传统意义上的 Zero-Copy)、Kafka、RocketMQ 等项目中被使用,在合适的地方利用这个特性,比如磁盘顺序读 + Mmap + sendfile,你的系统性能将瞬间提升几个数量级。

5.3.4 Epoll 多路复用

Epoll相比于自己用宏定义把自己坑死的 select,以及后继者 poll 来说,在使用限制上以及性能上有着明显的飞跃。也是目前最主流的 IO 模型。现在各种业内风靡的高性能服务器设计,Epoll 基本都是必然采用的 IO 模型。当然 Netty 也采用过真正意义上的异步 IO - AIO,但是由于 Linux 的AIO目前尚不成熟等原因,最后的效果不好所以并没有真正推开。

5.3.5 Reactor线程模型

基本高性能服务的底层都采用了Reactor模式来实现线程模型。当然,配合线程池/协程池,以及 Reactor 的层次,可以有多种的实现路径。有类似 Nginx 这样的一主多子进程 + 单 Reactor 单线程(高版本提供了线程池机制)的模型,evio 和 Envoy 利用“单 Reactor 协程池(线程池)”, Netty 采用多级 Reactor + 多级线程池。

5.3.6 字节重用

我们习惯于对每个请求去新创建一个他所需要的空间来存放一些信息。但是当并发量上来后,这样的空间分配将会导致较大的性能开销和回收压力。所以基于伙伴算法或者Slab算法或其他的方式,进行一个字节内存使用的分配管理,将会让你收益良多。比如 Netty 由于申请了堆外内存而采用了伙伴算法,Nginx 则采用了 Slab 机制,Mosn 在 Golang 分配机制的基础上引入多级容量加 sync.Pool 机制的缓存来进行优化。

5.3.7 本地通讯优化

如果你的服务通讯是采用的 Servicemesh 之类的 Local Proxy 来进行转发,那么应用服务和 Proxy 之间的通讯链路可以基于本地进程通讯的特性进行优化。比如利用 mmap 进行进程间的通信,可以减少内核切换次数,这能让你获得意想不到的收益。traffic-shm 是一个异步无锁的IPC框架,能够轻松支撑百万 TPS,其就采用了 mmap 来进行通讯。

5.3.8 内存对齐

操作系统按照页进行内存管理。如果你直接操作内存地址进行数据传输(比如用 mmap)的话,那么如果没有内存对齐,将会导致你拉取到并不需要的内存空间,且会有内存移动拼接的额外开销,这将会直接导致你性能的下滑。高性能内存队列 Disruptor 也是采用了内存对齐的方式进行优化。

5.3.9 无锁化

通讯的第一反应即需要处理并发安全的问题,很多时候你可能不得不通过锁的方式来保障安全。这个时候,考虑下通过利用硬件层面的CAS操作来替代常规的锁操作,也可以采取类似 Redis 这样单线程处理的方式,或者 Envoy 这样虽然采用了线程池,但是连接会进行单个线程的绑定操作来规避并发问题。

5.3.10 池化

线程资源是很宝贵的,加上线程本身不可能申请几千上万个出来,所以线程池是默认的标配。这边要谈的是,比如你用了协程技术,虽然协程被神化为轻量级线程,性能非常高且可以轻松开出几万个而面不改色。但是你需要知道,这也会很严重地影响你实际的处理性能,并且由于 golang 本身的协程分配原理,协程的一些元数据并不会在使用后被回收,这是由于 golang 开发者的理念是“一旦到达过这样的流量,就说明系统有可能再次面临这样的洪峰,那么就提前做好准备”。所以我们对于协程,仍然需要考虑池化的问题。Motan-Go 和 Thrift 的 golang 版本中目前并没有这方面的考虑,而 Sofa-Mosn 已经做了对应的池化处理。

5.4 标准化与自动化

如在前面章节中提到的:

牺牲一定的性能和资源,换取服务治理理整体的高度自治和可运营

我认为在未来的成熟服务治理中,比起绝对的性能表现,我们更关注应用服务拓扑是否能够真正成熟到可以“自动化”甚至“自治”的程度。尽可能地解放人力操作,将其进化为机器语言。比如我们提倡自动化部署、自动化压测、自动化故障演练,自动化系统测试,自动化限流熔断,自动伸缩等等,都是在各个领域应用自动化解放人的双手的很好示例。 但,服务治理上,如何才能实现更高效的自动化呢?我认为:

自动化是治理的高级形态,而标准化是规模化治理的前提。

只有标准化,才能简化复杂服务世界的问题,将各种异构场景尽量同构建模,如此才有可能用可控成本完成规模化的服务治理,进一步完成大规模的自动化。 标准化,意味着你要考虑的差异性越少,你治理的成本越低,你能自动化的程度就越高。 你可以认为:

  1. Docker 其实就是部署级别的标准化,通过它可以很好地标准化环境,也可以提供标准化部署运维的手段,甚至我们可以通过容器来标准化服务治理的核心设施,通过容器对我们应用的改造和适配,我们就可以轻松完成大规模的自动化部署和弹性伸缩。
  2. Servicemesh 领军项目 Istio 的控制平面,也很好诠释了什么叫标准化,Pilot 标准化了异构的配置下发能力和注册中心,Mixer 标准化了遥测和限流的能力(当然,这在业内有一定的争议)。
  3. 阿里的 Sandbox 标准化了 AOP 切面的编织过程和完整的生命周期,让使用者相比于传统的方式节省了非常多的成本。
  4. 你甚至可以认为,大多数的框架,本身就是一个标准化的过程。

这时候的你,是不是认为,标准化其实无处不在?是的,没错。介绍一个有意思的“奶牛和宠物理论”,大致意思是:

你不应该老是想区分哪些服务是奶牛,哪些服务是宠物。生了病就杀掉它而不要去想区分出哪些是宠物并治好它。

是的,区分得越少,你的系统将越可靠,你的烦恼就越少。回到初心,其实都是一样的。 记得关注自己构建的系统生态之上的研发同学,如果他们终日忙碌,那么请抽时间和他们一起停下脚步审视下系统标准化和自动化的进展,或许你会有意想不到的收获。

6. 结语与展望

我们来回顾一下,在第一章,我们讲述了什么是服务治理,认为服务治理即治理三要素和服务环,第二章,介绍了服务治理的发展演变,简单介绍了三个阶段的思潮和演变的逻辑,让我们对于目前服务治理大发展方向和未来的发展趋势可以有一个初步的预测。在步入实际一些实践杂谈之前,我们需要先问清楚自己一个问题,我们需要什么样的服务治理,第三章我阐述了我个人的理解,这其实是一个哲学问题。之后的两张,则从业务应用层面,以及从底层基础技术领域,挑出了几个我认为比较有意思而重要的思考和实践来与大家进行讨论。当然,限于篇幅,我无法展开的论证每一个点,也由于自身能力和实践的限制,多少会有一些谬误的地方,也欢迎大家随时指出。

如标题所示,这只是服务治理整体的漫谈,偏重于从整体视角来理解服务治理的内核,并对一些很重要但很少被系统性谈及的部分进行进一步的解读。后续我会进行服务治理每一重要层次和环节的剖析,我们不仅希望结合实际生产实践来分析具体的系统架构,也希望通过对架构的剖析能进一步地去洞察设计者的意图和思考逻辑,知其然而知其所以然,这是我认为架构师领域非常重要的一个技能,也欢迎大家持续关注。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/07/29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 【服务治理】服务治理漫谈
    • 0. 前言
      • 1. 什么是服务治理
        • 1.1 三要素
        • 1.2 系统层面的正向打通和逆向反馈
      • 2. 服务治理的发展史
        • 2.1 Server Proxy
        • 2.2 Smart Client
        • 2.3 Local Proxy
        • 2.4 总结
      • 3. 我们需要什么样的服务治理
        • 4. 应用领域的指导原则
          • 4.1 四个问题
          • 4.2 组织边界的两个原则
        • 5. 技术领域的指导原则
          • 5.1 可运营
          • 5.2 高可用
          • 5.3 高性能
          • 5.4 标准化与自动化
        • 6. 结语与展望
        相关产品与服务
        混沌演练平台
        混沌演练平台(Chaotic Fault Generator)提供高效便捷、安全可靠的故障演习服务,除可视化故障注入服务外,还提供行业经验模板,监控护栏等核心功能,致力于帮助用户及时发现业务容灾隐患、验证高可用预案的有效性,从而提高系统的可用性和韧性。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档