基于 Docker 的微服务架构实践

基于 Docker 的微服务架构-分布式企业级实践

前言

基于 Docker 的容器技术是在2015年的时候开始接触的,两年多的时间,作为一名 Docker 的 DevOps,也见证了 Docker 的技术体系的快速发展。本文主要是结合在公司搭建的微服务架构的实践过程,做一个简单的总结。希望给在创业初期探索如何布局服务架构体系的 DevOps,或者想初步了解企业级架构的同学们一些参考。

Microservice 和 Docker

对于创业公司的技术布局,很多声音基本上是,创业公司就是要快速上线快速试错。用单应用或者前后台应用分离的方式快速集成,快速开发,快速发布。但其实这种结果造成的隐性成本会更高。当业务发展起来,开发人员多了之后,就会面临庞大系统的部署效率,开发协同效率问题。然后通过服务的拆分,数据的读写分离、分库分表等方式重新架构,而且这种方式如果要做的彻底,需要花费大量人力物力。

个人建议,DevOps 结合自己对于业务目前以及长期的发展判断,能够在项目初期使用微服务架构,多为后人谋福。

随着 Docker 周围开源社区的发展,让微服务架构的概念能有更好的一个落地实施的方案。并且在每一个微服务应用内部,都可以使用 DDD(Domain-Drive Design)的六边形架构来进行服务内的设计。关于 DDD 的一些概念也可以参考之前写的几篇文章:领域驱动设计整理——概念&架构领域驱动设计整理——实体和值对象设计领域服务、领域事件

清晰的微服务的领域划分,服务内部有架构层次的优雅的实现,服务间通过 RPC 或者事件驱动完成必要的 IPC,使用 API gateway 进行所有微服务的请求转发,非阻塞的请求结果合并。本文下面会具体介绍,如何在分布式环境下,也可以快速搭建起来具有以上几点特征的,微服务架构 with Docker。

服务发现模式

如果使用 Docker 技术来架构微服务体系,服务发现就是一个必然的课题。目前主流的服务发现模式有两种:客户端发现模式,以及服务端发现模式。

客户端发现模式

客户端发现模式的架构图如下:

微服务客户端服务发现-Eureka

客户端发现模式的典型实现是Netflix体系技术。客户端从一个服务注册服务中心查询所有可用服务实例。客户端使用负载均衡算法从多个可用的服务实例中选择出一个,然后发出请求。比较典型的一个开源实现就是 Netflix 的 Eureka。

Netflix-Eureka

Eureka 的客户端是采用自注册的模式,客户端需要负责处理服务实例的注册和注销,发送心跳。

在使用 SpringBoot 集成一个微服务时,结合 SpringCloud 项目可以很方便得实现自动注册。在服务启动类上添加@EnableEurekaClient即可在服务实例启动时,向配置好的 Eureka 服务端注册服务,并且定时发送以心跳。客户端的负载均衡由 Netflix Ribbon 实现。服务网关使用 Netflix Zuul,熔断器使用 Netflix Hystrix

除了服务发现的配套框架,SpringCloud 的 Netflix-Feign,提供了声明式的接口来处理服务的 Rest 请求。当然,除了使用 FeignClient,也可以使用 Spring RestTemplate。项目中如果使用@FeignClient可以使代码的可阅读性更好,Rest API 也一目了然。

服务实例的注册管理、查询,都是通过应用内调用 Eureka 提供的 REST API 接口(当然使用 SpringCloud-Eureka 不需要编写这部分代码)。由于服务注册、注销是通过客户端自身发出请求的,所以这种模式的一个主要问题是对于不同的编程语言会注册不同服务,需要为每种开发语言单独开发服务发现逻辑。另外,使用 Eureka 时需要显式配置健康检查支持。

服务端发现模式

服务端发现模式的架构图如下:

微服务-服务端服务发现-Consul,etcd,zk

客户端向负载均衡器发出请求,负载均衡器向服务注册表发出请求,将请求转发到注册表中可用的服务实例。服务实例也是在注册表中注册,注销的。负载均衡可以使用可以使用 Haproxy 或者 Nginx。服务端发现模式目前基于 Docker 的主流方案主要是 Consul、Etcd 以及 Zookeeper。

Consul

Consul 提供了一个 API 允许客户端注册和发现服务。其一致性上基于RAFT算法。通过 WAN 的 Gossip 协议,管理成员和广播消息,以完成跨数据中心的同步,且支持 ACL 访问控制。Consul 还提供了健康检查机制,支持 kv 存储服务(Eureka 不支持)。Consul 的一些更详细的介绍可以参考之前写的一篇:Docker 容器部署 Consul 集群

Etcd

Etcd 都是强一致的(满足 CAP 的 CP),高可用的。Etcd 也是基于 RAFT 算法实现强一致性的 KV 数据同步。Kubernetes 中使用 Etcd 的 KV 结构存储所有对象的生命周期。

关于 Etcd 的一些内部原理可以看下etcd v3原理分析

Zookeeper

ZK 最早应用于 Hadoop,其体系已经非常成熟,常被用于大公司。如果已经有自己的 ZK 集群,那么可以考虑用 ZK 来做自己的服务注册中心。
Zookeeper 同 Etcd 一样,强一致性,高可用性。一致性算法是基于 Paxos 的。对于微服务架构的初始阶段,没有必要用比较繁重的 ZK 来做服务发现。

服务注册

服务注册表是服务发现中的一个重要组件。除了 Kubernetes、Marathon 其服务发现是内置的模块之外。服务都是需要注册到注册表上。上文介绍的 Eureka、consul、etcd 以及 ZK 都是服务注册表的例子。

微服务如何注册到注册表也是有两种比较典型的注册方式:自注册模式,第三方注册模式。

自注册模式 Self-registration pattern

上文中的 Netflix-Eureka 客户端就是一个典型的自注册模式的例子。也即每个微服务的实例本身,需要负责注册以及注销服务。Eureka 还提供了心跳机制,来保证注册信息的准确,具体的心跳的发送间隔时间可以在微服务的 SpringBoot 中进行配置。

如下,就是使用 Eureka 做注册表时,在微服务(SpringBoot 应用)启动时会有一条服务注册的信息:

com.netflix.discovery.DiscoveryClient    : DiscoveryClient_SERVICE-USER/{your_ip}:service-user:{port}:cc9f93c54a0820c7a845422f9ecc73fb: registering service...

同样,在应用停用时,服务实例需要主动注销本实例信息:

2018-01-04 20:41:37.290  INFO 49244 --- [       Thread-8] c.n.e.EurekaDiscoveryClientConfiguration : Unregistering application service-user with eureka with status DOWN
2018-01-04 20:41:37.340  INFO 49244 --- [       Thread-8] com.netflix.discovery.DiscoveryClient    : Shutting down DiscoveryClient ...
2018-01-04 20:41:37.381  INFO 49244 --- [       Thread-8] com.netflix.discovery.DiscoveryClient    : Unregistering ...
2018-01-04 20:41:37.559  INFO 49244 --- [       Thread-8] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_SERVICE-USER/{your_ip}:service-user:{port}:cc9f93c54a0820c7a845422f9ecc73fb - deregister  status: 200

自注册方式是比较简单的服务注册方式,不需要额外的设施或代理,由微服务实例本身来管理服务注册。但是缺点也很明显,比如 Eureka 目前只提供了 Java 客户端,所以不方便多语言的微服务扩展。因为需要微服务自己去管理服务注册逻辑,所以微服务实现也耦合了服务注册和心跳机制。跨语言性比较差。

第三方注册模式 Third party registration pattern

第三方注册,也即服务注册的管理(注册、注销服务)通过一个专门的服务管理器(Registar)来负责。Registrator 就是一个开源的服务管理器的实现。Registrator 提供了对于 Etcd 以及 Consul 的注册表服务支持。 Registrator 作为一个代理服务,需要部署、运行在微服务所在的服务器或者虚拟机中。比较简单的安装方式就是通过 Docker,以容器的方式来运行。三方注册模式的架构图如下:

微服务-Registrator-服务端模式,服务发现

通过添加一个服务管理器,微服务实例不再直接向注册中心注册,注销。由服务管理器(Registar)通过订阅服务,跟踪心跳,来发现可用的服务实例,并向注册中心(consul、etcd 等)注册,注销实例,以及发送心跳。这样就可以实现服务发现组件和微服务架构的解耦。

Registrator 配合 Consul,以及 Consul Template 搭建服务发现中心,可以参考: Scalable Architecture DR CoN: Docker, Registrator, Consul, Consul Template and Nginx 。此文示例了 Nginx 来做负载均衡,在具体的实施过程中也可以用 Haproxy 或其他方案进行替代。

小结

除了以上几种做服务发现的技术,Kubernetes 自带了服务发现模块,负责处理服务实例的注册和注销。Kubernetes 也在每个集群节点上运行代理,来实现服务端发现路由器的功能。如果编排技术使用的 k8n,可以用 k8n 的一整套 Docker 微服务方案,对 k8n 感兴趣的可以阅读下Kubernetes 架构设计与核心原理

在实际的技术选型中,最主要还是要结合业务、系统的未来发展的特征进行合理判断。

  • 在 CAP 理论中。Eureka 满足了 AP,Consul 是 CA,ZK 和 Etcd 是 CP。 在分布式场景下 Eureka 和 Consul 都能保证可用性。而搭建 Eureka 服务会相对更快速,因为不需要搭建额外的高可用服务注册中心,在小规模服务器实例时,使用 Eureka 可以节省一定成本。
  • Eureka、Consu
收藏 收藏
分享
购买文章 ¥1.99