为什么选择微服务
一般情况下,业务应用我们都会采用模块化的分层式架构,所有的业务逻辑代码最终会在一个代码库中并统一部署,我们称这种应用架构为单体应用。 单体应用的问题是,全部开发人员会共享一个代码库,不同模块的边界模糊,实现高内聚、松耦合极其困难。 肯定大家会碰到过这类场景,当尝试去重构改进代码时,改了一个地方好几个其他模块也需要同步改动, 当初划分的模块边界轻易被穿透,有人给这种应用的架构起了一个很形象的名字叫 “洋葱架构”。
Netflix是一家成功实践微服务架构的互联网公司,总结了一套行之有效的微服务方案。微服务架构强调 “微”,服务紧密围绕业务领域,形成高度内聚的自治性。
更多的单体应用和微服务优劣势请参看《微服务实战(一):微服务架构的优势与不足》。
微服务特征
业务能力建模:高内聚、松散耦合,暴露接口而隐藏实现细节
服务协作模型:中心化和去中心化
服务交互方式:RPC/REST等
自动化文化与环境:自动化构建、自动化测试、自动化部署
服务发布:灰度发布
服务部署:部署独立性、失败隔离性、可监控性;一服务一主机模型需要虚拟化、容器化
服务配置:中心化配置服务
服务流控:降级、限流
服务恢复:多考虑故障如何快速恢复服务而非如何避免故障发生
当前业界比较成熟的微服务框架有Netflix的Karyon/Ribbon,Spring的Spring Boot/Cloud,阿里的Dubbo等。
Netflix的微服务框架
Netflix是一家成功实践微服务架构的互联网公司,几年前,Netflix就把它的几乎整个微服务框架栈开源贡献给了社区,这些框架和组件包括:
- Eureka: 服务注册发现框架
- Zuul: 服务网关
- Karyon: 服务端框架
- Ribbon: 客户端框架
- Hystrix: 服务容错组件
- Archaius: 服务配置组件
- Servo: Metrics组件
- Blitz4j: 日志组件
微服务框架
1、服务注册、服务发现、健康检查
如果我们采用进程内LB方案,那么服务自注册一般统一做在服务器端框架中,健康检查逻辑由具体业务服务定制,框架层提供调用健康检查逻辑的机制,服务发现和负载均衡则集成在服务客户端框架中。
2、RPC/REST和序列化
框架层要支持将业务逻辑以HTTP/REST或者RPC方式暴露出来,HTTP/REST是当前主流API暴露方式,在性能要求高的场合则可采用Binary/RPC方式。针对当前多样化的设备类型(浏览器、普通PC、无线设备等),框架层要支持可定制的序列化机制,例如,对浏览器,框架支持输出Ajax友好的JSON消息格式,而对无线设备上的Native App,框架支持输出性能高的Binary消息格式。
3、管理接口
框架集成管理接口,一方面可以在线查看框架和服务内部状态,同时还可以动态调整内部状态,对调试、监控和管理能提供快速反馈。Spring Boot微框架的Actuator模块就是一个强大的管理接口。对于框架层和服务的内部异常,如果框架层能够统一处理并记录日志,对服务监控和快速问题定位有很大帮助。
4、安全控制
安全和访问控制逻辑可以在框架层统一进行封装,可做成插件形式,具体业务服务根据需要加载相关安全插件。
5、配置管理
除了支持普通配置文件方式的配置,框架层还可集成动态运行时配置,能够在运行时针对不同环境动态调整服务的参数和配置。
6、监控日志
框架一方面要记录重要的框架层日志、服务调用链数据,还要将日志、调用链数据等接口暴露出来,让业务层能根据需要记录业务日志数据。在运行环境中,所有日志数据一般由日志系统做进一步分析和处理。
7、统一错误处理
对于框架层和服务的内部异常,如果框架层能够统一处理并记录日志,对服务监控和快速问题定位有很大帮助。
8、流控和容错
框架集成限流容错组件,能够在运行时自动限流和容错,保护服务,如果进一步和动态配置相结合,还可以实现动态限流和熔断。
负载均衡
1、集中式的负载均衡方案
在服务消费者和服务提供者之间有一个独立的LB,LB通常是专门的硬件设备如F5,或者基于软件如LVS,HAproxy等实现。LB上有所有服务的地址映射表,通常由运维配置注册,当服务消费方调用某个目标服务时,它向LB发起请求,由LB以某种策略(比如Round-Robin)做负载均衡后将请求转发到目标服务。LB一般具备健康检查能力,能自动摘除不健康的服务实例。
服务消费方如何发现LB呢?通常的做法是通过DNS,运维人员为服务配置一个DNS域名,这个域名指向LB。
方案优缺点:
1)、单点问题,所有服务调用流量都经过LB,当服务数量和调用量大的时候,LB容易成为瓶颈,且一旦LB发生故障对整个系统的影响是灾难性的。
2)、LB在服务消费方和服务提供方之间增加了一跳(hop),有一定性能开销。
2、进程内的负载均衡方案
进程内LB方案将LB的功能以库Library的形式集成到服务消费方进程里头,该方案也被称为软负载(Soft Load Balancing)或者客户端负载方案。这一方案需要一个服务注册表(Service Registry)配合支持服务自注册和自发现,服务提供方启动时,首先将服务地址注册到服务注册表(同时定期报心跳到服务注册表以表明服务的存活状态,相当于健康检查),服务消费方要访问某个服务时,它通过内置的LB组件向服务注册表查询(同时缓存并定期刷新)目标服务地址列表,然后以某种负载均衡策略选择一个目标服务地址,最后向目标服务发起请求。这一方案对服务注册表的可用性(Availability)要求很高,一般采用能满足高可用分布式一致的组件(例如Zookeeper, Consul, Etcd等)来实现。
方案优缺点:
1)、是一种分布式方案,LB和服务发现能力被分散到每一个服务消费者的进程内部,同时服务消费方和服务提供方之间是直接调用,没有额外开销,性能比较好。
但由于该方案以客户库(Client Library)的方式集成到服务调用方进程里头,
2)、需要开发支持多种不同语言的客户端,有一定的研发成本。
3)、客户库Library跟随服务调用方发布到生产环境中,后续如果要对客户库Library进行升级,会有很大的维护成本。
阿里开源的服务框架Dubbo也是采用类似机制。
3、主机独立的负载均衡方案
主机独立LB进程方案,该方案是针对第二种方案的不足而提出的一种折中方案,原理和第二种方案基本类似,不同之处是,他将LB和服务发现功能从进程内移出来,变成主机上的一个独立进程,主机上的一个或者多个服务要访问目标服务时,他们都通过同一主机上的独立LB进程做服务发现和负载均衡。
方案优缺点:
1)、是一种分布式方案,没有单点问题,一个LB进程挂了只影响该主机上的服务调用方,服务调用方和LB之间是进程内调用,性能好,同时,该方案还简化了服务调用方,不需要为不同语言开发客户库,LB的升级不需要服务调用方改代码。
2)、不足是部署较复杂,环节多,出错调试排查问题不方便。
服务前端路由
IDL+Nginx+AOP
微服务除了内部相互之间调用和通信之外,最终要以某种方式暴露出去,才能让外界系统(例如客户的浏览器、移动设备等等)访问到,这就涉及服务的前端路由,对应的组件是服务网关(Service Gateway)。
服务网关service Gateway
1、服务反向路由
2、安全认证和防爬虫
3、限流和容错
4、监控
5、日志
服务容错
当我们的业务逐渐复杂以后,服务之间的依赖关系也会有错综复杂,例如,一个前端请求一般会依赖于多个后端服务。由于,服务往往不是百分百可靠,服务可能会出错或者产生延迟,如果一个应用不能对其依赖的故障进行容错和隔离,那么该应用本身就处在被拖垮的风险中。在一个高流量的网站中,某个单一后端一旦发生延迟,可能在数秒内导致所有应用资源(线程,队列等)被耗尽,造成所谓的雪崩效应(Cascading Failure),严重时可致整个网站瘫痪。
我们可以从不同的纬度避免和解决:
服务设计:
1、基础服务
2、复杂业务服务
3、减少服务复杂的依赖,尽量保持简单的依赖关系
容错设计:
1、故障隔离、容错
2、降级、限流
3、快速失败(Fail Fast):直接抛出异常、可以返回空值或缺省值
(未完待续)