-
写在前面的话:
本文是假定自建微服务基础架构,有些产品其实有对应的云服务可以直接使用,比如直接用开源的Spring Cloud等。自建和采用云服务各有利弊,架构师需要根据场景上下文综合权衡。
搬砖不易,希望能得到友情三连。如果有大佬想转载,转载记得附出处哈!
一、选型准则
1、成熟稳定抗流量
我们选择的技术栈一定是能上生产,能解决实际业务上产生的问题,而不是简单的做一个DEMO,这样容易由于实际业务中一些不可控因素导致生产级的事故。所以,生产级、可运维级、可治理级等成熟稳定的技术才是我们的首选。
2、选择一线互联网落地的产品
尽量采用在一线互联网公司落地并且开源的,且在社区内形成良好口碑的产品。它们已经在这些公司经过流量冲击,坑已经基本被填平,且被社区接受形成一个良好的社区生态。先谋发展,再求突破!(本文附录部分会给出所有推荐使用或参考的开源项目的github链接)
3、社区开源且活跃度高
Github上的stars的数量是一个重要指标,同时会参考其代码和文档更新频率(尤其是近年),这些指标直接反应开源产品的社区活跃度或者说生命力。如果引入的技术没有跟随时代的步伐迭代,那么我们可以寻找新技术,抛弃这个旧技术。因为你会发现,当你引入的是一个社区活跃度不高的技术,你在出现bug、出现生产事故的时候,你是没办法从社区里面快速的得到解决方法,只能自己搞定这个坑。这点特别重要,但是很多人会忽视。
另外,对于不同业务体量和团队规模的公司,技术选型标准往往是不同的,创业公司的技术选型和BAT级别公司的技术选型标准可能完全不同。
本文主要针对日流量千万以上的。如果研发团队规模不少于50人的公司,如果小于这个规模我建议认真评估是否真的需要采用微服务架构,而不是盲目的跟风做去分布式。讲道理,有这个时间和经费还不如想着怎么样把产品运营好,毕竟赚钱才是王道!
二、微服务基础架构的核心
以上是我认为微服务基础架构的几个核心模块,本文也会针对这几个核心的模块去展开分析。在针对具体产品做技术选型时,我希望大家可以尽可能覆盖到这些关注点。
下图是我在参考过华为技术专家王磊的《微服务的设计与生态系统》的基础上,结合自身的实践和理解调整而来,希望大家在做技术选型时,可以同时一起对照一下这个体系。
三、三种主流服务框架选型
SpringCloud
由于Spring社区的影响力和Netflix的背书,目前可以认为是构建Java微服务的一个社区标准。基于Spring的框架本质上可以认为是一种RESTful框架(不是RPC框架),序列化协议主要采用基于文本的JSON,通讯协议一般基于HTTP。RESTful框架天然支持跨语言,任何语言只要有HTTP客户端都可以接入调用,但是客户端一般需要自己解析payload。目前Spring框架也支持Swagger契约编程模型,能够基于契约生成各种语言的强类型客户端,极大方便不同语言栈的应用接入,但是因为RESTful框架和Swagger规范的弱契约特性,生成的各种语言客户端的互操作性还是有不少坑的。
优点
- Netflix背书
- 社区非常活跃
- 基于SpringBoot,配置简单,快速开发,部署轻松,方便测试等
- 集成了各种微服务组件,满足了构建微服务架构需要的所有解决方案,开发风险小
- 适用于轻量级的微服务架构
缺点
- JVM only
- 运行消耗资源性能,网络
Dubbo
Dubbo是阿里多年构建生产级分布式微服务的技术结晶,服务治理能力非常丰富,在国内技术社区具有很大影响力。Dubbo本质上是一套基于Java的RPC框架,当当Dubbox扩展了Dubbo支持RESTful接口暴露能力。Dubbo主要面向Java 技术栈,跨语言支持不足是它的一个弱项,另外因为治理能力太丰富,以至于这个框架比较重,完全用好这个框架的门槛比较高,但是如果你的企业基本上投资在Java技术栈上,选Dubbo可以让你在服务框架一块站在较高的起点上,不管是性能还是企业级的服务治理能力,Dubbo都做的很出色。新浪微博开源的Motan(github 4k stars)也不错,功能和Dubbo类似,可以认为是一个轻量裁剪版的Dubbo。但是实际上,Dubbo的关注点在于服务治理,并不能算是一个真正的微服务框架!
优点
- 阿里背书
- 成熟稳定
- RPC高性能调用
- 具有调度、发现、监控、治理等功能,相当丰富的服务治理能力
缺点
- 复杂度高,重量级
- JVM only
- 耦合性高
- 国外社区小
K8s
Kubernetes(简称k8s)是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效,Kubernetes提供了资源调度、部署管理、服务发现、扩容缩容、监控,维护等一整套功能。努力成为跨主机集群的自动部署、扩展以及运行应用程序容器的平台。 它支持一系列容器工具, 包括Docker等。故障迁移、资源调度、资源隔离、采用docker容器,进程之间互不影响、安全、快速精准地部署应用程序、负载均衡等特点。
优点
- 谷歌背书
- 社区活跃
- 平台抽象
- 全面覆盖的服务关注点(发布)
- 语言栈无关
缺点
- 偏DevOps和运维
- 重量复杂
- 技术门槛高
四、后台服务选型
后台服务主要包括消息系统,分布式缓存,分布式数据访问层和任务调度系统。后台服务是一个相对比较成熟的领域。很多开源产品基本可以开箱即使用。
消息系统
对于日志等可靠性要求不高的场景,则Apache顶级项目Kafka是社区标配。可能有些对可靠性要求比较高的业务场景,可能就有些会用阿里开源的RocketMQ。如果硬是要用kafka去处理一些需要高可用的场景,那建议就是在对kafka的监控和治理能力上进行适当的完善。可以参考allegro公司开源的hermes项目。除此之外,老牌的RabbitMQ也是可以考虑一下的,文档也特别完善,适用中小规模场景可选。
缓存治理
如果倾向于采用客户端直连模式(个人认为缓存直连更简单轻量),则SohuTV开源的cachecloud是一款不错的Redis服务治理平台,提供诸如监控统计,一键开启,自动故障转移,在线伸缩,自动化运维等生产级治理能力,另外其文档也比较丰富。如果倾向采用中间层Proxy模式,则Twitter开源的twemproxy和CodisLab开源的codis是社区比较热的选项。
分布式数据访问层
如果采用Java技术栈,当当开源的shardingjdbc是一个不错的选项,分库分表逻辑在客户端jdbc driver中,客户端直连数据库比较简单轻量,建议中小规模场景采用这种方式。如果倾向采用数据库访问层proxy模块,那么阿里的分库分表中间件MyCAT是一个不错选择。proxy模块运维成本较高,建议中大规模场景,有一定框架自研和运维能力的团队选型采用。
任务调度系统
个人推荐徐雪里开源的xxl-job,部署简单轻量,大部分场景够用。当当开源的elastic-job也是一个不错选择,相比xxl-job功能更强一些也更复杂。
五、运行时支撑服务选型
运行时支撑服务主要包括服务路由网关、服务注册中心,和集中式配置中心三个模块。
服务网关
是一个比较成熟的领域。如果采用springcloud那一套,那么选择Zuul是最佳搭配。Zuul在Netflix经过大规模生产验证,支持灵活的动态过滤器脚本机制,但是异步的性能不足,也是spring cloud的短板之一,希望后续基于Netty的异步Zuul可以推出正式版,那就真的无敌了。还有一款最近特别火的基于Ngnix/OpenResty的API网关Kong,因为采用Ngnix内核,Kong的一部性能较强,另外lua的插件机制也比较灵活,社区插件也丰富,从安全到限流熔断都有,也有不少开源的管理界面,能集中管理Kong集群。
服务注册与发现
如果采用Spring Cloud体系,则选择Eureka是最佳搭配,Eureka在Netflix经过大规模生产验证,支持跨数据中心,客户端配合Ribbon可以实现灵活的客户端软负载。Consul也是不错选择,天然支持跨数据中心,还支持KV模型存储和灵活健康检查能力。
配置中心
如果采用Spring Cloud体系,则可以选择Spring Cloud Config,不过个人并不推荐。因为它有点算不上生产级,很多治理能力缺失,小规模的场景可以试用。个人强力推荐Apollo配置中心,是携程推出的,也是经过了携程大规模的生产验证,具备高可用,配置实时生效(推拉结合),配置审计,分环境部署和版本化。
六、服务安全选型
对于服务安全这块,目前业界虽然有OAuth和OpenID connect等标准协议,但是由于企业一般都会有很多特殊的定制需求,整个社区没有形成通用的生产级开箱即用的产品。有一些开源授权服务器产品,比如:CAS、keycloak,spring security等,但是兼容性太差,缺乏灵活性。个人建议基于OAuth和OpenID connect标准,在参考一些开源产品的基础上(例如Mitre开源的 OpenID-Connect-Java-Spring-Server),定制自研轻量级授权服务器。
整块服务安全可以这样选型:
- 使用支持OAuth 2.0和OpenID connect标准协议的授权服务器(个人建议定制自研);
- 客户端在访问微服务之前,先通过授权服务器登录获取access token,然后带着access token和请求一起发送到API网关
- API网关一般是作为单一请求访问服务器入口,实现统一安全治理;
- API网关拿access token,通过授权服务器校验token,同时做token转换获取JWT token。
- API网关将JWT Token和请求一起转发到后台微服务;
- JWT中会存储一些用户的会话信息,该信息可以传递给后台的微服务,也可以在微服务之间传递,作为认证授权等用途;
- 每个微服务包含JWT客户端,能够解密JWT并获取其中的用户会话信息。
整个方案中,access token是一种by reference token,不包含用户信息可以暴露在公网上;JWT token是一种by value token,包含用户信息但不可以暴露在公网上。
七、服务容灾选型
针对Java技术栈,Netflix的Hystrix把熔断、隔离、限流和降级等能力封装成组件,任何依赖调用(数据库,服务,缓存)都可以封装在Hystrix Command之内,封装后自动具备容错能力。Hystrix起源于Netflix,经过Netflix大规模生产验证,目前是容错组件的社区标准。
Hystrix一般需要在应用端或者框架内埋点,有一定的使用门槛。对于采用集中式反向代理(边界和内部)做服务路由的公司,则可以集中在反向代理上做熔断限流,例如采用 nginx [附录12.25](github 5.1k stars)或者 Kong [附录12.7](github 11.4k stars)这类反向代理,它们都有插件支持灵活的限流容错配置。Zuul网关也可以集成Hystrix实现网关层集中式限流容错。集中式反向代理需要有一定的研发和运维能力,但是可以对限流容错进行集中治理,可以简化客户端。
Hystrix一般需要在应用端或者框架内埋点,有一定的使用门槛。对于采用集中式反向代理(边界和内部)做服务路由的公司,则可以集中在反向代理上做熔断限流,例如采用 nginx 或者 Kong 这类反向代理,它们都有插件支持灵活的限流容错配置。Zuul网关也可以集成Hystrix实现网关层集中式限流容错。集中式反向代理需要有一定的研发和运维能力,但是可以对限流容错进行集中治理,可以简化客户端。
八、服务监控选型
这块主要包括日志监控、调用链监控。健康检查和告警通知等产品。
日志监控
ELK目前可以认为是日志监控的标配。功能开箱即用,且在Elastalert里面还加入了告警通知模块。
调用链监控
目前社区主流的应该是美团点评的CAT,Twitter之前开源的Zipkin可以考虑一下。本人推荐美团点评开源的CAT,在多家公司都有经历生产级的磨练,另外CAT自带告警模块。可以看一下一下对比的表格:
- | CAT | Zipkin | Pinpoint |
---|---|---|---|
调用链可视化 | 有 | 有 | 有 |
报表 | 非常丰富 | 少 | 中 |
ServerMap | 简单依赖图 | 简单 | 好 |
埋点方式 | 侵入 | 侵入 | 不侵入字节码增强 |
心跳支持 | 有 | 无 | 有 |
java/.NET客户端支持 | 有 | 有 | 只支持java |
社区支持 | 好,文档较丰富 | 好,文档一般,暂无中文社区 | 一般,文档缺,暂无中文社区 |
国内案例 | 携程、点评 | 京东、阿里不开源 | 暂无 |
健康检查和告警
社区比较火的是Sensu,能够应对各种服务(例如spring boot暴露的健康检查端点,时间序列数据库中的metrics,ELK中的错误日志等)定制灵活的健康检查机制(check),然后用户可以针对check结果设置灵活的告警通知策略。同样的产品还有Esty和ZMon,但是定制check和告警配置的使用门槛比较高,社区不热,建议有定制自研能力的团队试用。
九、服务部署选型
容器已经被社区接受为交付微服务的一种理想手段,可以实现不可变(immutable)发布模式。一个轻量级的基于容器的服务部署平台主要包括系统发布平台,容器调度平台,镜像治理,用户资源治理和IAM等模块。
系统发布平台
面向用户发布管理控制台,支持发布流程编排,串并行发布皆可设置,它和其他子系统对接交互,实现基本的应用发布能力,也能实现蓝绿部署、金丝雀(灰度)部署、滚动部署等高级发布机制。这里简要介绍一下这三种部署机制:
蓝绿部署
蓝绿部署是不停老版本,部署新版本然后进行测试,确认OK,将流量切到新版本,然后老版本同时也升级到新版本。
无需停机,风险较小,新版本在上线的过程没有修改老版本的内容,所以在部署期间,老版本的状态不受影响。
滚动部署
滚动部署一般是取出一个或者多个服务器停止服务,执行更新,并重新将其投入使用。周而复始,直到集群中所有实例都更新到新版本。
相对蓝绿版本的好处是更加节省资源,不需要去维护两套集群、两倍的实例数,可以部分部署,例如每次只取出集群中的百分之20进行升级。缺点也很多:
(1) 没有一个确定OK的环境。使用蓝绿部署,我们能够清晰地知道老版本是OK的,而使用滚动发布,我们无法确定。
(2) 修改了现有的环境。
(3) 如果需要回滚,很困难。举个例子,在某一次发布中,我们需要更新100个实例,每次更新10个实例,每次部署需要5分钟。当滚动发布到第80个实例时,发现了问题,需要回滚,这个回滚却是一个痛苦,并且漫长的过程。
(4) 因为是逐步更新,那么我们在上线代码的时候,就会短暂出现新老版本同时并存的情况,如果对上线要求较高的场景,那么就需要考虑如何做好兼容的问题。
灰度发布/金丝雀部署
灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。
AB test就是一种灰度发布方式,用nginx或者网关,切一部分用户继续用A,一部分用户开始用B。如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。
灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度,而我们平常所说的金丝雀部署也就是灰度发布的一种方式。
除此之外灰度发布还可以设置路由权重,动态调整不同的权重来进行新老版本的验证。
容器调度平台
屏蔽底层的容器系统,将容器集群抽象成容器资源池,支持按需申请和释放容器资源,多种脚本语言同时运行不会出现数据安全问题,物理机发生故障时能实现自动迁移。目前谷歌开源的Kubernetes,即K8s,在谷歌背书和社区的强力推动下,基本上已经形成龙头型产品了 。其他还有mesos和swarm,不过不具竞争力了。
镜像治理
基于docker registry,封装一些轻量级的治理功能。vnware开源的harbor是目前社区比较成熟的企业级产品,在docker registy基础上拓展了权限控制,审计,镜像同步,管理界面等治理能力,可以考虑采用。
用户资源治理
类似CMDB的思路,在容器集群中也应该要有一个configuration manage去管理应用app,组织org,容器配置和数量等相关信息的轻量级治理产品。目前这块还没有开源的生产级产品,需要企业自研。
考虑到服务部署平台还没有端到端的生产级解决方案,企业一般需要自己定制方案集成,下面给出一个可供参考的轻量级部署平台的发布体系:(建议反复阅读)
1、应用通过CI集成后生成镜像,用户将镜像推到 镜像治理中心①。
2、用户在 用户资源治理中心② 申请发布,填报应用,发布,发布配置等信息,并等待审批通过。
3、审批等过,开发人员通过 发布控制台③ 发布应用。
4、服务部署平台通过 用户资源治理中心② 可以查询到发布规格信息。
5、发布控制台向 容器云④ 发送启动容器实例指令。
6、容器云④ 从 镜像治理中心① 拉取镜像并启动容器。
7、容器云中的服务启动后自动注册到 服务注册中心⑤ ,并定期保持心跳长连接。
8、用户通过 发布控制台③ 调用 服务注册中心⑤ 调拨流量,实现蓝绿部署、金丝雀(灰度)部署、滚动部署等发布机制。
9、网关⑥ 和 内部的微服务⑦ 定期的去 服务注册中心⑤ 上拉取最新的服务路由表,将流量按负载均衡策略分发到 容器云④ 上的新微服务实例上。
十、写在后面的话
注意,本文限于篇幅,对测试和CI等环节没有涉及,但它们同样是构建微服务架构的重要环节,也有众多成熟的开源成熟产品可选。
技术选型虽然重要,但还只是微服务建设的一小部分工作,选型后的产品要在企业内部真正落地,形成完整的微服务技术栈体系,则后续还有大量集成、定制、治理、运维和推广等工作。
本文仅限个人经验视角,选型思路仅供参考借鉴。每个企业的具体上下文(业务场景,团队组织,技术架构等)各不相同,每个架构师的背景经验也各不相同,大家要结合实际自己做出选型,没有最好的技术栈,只有相对较合适的技术栈。另外,好的技术选型是相互借鉴甚至PK出来的,欢迎大家讨论,给出自己的微服务2.0技术栈选型意见。
下面附各类开源微服务产品的社区地址:
Spring Boot
https://github.com/spring-projects/spring-boot
Alibaba Dubbo
https://github.com/alibaba/dubbo
Google gRPC
https://github.com/grpc/grpc
NetflixOSS Eureka
https://github.com/Netflix/eureka
Hashicorp Consul
https://github.com/hashicorp/consul
NetflixOSS Zuul
https://github.com/Netflix/zuul
Kong
https://github.com/Kong/kong
Spring Cloud Config
https://github.com/spring-cloud/spring-cloud-config
CTrip Apollo
https://github.com/ctripcorp/apollo
ElasticSearch
https://github.com/elastic/elasticsearch
Yelp Elastalert
https://github.com/Yelp/elastalert
Dianping CAT
https://github.com/dianping/cat
Zipkin
https://github.com/openzipkin/zipkin
Naver Pinpoint
https://github.com/naver/pinpoint
OpenTSDB
https://github.com/OpenTSDB/opentsdb
KairosDB
https://github.com/kairosdb/kairosdb
Argus
https://github.com/salesforce/Argus
InfluxDB
https://github.com/influxdata/influxdb
Prometheus
https://github.com/prometheus/prometheus
Grafana
https://github.com/grafana/grafana
Sensu
https://github.com/sensu/sensu
Esty 411
https://github.com/etsy/411
Zalando ZMon
https://github.com/zalando/zmon
NetflixOSS Hystrix
https://github.com/Netflix/Hystrix
Nginx
https://github.com/nginx/nginx
Apache Kafka
https://github.com/apache/kafka
Allegro Hermes
https://github.com/allegro/hermes
Apache Rocketmq
https://github.com/apache/rocketmq
Rabbitmq
https://github.com/rabbitmq/rabbitmq-server
Sohutv CacheCloud
https://github.com/sohutv/cachecloud
Twitter twemproxy
https://github.com/twitter/twemproxy
CodisLab codis
https://github.com/CodisLabs/codis
Dangdang Sharding-jdbc
https://github.com/shardingjdbc/sharding-jdbc
MyCAT
https://github.com/MyCATApache/Mycat-Server
Xxl-job
https://github.com/xuxueli/xxl-job
Dangdang elastic-job
https://github.com/elasticjob/elastic-job-lite
Apereo CAS
https://github.com/apereo/cas
JBoss keycloak
https://github.com/keycloak/keycloak
Spring cloud security
https://github.com/spring-cloud/spring-cloud-security
OpenID-Connect-Java-Spring-Server
https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server
Google Kubernetes
https://github.com/kubernetes/kubernetes
Apache Mesos
https://github.com/apache/mesos
Vmware Harbor
https://github.com/vmware/harbor
Netflix Spinnaker
https://github.com/spinnaker/spinnaker
Microservices in Practice – Key Architecture Concepts of an MSA
https://wso2.com/whitepapers/microservices-in-practice-key-architectural-concepts-of-an-msa/
微服务的设计与生态系统
http://servicecomb.incubator.apache.org/assets/slides/20170619/MSAPrinciple&EcoSystem.pdf