文章目录
- 应用层
- 微服务架构
- 服务注册查询 Service Discovery
- 客户端 Service Discovery
- DNS-SD DNS-based Service Discovery
- 服务端 Service Discovery
- 服务注册与注销
- 自注册模式
- 第三方注册模式
- 总结
- 参考
应用层
在简单的 3 层结构中,Web 服务层既要处理请求,又要承载业务功能:
而更优的结构是把 Web 层与应用层(也叫平台层)分开:
这样的优势在于:
- 能够单独扩展应用层;允许独立加机器、换专用机器
- 复用基础设施:简化多端支持,缓存、数据库等处理都可以复用
- 使得组织更容易扩展:一个团队负责实现/优化平台本身,其他多个团队利用平台功能进行开发
分离出应用层之后,面临的下一个问题是应用层内部如何划分职责,如何协同工作,也就是微服务架构所要解决的问题
微服务架构
Monolithic application 架构
把软件应用的不同组件都放到一个程序中,就叫 Monolithic application。例如,通过编程语言的基本特性将应用划分成类、函数和命名空间,用部署流水线来保证变更都经过测试后才部署到生产环境,并通过负载均衡机制运行多个实例,将其进行横向扩展。
在这种架构模式下,应用程序也能很好地工作,但存在 2 个问题:
- 变更受限制:很小的一处变更也需要对整个应用进行重新构建和部署,而且难以控制变更的影响范围
- 不利于扩展:无法仅扩展应用中需要更多资源的那些部分,只能扩展整个应用
这些限制在云环境下尤其突出。于是,微服务架构登上了舞台。
微服务架构提倡把应用程序设计成一系列松耦合的细粒度服务,并通过轻量级的通信协议组织起来。
这些服务都能够独立部署、独立扩展,每个服务都具有稳固的模块边界,甚至允许使用不同的编程语言来编写不同服务,也可以由不同的团队来管理。
微服务架构具有下面 9 大特征:
1、通过服务进行组件化(Componentization via Services)
组件可以理解为能够独立更换升级的软件单元,一系列组件插在一起构成软件系统。
在微服务架构中,组件就是服务,通过 Web 服务请求或 RPC 之类的机制通信。这种服务粒度的组件化方式有 2 点优势: - 服务能够独立部署
- 服务具有显式的对外接口
独立部署,意味着对一个服务的内部改动只需要重新部署该服务,涉及服务接口改动时才需要协同修改多个服务。另一方面,还可以通过服务边界和服务协议方面的演进来尽可能减少这样的关联。显式的对外接口则是一种强约束,能够保证组件的封装性,避免组件间出现过度的紧耦合。但比起进程内调用,RPC 的性能成本更高,因此 RPC 接口大多是粗粒度的,也往往更难使用。另一方面,如果想要调整组件职责的话,重构成本也更高。
2、围绕业务功能来组织团队(Organized around Business Capabilities)
微服务允许将系统根据业务功能分解成一系列服务,因此可以围绕业务功能来组织跨职能的团队。并且,这种组织结构还有利于强化服务边界。比起在 Monolithic application 中按业务线划分团队,以服务为边界更清晰、约束力也更强。因为很容易出现跨越模块边界的业务功能,而服务边界相对稳固一些。
3、做产品而不是做项目(Products not Projects)
微服务架构倾向于一个产品由所属开发团队长期维护/演进,而不是项目交付后转由另一个维护团队负责。
这种产品理念能够在开发团队与用户之间建立持续的关联,让开发团队关注到软件如何帮助用户增进业务功能。
4、智能端点和傻瓜式管道(Smart endpoints and dumb pipes)
通信机制上,一个典型的例子是企业服务总线(Enterprise Service Bus),消息都流经 ESB,由 ESB 负责消息路由、编排、转换以及业务规则的应用,随后到达端点(endpoints)进行处理。这种模式下,端点可以保持傻瓜式,因为很多逻辑都在 ESB 消息管道里处理了。因此,称之为智能管道和傻瓜式端点(smart pipes and dumb endpoints)。
而微服务倾向于相反的做法,智能端点和傻瓜式管道(smart endpoints and dumb pipes):管道只负责在组件之间分发消息,由服务本身针对消息做相应处理。
5、去中心化技术治理(Decentralized Governance)
中心化技术治理最大的问题在于其局限性,统一的技术栈并不一定适用于所有场景。
而在微服务背景下,每个服务单独构建,就有了选择不同技术栈的机会,允许用更合适的工具去做不同的事情。这种技术栈上的自由有助于服务独立演进,自然选择出更好的模式。
6、去中心化数据管理(Decentralized Data Management)
从最抽象的层面看,去中心化地管理数据,意味着各个系统对客观世界所形成的概念模型各不相同。给模型概念限定一个上下文,在该上下文中保证概念严格一致。把一个复杂领域划分成多个界限上下文,再将其间关联勾画出来,就是概念模型层面的去中心化。具体到数据存储上,微服务也进行类似的去中心化策略,让每一个服务管理自己的数据库。这些数据库可以是相同数据库的不同实例,也可以是完全不同的数据库系统,称之为混合持久化。对于去中心化数据存储带来的数据一致性问题,可以考虑通过一些补偿操作来让数据最终达到一致。
7、基础设施自动化(Infrastructure Automation)
与 Monolithic application 相比,微服务的部署要更复杂一些。因为在复杂的网络环境中,部署多个服务比部署一个独立应用更困难。
8、容错设计(Design for failure)
在微服务背景下,客户端的容错设计更为重要:
将服务作为组件使用的一个结果是,应用程序需要设计为能够容忍服务故障。
由于供应商不可用,任何服务呼叫都可能失败,客户必须尽可能优雅地响应。
比起 Monolithic application,这种容错设计带来的额外复杂性算是一种劣势。另一方面,为了快速检测到故障点,甚至尽可能自动恢复服务,实时监控在微服务架构中也格外重要。
9、演进式设计(Evolutionary Design)
组件的划分在微服务架构中很关键,关系到能否减少变化。一般原则是该组件能否独立更换和升级。
把微服务架构提供的服务分解能力当做一种工具来使用,以此实现服务粒度的变化控制:
- 预期一些服务将来会作废,不必长期演进
- 把那些会同时变化的东西放到同一个服务中,把很少发生变化的部分放到单独服务中,与经常发生变化的部分区分开
服务注册查询 Service Discovery
微服务架构下,应用被拆分成了多个服务,各自运行在(不同机器的)不同进程中。
如果每个微服务都只运行在单台机器上,一个微服务可以通过静态配置表找到其它依赖服务,进而通过服务间通信完成协作。然而,实际场景下,1 个微服务通常会部署在多台机器上,并按需动态伸缩(增减机器),简单的静态配置显然无法满足,因而需要一种服务注册查询机制:
这点即Service Discovery
客户端 Service Discovery
客户端查询服务注册表,得到目标服务的一系列地址,并根据负载均衡策略从中选择一个发起请求(即客户端负载均衡)。
其中,服务注册表(service registry)用来存放所有可用的服务实例,并提供管理(注册/注销)和查询 API:
服务注册表是可用服务实例的数据库。
服务注册中心提供了一个管理API和一个查询API。
使用管理API在服务注册表中注册和注销服务实例。
系统组件使用查询API来发现可用的服务实例。
具体的,在启动服务实例时,向注册表添加其网络位置,停掉服务时移除记录,并在服务实例运行期间,通过心跳机制周期性地刷新注册信息。
这种模式相对简单,而且客户端能够做出更聪明的(比如特定于应用程序的)负载均衡决策,但也存在一些缺点:
- 客户端用到的每种语言都要实现一遍
- 需要自行维护一个高可用的注册服务
- 服务发现相关逻辑都在客户端实现,比如重试,造成客户端比较重
DNS-SD DNS-based Service Discovery
特殊的,可以将 DNS 用作服务注册表,称之为DNS-SD(DNS-based Service Discovery)
通过 DNS SRV 记录来完成服务到实例的一对多映射:
SRV 记录(Service locator record):通用服务定位记录,指定服务所在的服务器(域名和端口号),多用于 SIP(Session Initiation Protocol,会话发起协议)
借助 DNS 虽然简单易操作,但受限于 DNS 的更新时效(缓存问题)
服务端 Service Discovery
当然,查询的过程也可以在服务端完成:
客户端通过负载均衡器请求目标服务,负载均衡器查注册表得到一组可用实例,并根据负载均衡策略从中选择一个发起请求。
这种模式下,客户端不必再为各种语言、不同框架实现服务查询逻辑,简单地向负载均衡器发起请求即可,但如果部署平台没有提供这种能力的话,需要自行建立并维护这样一个高可用的系统组件。
服务注册与注销
Service Discovery 中,服务实例必须注册到服务注册表,并及时注销,分为自注册与第三方注册 2 种模式。
自注册模式
自注册模式下,服务实例负责把自己注册到服务注册表,以及从中注销,必要的话,还要发送心跳请求保持活跃,避免其注册过期。这种方式相对简单,不依赖其它系统组件,但服务实例和服务注册机制产生了耦合,以致于注册逻辑需要在各种语言、不同框架的客户端都实现一遍。
第三方注册模式
服务实例不再负责注册/注销,交由服务登记员(service registrar)来处理,解除了服务实例与注册机制间的耦合关系。登记员通过轮询部署平台或订阅事件来跟踪服务实例的运行状态,发现新服务实例就注册上去,发现服务实例停掉了就注销掉。
例如Registrator就采用了这种模式,支持自动注册/注销用 Docker 容器部署的服务。
总结
微服务架构负责拆分服务、解耦依赖关系,而 Service Discovery 用来解决这些服务间的通信问题,让一个微服务能够找到另一个。
实现上,分为客户端 Service Discovery 与服务端 Service Discovery 两种,区别在于查询/选取逻辑实现在客户端还是服务端。而服务的注册/注销可以由服务自身完成(自注册),也可以由部署平台等第三方来完成(第三方注册)
参考
http://www.ayqy.net/blog/service-discovery/