前言首先,本文不讨论为什么要面向服务,包括面向服务的优缺点。其次,本文不讨论什么是微服务,也不讨论微服务和SOA的区别。最后,本文不讨论哪种技术最好。服务框架构成了最基本的服务框架。基础服务框架包括以下模块:统一RPC框架、服务注册中心、管理平台。有了这三个模块,就可以实现基础服务了。下面分别对这三个模块进行详细分析。为什么RPC框架选择必须是统一的RPC框架,而不是任何框架?这主要是为了技术对齐,减少开发者的学习成本,减少团队之间的沟通成本。好了,那么我们在选择RPC框架的时候需要考虑什么呢?这里我总结一下:代码规范:比如是否对现有代码透明,或者代码生成;通信协议:例如TCP或HTTP;序列化协议:例如是二进制还是文本,是否需要跨语言,性能;IO模型:异步/同步,阻塞/非阻塞;负载均衡:客户端软负载、代理模式、服务器负载。另外,如果我们选择开源,那么我们还需要考虑:成熟度:包括学习成本、社区知名度、文档数量、是否有团队维护、稳定性(盲目追求不一定最合适);可扩展性:SPI是否支持扩展,是否支持上下兼容;cross-language:是否支持跨语言;性能:如果想作为RPC框架使用,性能一般不会太差[滑稽脸]。下面是一些常见的开源框架的对比,大家可以看看。ps:SOAP、RMI、Hessian、ICE没有列出来。选型总结:如果需要和前端交互,适合短链接、跨语言的RPC框架,比如RESTful、gRPC等;如果是纯后台交互,适合长链接和序列化成二进制的RPC框架,比如thrift、dubbo等,效率更高;如果是小公司,新公司可以选择标准化的RPC框架,比如thrift、RESTful、gRPC;如果是业务代码较多的二次推广服务框架,最好选择没有代码侵入的RPC框架,比如dubbo、RESTful。注册中心选择注册中心相当于服务提供者和服务调用者之间的向导,在服务治理中起着极其重要的作用。选择注册中心的基本考虑因素是:服务注册:接收注册信息的方式;服务订阅:返回订阅信息的方式,push或者pull;状态检测:检测服务器的生存状态。重点关注这个状态检测,因为如果检测不准确,就会误判,造成严重的后果。例如Zookeeper根据服务器注册的临时节点进行状态检测。如果服务器和Zookeeper之间的网络中断,Zookeeper会认为服务端死了,所以去掉这个节点;但实际上,客户端和服务端之间的直连网络是好的,所以有可能把所有的节点都去掉,导致没有可用的节点。如果选择开源,还需要考虑:成熟度:包括学习成本、社区知名度、文档数量(一味追求不一定最合适);维护费用:注册中心维护;数据解构:是否可以快速定位结果,是否可以遍历;性能和稳定性;CAP原则:CP(关注一致性)或AP(关注可用性)。以下是一些使用开源项目作为注册中心的常见对比,大家可以看看。ps:Redis和MySQL没有列出来。选择总结:如果规模小,选择CP,RPC框架可以直接连接数据源;如果规模大,选择AP,RPC框架不能直接连接数据源;如果有跨机房、跨地域的,尽量不要选择强一致性协议的注册中心;RPC框架必须有注册中心不可用时的容灾策略;服务状态检测非常重要。简单的管理端管理端没有什么特殊要求,至少可以看到服务提供者和调用者。完善的服务框架如果需要一个完善的服务框架,就必须添加外部模块。常用模块如下:接口文档管理提供接口文档管理和接口查询入口,可以是公共WIKI,也可以是Standalone系统等。这里可以定义接口的文档,包括接口描述,方法定义,和字段定义。可以定义接口的SLA,包括支持的并发数、tp99数、推荐配置。还有接口负责人和其他查询入口。配置中心提供了配置管理的场所。这里所说的配置主要是指一些与服务相关的配置。配置包括组配置、路由策略、黑白名单、降级开关、限流信息、超时、重试次数等,任何可以动态改变的数据。这样,服务提供者和服务调用者可以直接进行配置更改,而无需重启自己的应用程序。配置中心可以独立于注册中心,也可以与注册中心合并。监控中心的监控服务关注接口维度和实例维度(比如所在的JVM实例)的数据。RPC框架可以定时上报调用次数、耗时、异常等信息。监控中心可以统计服务质量信息,也可以进行监控和报警。分布式溯源不同于监控中心,以调用链的方式进行服务。RPC框架作为分布式跟踪系统的天然埋点,可以很好的进行数据输出。服务治理(重点)我这里列举了常见的服务治理功能,例如:服务路由:权重:比如配置高的机器权重高,配置低的机器权重低;IP路由:比如某些机器只能调某几台机器;群组路由:比如根据配置自动调整一个群组;参数路由:比如根据方法名进行分类读写,或者根据参数去不同的节点;机房路由:比如只去同一个机房??,或者同一个机房??优先。调用授权:应用授权:只有授权的应用才能调用这组服务Token:只有token对才能调用这组服务黑白名单:只有列表允许的才能调用这组服务本例为动态组调度在服务提供者上执行;client-sidesplitgrouping:可以对主叫进行分组调度。Callthrottling:Server-sidethrottling:基于令牌桶或漏桶模型的服务器端节流;客户端限制:调用次数根据客户端身份进行限制。灰度部署:灰度上线:先启动,验证后提供服务;预发布标志:表示该服务是预发布服务;接口测试:方便的提供接口自动化功能测试功能。配置下发:服务配置;全局配置。服务降级:Mock:异常或测试时返回Mock数据;断路器:客户端超时或服务器超时;拒绝服务:当服务器压力过大时,会自动拒绝服务以保护自己。网关RPC框架的大部分场景都是自己调用的。什么时候需要网关?网关可以提供以下功能:统一认证服务;限流服务;协议转换:外部协议到统一的内部协议;Mock:服务测试、降级等;其他一些统一的处理逻辑(如请求解析、响应打包)。ServiceRegistryPlus需要具备逻辑处理能力,如过滤整合数据、计算服务路由等功能。它还需要能够与RPC框架进行交互。管理端Plus管理端除了具备以往简单的业务管理功能外,还需要提供配置信息展示、监控信息展示、数据展示等多个维度。即下面提到的服务治理功能都可以在管理端进行管理。另外,可以将常用的服务治理功能作为开放服务,供开发者调用。京东第一代SAF背景2012年初,京东从.NET转向Java。各个部门和业务线没有一个统一的服务框架,有的是dubbo,有的是WebService,有的是Hessian等等。同时,每个业务系统都有大量的业务代码。据统计,接口大小约1K,服务节点约50K,机器大小约8K,机房较小,拓扑简单。所以,当时的愿景和目标比较明确:京东的系统从无到有,面向服务,基于API;统一京东RPC调用框架;稳定可靠;提供简单的服务治理功能。第一代SAF选择了OK,结合我们的情况和上面的一些选择总结,我们当时的选择是:RPC框架:基于dubbo2.3.2进行配置扩展,功能扩展包括:rest(resteasy)、webservice(cxf)、kryo/thrift序列化、调用压缩等;注册中心:Zookeeper、数据源直连RPC框架;监控中心:监控服务+HBase;管理平台:读作Zookeeper作为管理平台,提供基本的在线离线、黑白名单等功能。2012年4月上线,最大规模时接口数3K,最大连接IP数20K。二代JSF后台随着京东业务的持续快速增长,接口数量和机器数量也呈数量级增长。与此同时,京东在全国设立子公司、新建机房,部署结构变得更加复杂。除了SAF遗留的一些问题外,它可能面临以下几点:RPC框架较重,性能有提升空间;注册中心没有业务逻辑,直接对外暴露;京东复杂的部署架构需要更强大、更灵活的服务治理功能;监控数据不完整,维度不足;没有应用程序依赖性;跨语言调用要求。二代JSF选型所以在2014年初,我们进行了一个完整的二代JSF的自主开发过程。我们主要做了以下技术选型:(全部自研)RPC框架:轻量级,性能更好,兼容老版本协议;注册中心:以DB为数据源,前置索引服务;支持十次访问,部分逻辑放在注册中心,减轻客户端负担;监控中心:监控Proxy服务+InfluxDB(2015年后改为ElasticSearch);管理端:基于DB,功能更强大,提供完善的服务治理和管理功能;开通京东应用管理平台,提供应用依赖排序;HTTP网关:基于Netty,支持跨语言调用。开发周期:7人/年(2014.1-2015.1)。包括开发、测试、预发布、发布和推广。JSF架构图JSF注册中心京东的注册中心是自研的,基于DB的数据最终一致性,也就是上面说的AP系统。注册中心主要实现服务列表的注册和订阅推送、服务配置的获取和分发、服务状态的实时查看等功能。注册表节点是无状态的并且可以水平扩展。整个注册表集群下的所有注册表点都是等价的。每个机房部署多个注册中心节点。同机房的RPC框架会优先连接机房的注册中心节点。主要亮点如下:引入Index服务的概念:该服务是最简单的HTTP服务,用于查找注册中心节点(在同一机房或压力最小或其他特定场景)。可以认为是一个不会挂掉的服务,会优先调用RPC框架即使服务拿的是注册中心的地址,这样做的好处是注册中心地址发生变化后,RPC框架不需要修改任何设置;注册中心全量服务列表缓存,即使不连接数据库也保证可读;数据库的数据结构更适合各种维度的展示、过滤、分析等,例如根据分组/IP/应用/机房等不同维度;注册中心为JSF服务,监控压力大时可动态水平扩展。Dogfooding,注册中心其实是第一个JSF接口;服务列表推送逻辑改进:比如之前有100个Provider,现在增加了1个节点。之前的SAF需要下发101个节点,需要判断添加哪个节点建立长链路;目前的改进是:修改发送一个add事件,通知RPC框架已经添加了一个节点,RPC框架建立一个长链接;这大大减少了推送的数据量;注册中心和RPC框架可以通过多种方式进行交互:注册中心和RPC框架是长期Link,JSF支持Callback,注册中心可以调用RPC框架进行除改变服务列表以外的操作;如检查状态、检查配置、分发配置等。JSFRPC框架作为服务中最基础的组件,RPC框架其实也是类似的,因为RPC调用无法绕过代理、网络、序列化等操作。JSF的RPC框架也类似。图中主要分为几个模块。部分功能特性如下:Config:Spring/API/AnnotationProxy:Javassist/JDKInvoker/Filter:内置+自定义,Filter可扩展Client:Failover(默认)/FailFast/TransportPinpoint/MultiClientProxy调用方式:同步(default)/asynchronousparallel/asynchronouscallback/Callback/generalizedLoadbalance:Random(default)/Roundrobin/ConsistentHash/LocalPreference/LeastActiveCall路由:参数路由,分组路由,(IP级路由逻辑在注册中心完成)长连接维护:available/dead/sub-health协议:JSF(默认)/SAF(dubbo)/HTTP/Telnet/HTTP2第三方:REST/Webservice序列化:MsgPack(默认)/Hessian/Json/Java/protobuf(c++)压缩:Snappy/LZMA网络:基于Netty4.0,长连接多路复用线程模型:BOSS+WORKER+BIZ容灾:本地文件请求上下文:IP、参数、隐式参数传递事件监听:响应事件、连接事件、状态事件分发d跟踪支持:数据埋点JSF管理平台提供强大的管理功能,包括服务管理、监控管理、注册中心管理等功能。对于服务治理的功能,我们提供了很多API,可以授权给开发者或者外部系统。比如单元测试调用、限流配置/开关、动态分组、上下线等都提供了开放的API。JSFHTTP网关网关是为了方便通过HTTP+JSON对JSF服务进行跨语言调用,而不需要使用JSF的RPC框架。特点如下:基于Netty4.0实现HTTP网关,不使用Servlet容器,轻量高效;支持自动服务发现:一般的HTTP服务,为了解决外面的单点问题,会使用域名+VIP来实现高可用,故障转移等;现在网关同时原生连接到JSF注册中心时间,并知道服务提供者信息(JSF协议支持HTTP调用);服务提供者无需担心扩缩容引起的服务IP端口问题,网关会自动维护服务列表;服务流量限制:方法级+应用授权,固定时间内只调用指定次数;同一个方法只能占用网关中的部分线程;结果统一打包:打包异常等响应。JSF遇上京东弹性云京东的JSF服务开发是在京东弹性云的研发和推广之前完成的。京东弹性云自上线以来,也遇到了很多问题。例如:硬件指标:比如使用JDK得到的Docker指标有一部分是物理机,我们需要特殊处理;网络:结合京东的“胖”容器,每个容器其实都有一个实际的IP,对外提供服务;轻量级:提高启动速度;开放服务:在容器销毁或非优雅关闭的情况下,提供API进行服务管理。JSF规模接口数:万级服务节点数:百万级访问实例数:10万级框架调用量:千亿级每天监控数据:每天120亿条数据,1.2T数据量HTTP网关:每天100亿级综上所述,没有最好,只有最合适!就是不跟风,盲目看大公司用什么,什么是最新的,什么性能最好。因为架构不是设计给你用一辈子的,好的架构是慢慢演化出来的。不同的架构会做出不同的技术选择。所以,任何时候,我们都要结合自己的现状和未来几年的规划来进行技术选择。这仅仅是个开始!选择面向服务的框架只是一个开始,真正改变的是选择之后公司整体业务和发展的变化。有时间可以看看康威定律。作者:张庚,原京东高级架构师,负责京东服务框架、配置中心等基础平台。近十年工作经验,专注基础中间件等底层技术架构,对分布式系统/面向服务/DevOps建设有一定经验。【本文来自专栏作者张凯涛微信公众号(凯涛的博客)公众号id:kaitao-1234567】点此查看作者更多好文
