详细描述微服务架构模式 | 微服务系列第三篇

文章导读

  • 本文仅代表作者的个人观点;
  • 本文的内容仅限于技术探讨,不能作为指导生产环境的素材;
  • 本文素材是红帽公司产品技术和手册;
  • 本文分为系列文章,将会有多篇,初步预计将会有26篇。
  • 微服务是小型,独立,松散耦合和可独立部署的服务。它们是分散的,可以用不同的编程语言开发,在自己的进程中运行,并使用轻量级机制进行通信。
  • 微服务以业务功能或域为模型。这些域可以进一步分为域和子域,称为有界上下文。
  • 微服务使用进程间通信,同步或异步进行交互。
  • API网关模式为所有客户端提供单一入口点,并简化了服务发现。
  • 断路器和隔板模式在调用相关服务的微服务中提供容错。
  • 日志聚合将来自所有微服务的日志存储在中央位置。 OpenShift使用EFK堆栈进行日志聚合。
  • 基于令牌的身份验证技术(如单点登录,分布式会话,客户端令牌和带有API网关的客户端令牌)有助于保护微服务。

一、同步和异步进程间通信

虽然微服务通常是单独部署的,但大多数企业级微服务架构要求服务彼此交互以及与其他外部服务交互。 使用进程间通信(IPC)机制实现该通信。 根据应用程序的要求,微服务之间的通信可以是同步的或异步的。

同步通信

同步通信基于请求和响应模型。 在此模型中,客户端等待服务的及时响应。 一个常见的示例是通过HTTP与REST服务进行通信。

在该图中,乘客正在使用智能手机客户端购买新的火车票。 电话客户端向旅行管理服务发送POST请求。 旅行管理服务向乘客管理服务发送GET请求。 乘客管理服务向状态200 OK发送响应,返回到行程管理,其返回成功状态201 CREATED。 在此示例中,两个客户端都在等待响应。

同步IPC - 优点和缺点

优点

  • 易于编程和测试
  • 提供更好的实时响应
  • 使用标准防火墙端口
  • 无需中间代理或其他集成软件

缺点

  • 仅支持请求和响应样式交互
  • 客户和服务都必须在整个交换期间可用
  • 客户端必须知道服务的URL(位置)或使用服务发现机制来定位服务实例

异步消息通信

微服务可以使用基于异步消息的通信(例如AMQP或MQTT协议)进行通信。 微服务可以使用其他基于消息的模式,如点对点、发布和订阅、请求和回复、或请求和通知。 异步通信是非阻塞的,因此客户端能够继续发出无需等待接收响应的请求。

在上图中,三个服务:旅行管理、乘客管理和驾驶员管理,使用单个发布 - 订阅信道从调度员接收消息。 旅行管理服务使用另一个发布 - 订阅频道向调度员发送消息。 在该示例中,当提交新旅行时,调度员服务不直接回复旅行管理服务。 相反,它进行一些内部处理,然后,一旦准备就绪,使用不同的渠道来回复旅行管理服务,以及通知乘客和驾驶员管理服务。 这种异步方法允许旅行管理服务继续处理用户对更多新旅行的请求,而无需等待调度员的处理和后续响应。

异步通信 - 优点和缺点

优点

  • 将客户端与服务分离:客户端不知道服务实例,不需要发现机制。
  • 消息缓冲:消息代理在消费者缓慢或不可用时将消息排入消息缓冲区。
  • 灵活的客户端 - 服务交互:客户端和服务之间的通信非常灵活。客户端无需接收消息。消息支持各种样式以确保消息传递。

缺点

  • 额外的操作复杂性:消息组件还有其他配置。消息代理组件必须具有高可用性以确保系统可靠性。
  • 实现基于请求和响应的交互的复杂性:每个请求消息必须包含应答信道和相关标识符。该服务将响应和相关标识符写入回复通道。客户端使用相关标识符识别消息。

二、了解服务发现

单个应用程序中的服务:

1.通过使用过程调用或语言级方法相互调用。

2. 使用EJB / CDI甚至JNDI来查找类路径上的资源。

在传统的分布式系统部署中,服务必须使用HTTP / REST或远程过程调用(RPC)机制相互调用,并且服务在已知的固定位置(主机和端口)上运行。

基于微服务的应用程序通常在虚拟化或容器化的云环境中运行。 网络位置会动态分配给服务实例,并且可能会因故障,自动扩展和升级而发生变化。 这些频繁的变化使服务发现具有挑战.

微服务的客户端必须能够通过不断变化的网络位置发现这些服务实例以进行API调用。 这些客户端需要一个精心设计的机制来成功发现服务。 有两种主要的服务发现模式:客户端发现和服务器端发现。

客户端服务发现模式

使用客户端服务发现模式时,客户端将查询服务注册表数据库中的可用服务实例。 然后,客户端使用负载平衡算法选择一个可用的服务实例。 选择服务实例后,客户端发出请求。 服务启动时,它会在服务注册表中注册其位置。 当服务实例终止时,将从服务注册表中删除其服务注册。 服务注册表由心跳机制定期更新。

服务器端服务发现模式

使用服务器端服务发现模式时,客户端通过负载均衡器向服务发出请求。 负载均衡器查询注册表,然后将每个请求路由到可用的服务实例。 与服务器端服务发现类似,客户端仍必须在注册表中注册自己,注册表负责监视其健康状况和准备情况,并删除任何不可用的客户端。

在Kubernetes和OpenShift中查看服务发现

OpenShift提供自己的服务发现机制,利用动态DNS正确路由请求。 在OpenShift中,服务在pod中运行,pods相当于容器的虚拟机实例。 可以将服务放置在一组pod上,这些pod可以在相同或不同的物理主机上运行。 服务是具有IP地址和端口的可路由对象,该端口充当外部通信的服务端点。 创建后,使用选择器标签将服务映射到pod或pod组。 然后,唯一的名称与DNS解析的每个服务相关联。 在较高级别,服务现在可以充当组中所有pod的负载均衡器。

容器可以使用环境变量来注入其他服务端点的值。 Kubernetes可以创建可在所有pod中访问的环境变量。 例如,服务redis-master(公开TCP端口6379并具有分配的集群IP地址10.0.0.11)会生成以下环境变量:

REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11

集群级DNS内置于Kubernetes中。 群集DNS指向群集IP。 群集IP是在创建服务对象时分配给服务的虚拟IP。 群集IP是固定IP,因此DNS缓存没有问题。

内部DNS服务器为每个服务创建一组DNS记录。 DNS服务器使用的命名系统是称为命名空间的分层和逻辑树。 在同一名称空间内,使用其名称解析服务。 其他命名空间中的Pod可以通过将命名空间添加到DNS路径来访问服务,如以下示例所示:

my-service.my-namespace.svc.cluster.local

Kubernetes / OCP服务类型

Kubernetes ServiceTypes指定服务的类型。 默认类型是ClusterIP。

  • ClusterIP:在集群内部IP上公开服务。 该服务只能从群集中访问。
  • NodePort:在静态端口(NodePort)上公开每个Node的IP上的服务。 可以通过每个节点上的外部NodeIP:NodePort地址访问该服务。
  • LoadBalancer:使用云提供商的负载均衡器在外部公开服务。
  • 路由:以主机名公开服务,以便外部客户端可以按名称访问它。

三、描述API网关模式

在开发微服务时解决服务发现问题的另一种方法是使用API网关模式。基于微服务的应用程序的客户面临许多挑战,包括:

  • 微服务提供细粒度的API。基于微服务的应用程序的客户端需要与不同的服务进行交互。
  • 不同客户需要不同的数据。例如,产品详细信息页面的桌面浏览器版本通常比移动版本更精细。
  • 不同类型的客户端的网络性能不同。例如,移动和LAN客户端通常受到不同网络性能的影响。
  • 服务实例的数量及其位置(主机名和端口号)动态更改。
  • 将上下文划分为服务可以随着时间的推移而改变,并且应该从客户端隐藏。
  • 服务可能使用多种协议,其中一些协议(如AMQP和二进制RPC(Thrift))可能不适合Web。

API网关模式通过提供中间服务来解决所有这些问题,该中间服务充当后端微服务和以UI为中心的客户端(例如Web应用程序或移动应用程序)之间的传递层。

使用API网关

API网关是一种服务,是一个或多个微服务的主要入口点。 网关通过将请求代理到预期的微服务来处理请求。 API网关负责请求路由,组合,协议转换,安全性,缓存和分析。

移动客户端不使用网关直接与多个微服务通信

移动客户端通过API网关与多个微服务进行通信

使用API网关的优点

  • 减少客户端与服务的耦合:将客户端与应用程序结构隔离开来
  • 简化的服务发现:将客户端与服务实例位置隔离
  • 特定于客户端的API:为每种类型的客户端提供最佳API,简化客户端开发

使用API网关的缺点

  • 复杂性增加:表示必须开发,部署和管理的另一个高可用性组件(API网关)
  • 响应时间增加:通过API网关添加另一个网络跃点
  • 潜在的开发瓶颈:每当需要暴露新的微服务或API时都需要更新

四、了解容错

使用断路器和隔板模式为基于微服务的应用提供容错。容错意味着服务可以处理故障,最终用户体验不会受到单个服务故障的影响。在基于微服务的应用程序中,容错是必不可少的,因为存在很多故障点。

描述断路器模式

断路器模式是,用于避免微服务架构中的级联服务故障的应用设计模式。级联故障可能由于多种原因而发生。在运行依赖于子系统的微服务应用程序中,当单个依赖关系在高容量下显示增加的延迟时,上游系统中的用户请求线程变得饱和,整个应用程序可能变得无响应,从而导致级联故障。

断路器模式,有助于确保微服务,可以优雅地处理其所依赖的服务的下游故障。 断路器对象将函数调用包装到依赖服务并监视调用是否成功。 当一切正常并且呼叫成功时,断路器处于闭合状态。 当故障次数(呼叫期间的异常或超时)达到预先配置的阈值时,断路器跳闸。 当断路器打开时,不会对从属服务进行调用,但会返回回退响应。 在可配置的时间量之后,断路器移动到半开状态。 在半开状态中,断路器定期执行服务呼叫以检查从属服务的健康状况。 如果服务再次健康,并且测试呼叫成功,则电路状态切换回关闭状态。 断路器生命周期如下图所示:

回顾断路器实现

Hystrix库实现了断路器和隔板模式。 它是Netflix OSS套件的一部分。 Hystrix还包括Hystrix仪表板,允许开发人员实时监控Hystrix指标。 仪表板还提供流聚合,以使用Netflix Turbine监控服务器群集。

断路器模式的其他实现可在以下方式使用:

  • Hystrix EIP集成在Camel中
  • Vert.x断路器组件
  • Hystrix-javanica在Spring Boot中的集成
  • Wildfly Swarm Microprofile实现(基于Hystrix)

描述Bulkhead Pattern

使用隔板模式来隔离彼此的依赖关系,并限制尝试访问每个模块的并发线程数。将隔板应用于服务调用时,将为该调用分配一个专用线程池(信号量)。这种隔离意味着此调用仅限于使用多个线程,如果调用变得不饱和,或者相关服务性能不佳,则会影响服务其他部分的性能。

应用程序向组件发出连接请求。单个隔板控制与每个组件的连接。当发出新连接请求时,隔板会检查与所请求组件的连接是否可用。如果要建立连接的线程可用,则会分配连接。如果线程不可用,则等待预定义的时间间隔。如果线程在此持续时间内变为可用,则将连接分配给等待请求,否则它将拒绝该呼叫并调用回退。

五、分布式跟踪

在单一应用程序中,跟踪单个用户与系统的交互,可以通过隔离应用程序的单个实例并重现问题来完成。 基于微服务的应用程序很复杂; 单个微服务无法提供整个应用程序的行为,性能或正确性。

分布式跟踪是一种工具,可在请求通过多个服务时提供应用程序行为的完整信息。 分布式跟踪工具可以为运行服务配置文件以进行报告。 这些工具在中央聚合器中收集数据以进行存储,报告和可视化。

分布式跟踪使用代码注入服务,该代码为每个外部请求分配唯一的外部请求ID或跟踪ID。 跟踪ID将传递给处理请求所涉及的所有服务,并且跟踪ID包含在所有日志消息中。 每个服务都会向跟踪添加新的跨区ID。 该服务向范围添加元数据,例如开始和停止时间戳以及业务相关数据。 跨度数据由中央聚合器收集或发送到中央聚合器以进行存储和可视化。

OpenTracing API

OpenTracing API是一种供应商中立的开放标准,用于跟踪。 OpenTracing以最小的工作量提供应用程序的分布式跟踪。 它支持多种语言,例如Java,JavaScript和Go。 它在Twitter的Zipkin,Uber的Jaeger和Red Hat的Hawkular APM中实现。

六、使用聚合日志记录

大多数基于微服务的应用程序,由许多独立的微服务组成。这些服务负责执行独特的业务任务。此外,每个服务实例可以在多台机器上运行,也可以在单独的容器中运行每个运行的服务实例都有自己的日志。当服务在容器中运行时,日志将写入stdout和stderr,并且容器和日志都是短暂的。

有效地管理和监控所有这些日志是一项相当大的挑战。使用日志聚合机制将所有日志放入中央存储,并使用可以适当解析日志数据的工具。为了提供最大价值,服务应该以标准化和结构化的格式编写日志。应用程序记录器应该在日志消息中添加上下文,例如日期和时间,类名或线程号。日志应该是可索引的,可解析的,可过滤的和可搜索的。日志编码器可用于生成JSON日志消息。

OpenShift平台使用称为EFK(Elasticsearch,fluentd和Kibana)的堆栈进行日志聚合。使用fluentd收集日志,这是一个日志收集器守护程序,用于监视节点上所有正在运行的pod的容器日志。 Elasticsearch用于存储,索引和查询日志。 Kibana是用于日志可视化的Web UI。

七、维护微服务中的安全性

在基于微服务的应用程序中,通过一系列独立服务维护身份和访问管理可能是一个真正的挑战。要求每个服务呼叫包括认证步骤并不理想。幸运的是,有许多可能的解决方案,包括:

  • 单点登录:一种通用的身份验证和授权方法,允许客户端使用一组登录凭据来访问多个服务。
  • 分布式会话:一种在微服务和整个系统之间分配身份的方法。
  • 客户端令牌:客户端请求令牌并使用此令牌访问微服务。令牌由身份验证服务签名。微服务在不调用身份验证服务的情况下验证令牌。 JSON Web Token(JWT)是基于令牌的身份验证的示例。

使用API网关的客户端令牌:API网关缓存客户端令牌。令牌的验证由API网关处理。

魏新宇

  • "大魏分享"运营者、红帽资深解决方案架构师
  • 专注开源云计算、容器及自动化运维在金融行业的推广
  • 拥有MBA、ITIL V3、Cobit5、C-STAR、TOGAF9.1(鉴定级)等管理认证。
  • 拥有红帽RHCE/RHCA、VMware VCP-DCV、VCP-DT、VCP-Network、VCP-Cloud、AIX、HPUX等技术认证。

原文发布于微信公众号 - 大魏分享(david-share)

原文发表时间:2018-08-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我是攻城师

漫谈依赖管理工具:从Maven,Gradle到Go

4606
来自专栏农夫安全

【小技巧】获取到的cookie如何简便使用

首先假设我们通过XSS或者前端某骚姿势拿到某人的cookie【必须是完整cookie,因为cookie不完整也时候不能成功登录该用户的】

1052
来自专栏逸鹏说道

开发人员为何需要企业服务总线?

引言 重要的应用程序很少是单独存在的;如果不能与其他的应用程序一起使用,应用程序将难以发挥很大的作用。面向服务的体系结构往往将应用程序集成在一起,这样它们就可以...

2805
来自专栏张首富-小白的成长历程

CentOS系统优化脚本,未完结

sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

2202
来自专栏轻扬小栈

linux 百度客户端 非图形界面 小结

2045
来自专栏Esofar 开发日记

[转]Nginx基本功能极速入门

本文主要介绍一些Nginx的最基本功能以及简单配置,但不包括Nginx的安装部署以及实现原理。废话不多,直接开始。

1084
来自专栏黑白安全

中间件漏洞与防护

中间件漏洞可以说是最容易被web管理员忽视的漏洞,原因很简单,因为这并不是应用程序代码上存在的漏洞,而是属于一种应用部署环境的配置不当或者使用不当造成的 我们...

3003
来自专栏PHP实战技术

论linux下计划任务

小伙伴们,平时做程序开发的时候,是否也曾为实现一个商城网站或者一个小程序自动执行某个方法而苦恼呢?

20710
来自专栏王磊的博客

iBatis for Net 代码生成器(CodeHelper)附下载地址(已经升级为V 1.1)

CodeHelper是一款可以自己定义模板和生成内容的代码生成器,目前只支持MsSql数据库,这款代码生成器的初衷也只是为了生成MyBatis.net框架的配置...

3716
来自专栏月牙寂

docker源码分析(1)---框架与engine

第一时间获取文章,可以关注本人公众号 月牙寂道长 yueyajidaozhang

41011

扫码关注云+社区

领取腾讯云代金券