文章导读
一、同步和异步进程间通信
虽然微服务通常是单独部署的,但大多数企业级微服务架构要求服务彼此交互以及与其他外部服务交互。 使用进程间通信(IPC)机制实现该通信。 根据应用程序的要求,微服务之间的通信可以是同步的或异步的。
同步通信
同步通信基于请求和响应模型。 在此模型中,客户端等待服务的及时响应。 一个常见的示例是通过HTTP与REST服务进行通信。
在该图中,乘客正在使用智能手机客户端购买新的火车票。 电话客户端向旅行管理服务发送POST请求。 旅行管理服务向乘客管理服务发送GET请求。 乘客管理服务向状态200 OK发送响应,返回到行程管理,其返回成功状态201 CREATED。 在此示例中,两个客户端都在等待响应。
同步IPC - 优点和缺点
优点
缺点
异步消息通信
微服务可以使用基于异步消息的通信(例如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。
三、描述API网关模式
在开发微服务时解决服务发现问题的另一种方法是使用API网关模式。基于微服务的应用程序的客户面临许多挑战,包括:
API网关模式通过提供中间服务来解决所有这些问题,该中间服务充当后端微服务和以UI为中心的客户端(例如Web应用程序或移动应用程序)之间的传递层。
使用API网关
API网关是一种服务,是一个或多个微服务的主要入口点。 网关通过将请求代理到预期的微服务来处理请求。 API网关负责请求路由,组合,协议转换,安全性,缓存和分析。
移动客户端不使用网关直接与多个微服务通信
移动客户端通过API网关与多个微服务进行通信
使用API网关的优点
使用API网关的缺点
四、了解容错
使用断路器和隔板模式为基于微服务的应用提供容错。容错意味着服务可以处理故障,最终用户体验不会受到单个服务故障的影响。在基于微服务的应用程序中,容错是必不可少的,因为存在很多故障点。
描述断路器模式
断路器模式是,用于避免微服务架构中的级联服务故障的应用设计模式。级联故障可能由于多种原因而发生。在运行依赖于子系统的微服务应用程序中,当单个依赖关系在高容量下显示增加的延迟时,上游系统中的用户请求线程变得饱和,整个应用程序可能变得无响应,从而导致级联故障。
断路器模式,有助于确保微服务,可以优雅地处理其所依赖的服务的下游故障。 断路器对象将函数调用包装到依赖服务并监视调用是否成功。 当一切正常并且呼叫成功时,断路器处于闭合状态。 当故障次数(呼叫期间的异常或超时)达到预先配置的阈值时,断路器跳闸。 当断路器打开时,不会对从属服务进行调用,但会返回回退响应。 在可配置的时间量之后,断路器移动到半开状态。 在半开状态中,断路器定期执行服务呼叫以检查从属服务的健康状况。 如果服务再次健康,并且测试呼叫成功,则电路状态切换回关闭状态。 断路器生命周期如下图所示:
回顾断路器实现
Hystrix库实现了断路器和隔板模式。 它是Netflix OSS套件的一部分。 Hystrix还包括Hystrix仪表板,允许开发人员实时监控Hystrix指标。 仪表板还提供流聚合,以使用Netflix Turbine监控服务器群集。
断路器模式的其他实现可在以下方式使用:
描述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。
七、维护微服务中的安全性
在基于微服务的应用程序中,通过一系列独立服务维护身份和访问管理可能是一个真正的挑战。要求每个服务呼叫包括认证步骤并不理想。幸运的是,有许多可能的解决方案,包括:
使用API网关的客户端令牌:API网关缓存客户端令牌。令牌的验证由API网关处理。
魏新宇