一、前言
2014年可以认为是微服务1.0的元年,当年有几个标志性事件,一是Martin Fowler在其博客上发表了“Microservices”一文,正式提出微服务架构风格;二是Netflix微服务架构经过多年大规模生产验证,最终抽象落地形成一整套开源的微服务基础组件,统称NetflixOSS,Netflix的成功经验开始被业界认可并推崇;三是Pivotal将NetflixOSS开源微服务组件集成到其Spring体系,推出Spring Cloud微服务开发技术栈。
一晃三年过去,微服务技术生态又发生了巨大变化,容器,PaaS,Cloud Native,gRPC,ServiceMesh,Serverless等新技术新理念你方唱罢我登场,不知不觉我们又来到了微服务2.0时代。基于近年在微服务基础架构方面的实战经验和平时的学习积累,我想总结并提出一些构建微服务2.0技术栈的选型思路,供各位在一线实战的架构师、工程师参考借鉴。对于一些暂时还没有成熟开源产品的微服务支撑模块,我也会给出一些定制自研的设计思路。
二、选型准侧
对于技术选型,我个人有很多标准,其中下面三项是最重要的:
1. 生产级
我们选择的技术栈是要解决实际业务问题和上生产抗流量的(选择不慎可能造成生产级事故),而不是简单做个POC或者Demo展示,所以生产级(Production Ready),可运维(Ops Ready),可治理,成熟稳定的技术才是我们的首选;
2. 一线互联网公司落地产品
我们会尽量采用在一线互联网公司落地并且开源的,且在社区内形成良好口碑的产品,它们已经在这些公司经过流量冲击,坑已经基本被填平,且被社区接受形成一个良好的社区生态(本文附录部分会给出所有推荐使用或参考的开源项目的github链接。)。
3. 开源社区活跃度
Github上的stars的数量是一个重要指标,同时会参考其代码和文档更新频率(尤其是近年),这些指标直接反应开源产品的社区活跃度或者说生命力。
另外,对于不同业务体量和团队规模的公司,技术选型标准往往是不同的,创业公司的技术选型和BAT级别公司的技术选型标准可能完全不同。本文主要针对日流量千万以上,研发团队规模不少于50人的公司,如果小于这个规模我建议认真评估是否真的需要采用微服务架构。考虑到Java语言在国内的流行度和我个人的背景经验,本文主要针对采用Java技术栈的企业。本文也假定自建微服务基础架构,有些产品其实有对应的云服务可以直接使用,自建和采用云服务各有利弊,架构师需要根据场景上下文综合权衡。
三、微服务基础架构核心关心点
下面脑图中芒果色标注的七个模块,我认为是构建微服务2.0技术栈的核心模块,本文后面的选型会分别基于这些模块展开。对于每个模块我也列出一些核心架构关注点,在选择具体产品时,需要尽可能覆盖到这些关注点。
下图是在参考过华为技术专家王磊的《微服务的设计与生态系统》[附录12.46]的基础上,结合作者自身的实践调整而来,我想同时分享给一线架构师或者工程师参考,其中粉红色标注的模块是和微服务关系最密切的模块,大家在做技术选型时,可以同时对照这个体系。
四、服务框架选型
服务框架是一个比较成熟的领域,有太多可选项。Spring Boot/Cloud[附录12.1]由于Spring社区的影响力和Netflix的背书,目前可以认为是构建Java微服务的一个社区标准,Spring Boot目前在github上有超过20k星。基于Spring的框架本质上可以认为是一种RESTful框架(不是RPC框架),序列化协议主要采用基于文本的JSON,通讯协议一般基于HTTP。RESTful框架天然支持跨语言,任何语言只要有HTTP客户端都可以接入调用,但是客户端一般需要自己解析payload。目前Spring框架也支持Swagger契约编程模型,能够基于契约生成各种语言的强类型客户端,极大方便不同语言栈的应用接入,但是因为RESTful框架和Swagger规范的弱契约特性,生成的各种语言客户端的互操作性还是有不少坑的。
Dubbo[附录12.2]是阿里多年构建生产级分布式微服务的技术结晶,服务治理能力非常丰富,在国内技术社区具有很大影响力,目前github上有超过16k星。Dubbo本质上是一套基于Java的RPC框架,当当Dubbox扩展了Dubbo支持RESTful接口暴露能力。Dubbo主要面向Java 技术栈,跨语言支持不足是它的一个弱项,另外因为治理能力太丰富,以至于这个框架比较重,完全用好这个框架的门槛比较高,但是如果你的企业基本上投资在Java技术栈上,选Dubbo可以让你在服务框架一块站在较高的起点上,不管是性能还是企业级的服务治理能力,Dubbo都做的很出色。新浪微博开源的Motan(github 4k stars)也不错,功能和Dubbo类似,可以认为是一个轻量裁剪版的Dubbo。
gRPC[附录12.3]是谷歌近年新推的一套RPC框架,基于protobuf的强契约编程模型,能自动生成各种语言客户端,且保证互操作。支持HTTP2是gRPC的一大亮点,通讯层性能比HTTP有很大改进。Protobuf是在社区具有悠久历史和良好口碑的高性能序列化协议,加上Google公司的背书和社区影响力,目前gRPC也比较火,github上有超过13.4k星。目前看gRPC更适合内部服务相互调用场景,对外暴露HTTP RESTful接口可以实现,但是比较麻烦(需要gRPC Gateway配合),所以对于对外暴露API场景可能还需要引入第二套HTTP RESTful框架作为补充。总体上gRPC这个东西还比较新,社区对于HTTP2带来的好处还未形成一致认同,建议谨慎投入,可以做一些试点。
五、运行时支撑服务选型
运行时支撑服务主要包括服务注册中心,服务路由网关和集中式配置中心三个产品。
服务注册中心,如果采用Spring Cloud体系,则选择Eureka[附录12.4]是最佳搭配,Eureka在Netflix经过大规模生产验证,支持跨数据中心,客户端配合Ribbon可以实现灵活的客户端软负载,Eureka目前在github上有超过4.7k星;Consul[附录12.5]也是不错选择,天然支持跨数据中心,还支持KV模型存储和灵活健康检查能力,目前在github上有超过11k星。
服务网关也是一个比较成熟的领域,有很多可选项。如果采用Spring Cloud体系,则选择Zuul[附录12.6]是最佳搭配,Zuul在Netflix经过大规模生产验证,支持灵活的动态过滤器脚本机制,异步性能不足(基于Netty的异步Zuul迟迟未能推出正式版)。Zuul网关目前在github上有超过3.7k星。基于Nginx/OpenResty的API网关Kong[附录12.7]目前在github上比较火,有超过14.1k星。因为采用Nginx内核,Kong的异步性能较强,另外基于lua的插件机制比较灵活,社区插件也比较丰富,从安全到限流熔断都有,还有不少开源的管理界面,能够集中管理Kong集群。
配置中心,Spring Cloud自带Spring Cloud Config[附录12.8](github 0.75k stars),个人认为算不上生产级,很多治理能力缺失,小规模场景可以试用。个人比较推荐携程的Apollo[附录12.9]配置中心,在携程经过生产级验证,具备高可用,配置实时生效(推拉结合),配置审计和版本化,多环境多集群支持等生产级特性,建议中大规模需要对配置集中进行治理的企业采用。Apollo目前在github上有超过3.4k星。
六、服务监控选型
主要包括日志监控,调用链监控,Metrics监控,健康检查和告警通知等产品。
ELK目前可以认为是日志监控的标配,功能完善开箱即用,Elasticsearch[附录12.10]目前在github上有超过28.4k星。Elastalert(github 4k stars)[附录12.11]是Yelp开源的针对ELK的告警通知模块。
调用链监控目前社区主流是点评CAT(github 4.3k stars)[附录12.12],Twitter之前开源现在由OpenZipkin社区维护的Zipkin(github 7.5k stars)[附录12.13]和Naver开源的Pinpoint[附录12.14](github 5.3k stars)。个人比较推荐点评开源的CAT,在点评和国内多家互联网公司有落地案例,生产级特性和治理能力较完善,另外CAT自带告警模块。下面是我之前对三款产品的评估表,供参考。
Metrics监控主要依赖于时间序列数据库(TSDB),目前较成熟的产品是StumbleUpon公司开源的基于HBase的OpenTSDB[附录12.15](基于Cassandra的KariosDB[附录12.16]也是一个选择,github 1.1k stars,它基本上是OpenTSDB针对Cassandra的一个改造版),OpenTSDB具有分布式能力可以横向扩展,但是相对较重,适用于中大规模企业,OpenTSDB目前在github上有近2.9k星。OpenTSDB 本身不提供告警模块,Argus[附录12.17](github 0.29k星)是Salesforce开源的基于OpenTSDB的统一监控告警平台,支持丰富的告警函数和灵活的告警配置,可以作为OpenTSDB的告警补充。近年也出现一些轻量级的TSDB,如InfluxDB[附录12.18](github 12.4k stars)和Prometheus(github 14.3k stars)[附录12.19],这些产品函数报表能力丰富,自带告警模块,但是分布式能力不足,适用于中小规模企业。Grafana(github 19.9k stars)[附录12.20]是Metrics报表展示的社区标配。
社区还有一些通用的健康检查和告警产品,例如Sensu(github 2.7k stars)[附录12.21],能够对各种服务(例如spring boot暴露的健康检查端点,时间序列数据库中的metrics,ELK中的错误日志等)定制灵活的健康检查(check),然后用户可以针对check结果设置灵活的告警通知策略。Sensu在Yelp等公司有落地案例。其它类似产品还有Esty开源的411(github 0.74k星)[附录12.22]和Zalando的ZMon(github 0.15k星)[附录12.23],它们是分别在Esty和Zalando落地的产品,但是定制check和告警配置的使用门槛比较高,社区不热,建议有定制自研能力的团队试用。ZMon后台采用KairosDB存储,如果企业已经采用KariosDB作为时间序列数据库,则可以考虑ZMon作为告警通知模块。
七、服务容错选型
针对Java技术栈,Netflix的Hystrix(github 12.4k stars)[附录12.24]把熔断、隔离、限流和降级等能力封装成组件,任何依赖调用(数据库,服务,缓存)都可以封装在Hystrix Command之内,封装后自动具备容错能力。Hystrix起源于Netflix的弹性工程项目,经过Netflix大规模生产验证,目前是容错组件的社区标准,github上有超12k星。其它语言栈也有类似Hystrix的简化版本组件。
Hystrix一般需要在应用端或者框架内埋点,有一定的使用门槛。对于采用集中式反向代理(边界和内部)做服务路由的公司,则可以集中在反向代理上做熔断限流,例如采用nginx(github 5.1k stars)[附录12.25]或者Kong(github 11.4k stars)[附录12.7]这类反向代理,它们都有插件支持灵活的限流容错配置。Zuul网关也可以集成Hystrix实现网关层集中式限流容错。集中式反向代理需要有一定的研发和运维能力,但是可以对限流容错进行集中治理,可以简化客户端。
八、后台服务选型
后台服务主要包括消息系统,分布式缓存,分布式数据访问层和任务调度系统。后台服务是一个相对比较成熟的领域,很多开源产品基本可以开箱即用。
消息系统,对于日志等可靠性要求不高的场景,则Apache顶级项目Kafka(github 7.2k stars)[附录12.26]是社区标配。对于可靠性要求较高的业务场景,kafka其实也是可以胜任,但企业需要根据具体场景,对 Kafka的监控和治理能力进行适当定制完善,Allegro公司开源的hermes(github 0.3k stars)[附录12.27]是一个可参考项目,它在Kafka基础上封装了适合业务场景的企业级治理能力。阿里开源的RocketMQ(github 3.5k星)[附录12.28]也是一个不错选择,具备更多适用于业务场景的特性,目前也是Apache顶级项目。RabbitMQ(github 3.6k星)[附录12.29]是老牌经典的MQ,队列特性和文档都很丰富,性能和分布式能力稍弱,中小规模场景可选。
对于缓存治理,如果倾向于采用客户端直连模式(个人认为缓存直连更简单轻量),则SohuTv开源的cachecloud(github 2.5k stars)[附录12.30]是一款不错的Redis缓存治理平台,提供诸如监控统计,一键开启,自动故障转移,在线伸缩,自动化运维等生产级治理能力,另外其文档也比较丰富。如果倾向采用中间层Proxy模式,则Twitter开源的twemproxy(github 7.5k stars)[附录12.31]和CodisLab开源的codis(github 6.9k stars)[附录12.32]是社区比较热的选项。
对于分布式数据访问层,如果采用Java技术栈,则当当开源的shardingjdbc(github 3.5k stars)[附录12.33]是一个不错的选项,分库分表逻辑做在客户端jdbc driver中,客户端直连数据库比较简单轻量,建议中小规模场景采用。如果倾向采用数据库访问中间层proxy模式,则从阿里Cobar演化出来的社区开源分库分表中间件MyCAT(github 3.6k stars)[附录12.34]是一个不错选择 。proxy模式运维成本较高,建议中大规模场景,有一定框架自研和运维能力的团队采用。
任务调度系统,个人推荐徐雪里开源的xxl-job(github 3.4k stars)[附录12.35],部署简单轻量,大部分场景够用。当当开源的elastic-job(github 3.2k stars)[附录12.36]也是一个不错选择,相比xxl-job功能更强一些也更复杂。
九、服务安全选型
对于微服务安全认证授权机制一块,目前业界虽然有OAuth和OpenID connect等标准协议,但是各家具体实现的做法都不太一样,企业一般有很多特殊的定制需求,整个社区还没有形成通用生产级开箱即用的产品。有一些开源授权服务器产品,比较知名的如Apereo CAS(github 3.6k stars)[附录12.37],JBoss开源的keycloak(github 1.9 stars)[附录12.38],spring cloud security[附录12.39]等,大都是opinionated(一家观点和做法)的产品,同时因支持太多协议造成产品复杂,也缺乏足够灵活性。个人建议基于OAuth和OpenID connect标准,在参考一些开源产品的基础上(例如Mitre开源的OpenID-Connect-Java-Spring-Server(github 0.62k stars)[附录12.40],定制自研轻量级授权服务器。Wso2提出了一种微服务安全的参考方案[附录12.45],建议参考,该方案的关键步骤如下:
- 使用支持OAuth 2.0和OpenID Connect标准协议的授权服务器(个人建议定制自研);
- 使用API网关作为单一访问入口,统一实现安全治理;
- 客户在访问微服务之前,先通过授权服务器登录获取access token,然后将access token和请求一起发送到网关;
- 网关获取access token,通过授权服务器校验token,同时做token转换获取JWT token。
- 网关将JWT Token和请求一起转发到后台微服务;
- JWT中可以存储用户会话信息,该信息可以传递给后台的微服务,也可以在微服务之间传递,用作认证授权等用途;
- 每个微服务包含JWT客户端,能够解密JWT并获取其中的用户会话信息。
- 整个方案中,access token是一种by reference token,不包含用户信息可以直接暴露在公网上;JWT token是一种by value token,可以包含用户信息但不暴露在公网上。
十、服务部署平台选型
容器已经被社区接受为交付微服务的一种理想手段,可以实现不可变(immutable)发布模式。一个轻量级的基于容器的服务部署平台主要包括容器资源调度,发布系统,镜像治理,资源治理和IAM等模块。
集群资源调度系统:屏蔽容器细节,将整个集群抽象成容器资源池,支持按需申请和释放容器资源,物理机发生故障时能够实现自动故障迁移(fail over)。目前Google开源的kubernetes[附录12.41],在Google背书和社区的强力推动下,基本已经形成市场领导者地位,github上有31.8k星,社区的活跃度已经远远超过了mesos(github 3.5k stars)[附录12.42]和swarm等竞争产品,所以容器资源调度建议首选k8s。当然如果你的团队有足够定制自研能力,想深度把控底层调度算法,也可以基于mesos做定制自研。
镜像治理:基于docker registry,封装一些轻量级的治理功能。vmware开源的harbor(github 3.5k stars)[附录12.43] 是目前社区比较成熟的企业级产品,在docker registry基础上扩展了权限控制,审计,镜像同步,管理界面等治理能力,可以考虑采用。
资源治理:类似于CMDB思路,在容器云环境中,企业仍然需要对应用app,组织org,容器配额和数量等相关信息进行轻量级的治理。目前这块还没有生产级的开源产品,一般企业需要根据自己的场景定制自研。
发布平台:面向用户的发布管理控制台,支持发布流程编排。它和其它子系统对接交互,实现基本的应用发布能力,也实现如蓝绿,金丝雀和灰度等高级发布机制。目前这块生产级的开源产品很少,Netflix开源的spinnaker(github 4.2k stars)[附录12.44]是一个,但是这个产品比较复杂重量(因为它既要支持适配对接各种CI系统,同时还要适配对接各种公有云和容器云,使得整个系统异常复杂),一般企业建议根据自己的场景定制自研轻量级的解决方案。
IAM:是identity & access management的简称,对发布平台各个组件进行身份认证和安全访问控制。社区有不少开源的IAM产品,比较知名的有Apereo CAS(github 3.6k stars),JBoss开源的**keycloak(github 1.9 stars)**等。但是这些产品一般都比较复杂重量,很多企业考虑到内部各种系统灵活对接的需求,都会考虑定制自研轻量级的解决方案。
考虑到服务部署平台目前还没有端到端生产级解决方案,企业一般需要定制集成,下面给出一个可以参考的具备轻量级治理能努力的发布体系:
简化发布流程如下:
- 应用通过CI集成后生成镜像,用户将镜像推到镜像治理中心;
- 用户在资产治理中心申请发布,填报应用,发布和配额相关信息,然后等待审批通过;
- 发布审批通过,开发人员通过发布控制台发布应用;
- 发布系统通过查询资产治理中心获取发布规格信息;
- 发布系统向容器云发出启动容器实例指令;
- 容器云从镜像治理中心拉取镜像并启动容器;
- 容器内服务启动后自注册到服务注册中心,并保持定期心跳;
- 用户通过发布系统调用服务注册中心调拨流量,实现蓝绿,金丝雀或灰度发布等机制;
- 网关和内部微服务客户端定期同步服务注册中心上的服务路由表,将流量按负载均衡策略分发到新的服务实例上。
另外,持续交付流水线(CD Pipeline)也是微服务发布重要环节,这块主要和研发流程相关,一般需要企业定制,下面是一个可供参考的流水线模型,在镜像治理中心上封装一些轻量级的治理流程,例如只有通过测试环境测试的镜像才能升级发布到UAT环境,只有通过UAT环境测试的镜像才能升级发布到生产环境,通过在流水线上设置一些质量门,保障应用高质量交付到生产。
十一、写在最后
注意,本文限于篇幅,对测试和CI等环节没有涉及,但它们同样是构建微服务架构的重要环节,也有众多成熟的开源成熟产品可选。
技术选型虽然重要,但还只是微服务建设的一小部分工作,选型后的产品要在企业内部真正落地,形成完整的微服务技术栈体系,则后续还有大量集成、定制、治理、运维和推广等工作。
本文仅限个人经验视角,选型思路仅供参考借鉴。每个企业的具体上下文(业务场景,团队组织,技术架构等)各不相同,每个架构师的背景经验也各不相同,大家要结合实际自己做出选型,没有最好的技术栈,只有相对较合适的技术栈。另外,好的技术选型是相互借鉴甚至PK出来的,欢迎大家讨论,给出自己的微服务2.0技术栈选型意见。
十二、附录
- Spring Boot
- Alibaba Dubbo
- Google gRPC
- NetflixOSS Eureka
- Hashicorp Consul
- NetflixOSS Zuul
- Kong
- Spring Cloud Config
- CTrip Apollo
- ElasticSearch
- Yelp Elastalert
- Dianping CAT
- Zipkin
- Naver Pinpoint
- OpenTSDB
- KairosDB
- Argus
- InfluxDB
- Prometheus
- Grafana
- Sensu
- Esty 411
- Zalando ZMon
- NetflixOSS Hystrix
- Nginx
- Apache Kafka
- Allegro Hermes
- Apache Rocketmq
- Rabbitmq
- Sohutv CacheCloud
- Twitter twemproxy
- CodisLab codis
- Dangdang Sharding-jdbc
- MyCAT
- Xxl-job
- Dangdang elastic-job
- Apereo CAS
- JBoss keycloak
- Spring cloud security
- OpenID-Connect-Java-Spring-Server
- Google Kubernetes
- Apache Mesos
- Vmware Harbor
- Netflix Spinnaker
- Microservices in Practice – Key Architecture Concepts of an MSA
- 微服务的设计与生态系统