davidsajare
作者davidsajare2020-02-12 23:20
副首席解决方案架构师, Red Hat

Spring Cloud如何OpenShift上落地?

字数 4997阅读 12968评论 0赞 5

本文节选《OpenShift在企业中的实践 PaaS DevOps 微服务》。 目前本书在京东和当当网五折促销(原价139,现在只需69.5,而且京东还有额外优惠券,优惠完59.5),优惠活动截止到2020年2月16日,好书不容错过!

7.1.1 Spring Cloud 在 OpenShift 上实现的不同

OpenShift 平台作为 PaaS 平台,原生针对微服务架构的应用提供了众多主流的微服务编排和治理工具,这些工具在互联网公司和一些大型企业有着长期广泛的应用,是实施微服务架构的最佳实践。

接下来,我们针对在 OpenShift 上运行 Spring Cloud 与原生 Spring Cloud 的不同点进行说明。

1. 服务注册与发现

在传统的分布式系统部署中,服务监听在固定的主机和端口运行,但在基于云的环境中,主机名和 IP 地址会动态变化,这就需要服务注册与发现。

许多微服务框架都提供实现服务注册和发现的组件,但它们通常仅适用于在框架内的其他服务。这些框架,都需要一个特殊的服务注册表来跟踪每个微服务的可用实例。

Spring Cloud 的服务注册发现和注册中心是 Eureka 或者 Consul (原生是 Eureka )。 OpenShift 平台的 ETCD 集群是用于存储集群元数据的高可用键值对存储系统,提供 OpenShift 集群内 Service 的服务注册与发现。这样在 OpenShift 上运行 Spring Cloud ,可以使用 OpenShift 平台的 Service 实现微服务的服务注册发现机制,然后存储到 ETCD 集群中。当然,我们也可以保持 Spring Cloud 原生的注册中心,在 OpenShift 上部署 Eureka 、 Consul 或 Zookeeper 。

我们举例说明在 OpenShift 上服务注册发现用 Consul 的例子( Consul 需要 pod 中以 sidecar 方式注入 Consul client )。在下图中 7-5 中, WebServer Service 中部署 Tomcat 应用,用于将内部微服务转换为 RESTful 接口。 Consul 集群(一主二从)在 OpenShift 中使用 DeploymentConfig 形式进行部署,通过 HostNetwork 方式固定 IP 和端口,在对集群内外提供服务的同时又可以满足高可用的要求。因采用 Hostnetwork 方式部署,集群内部的微服务及 WebServer 应用可以通过该 IP 及端口进行服务注册和发现,集群外部同样可以通过该 IP 及端口进行连接 ,如下图7-5所示:

图 7-5 使用 Consul 实现注册中心

虽然上述方式技术可行。但在 OpenShift 中部署 Spring Cloud ,我们推荐使用 Service 的服务发现机制,注册信息保存在 ETCD 中。

2. 微服务间负载均衡

Spring Cloud 的微服务的负载均衡主要通过 Ribbon 实现。在 OpenShift 中,每个微服务应用都有自己的 Service ,通过 Service 负责其后端多个 Pod 之间的负载均衡。关于这部分实现在第 2 章已经介绍,这里不再赘述。基于 OpenShift 的 Spring Cloud 实现微服务之间的负载均衡推荐使用 Service 底层的机制实现。

3. 配置管理中心

用户通过配置管理中心可以实现对云平台的快速、便捷、灵活化管理,以应对互联网时代业务快速发展的需要。 Spring Cloud 的配置中心可以使用 Config Server 。在 OpenShift 和 Spring Cloud 的配合中,我们建议使用 ConfigMap ,它可以用于存储配置文件和 JSON 数据。然后我们把 ConfigMap 挂载到 Pod 中或者作为环境变量传入,这样应用就可以加载相关的配置参数。

创建一个键值对的 ConfigMap ,我们可以用如下命令行创建:

# oc create configmap config_map_name --from-literal key1=value1 --from-literal key2=value2

也可以从一个文件创建:

# oc create configmap config_map_name --from-file /home/demo/conf.txt

然后在 DeploymentConfig 中注入 ConfigMap :

# oc set env dc/mydcname --from configmap/myconf

如果以 Volume 形式将创建的 ConfigMap 加载到 Pod 中,可以使用如下方法。

# oc set volume dc/mydcname --add -t configmap -m /path/to/mount/volume --name myvol --configmap-name myconf

4. 微服务网关

微服务中的 API 网关,提供了一个或多个 HTTP API 的自定义视图的分布式机制。一个 API 网关是为特定的服务和客户端定制的,不同的应用程序通常使用不同的 API 网关。

API 网关的使用场景包括:

l 聚合来自多个微服务的数据,以呈现基于 Web 浏览器的应用程序的统一视图。

l 桥接不同的消息传输协议,例如 HTTP 和 AMQP 。

l 实现同一个应用不同版本 API 的灰度发布。

l 使用不同的安全机制验证客户端。

目前,有多种方法可以实现 API 网关,如通过编程的方式实现 API 网关、使用工具实现微服务网关,如 Zuul 和 Apache Camel 。

Spring Cloud 默认使用 Zuul 提供微服务 API 网关能力,将 API 网关作为所有客户端的入口。在 OpenShift 上运行 Spring Cloud ,可以使用 Zuul 。但我们更推荐使用 Camel 作为微服务的网关。 Apache Camel 是一个基于规则路由和中介引擎,提供企业集成模式( EIP )的 Java 对象 (POJO) 的实现,通过 API 或 DSL ( Domain Specific Language )来配置路由和中介的规则。

关于 Camel 的具体实践,我们将在第 10 章进行详细介绍。在本章后面的实践中,我们使用的是 Apache Camel Java DSL 的模式。

5. 微服务的容错

在微服务中,容错是一个很重要的功能。它的作用是防止出现微服务的 “ 雪崩效应 ” 。雪崩效应, 是从 “ 雪球越滚越大 ” 的现象抽象出来的。在单体应用中,多个业务的功能模块放在一个应用中,功能模块之前是紧耦合,单体应用要么整体稳定运行,要么整体出现问题整体不可用。

但在微服务中,由于各个微服务模块是相对独立的,同时可能存在调用链。例如微服务 A 需要调用微服务 B ,微服务 B 需要调用微服务 C 。这个时候,如果微服务 C 出现了问题,可能最终导致微服务 A 不可用,问题的雪球越滚越大,最终可能会造成整个微服务体系的崩溃。

要想避免雪崩效应,就需要有容错机制,如采用断路模式。为每个微服务前面加一个 “ 保险丝 ” 。当电流过大的时候(如服务访问超时,并且超过设定的重试次数),保险丝烧断,中断客户端对该服务的访问,而访问其他正常的服务。

在 Spring Cloud 中,微服务的容错通过 Hytrix 实现。基于 OpenShift 的 Spring Cloud ,也需要通过 Hytrix 实现容错。

在启用 Hytrix 后, 当请求后端服务失败数量超过一定比例 , 断路器会切换到开路状态( Open ), 这时所有请求会直接失败而不会发送到后端服务。断路器保持在开路状态一段时间后 ( 默认 5 秒 ) ,自动切换到半开路状态 (HALF-OPEN) 。这时会判断下一次请求的返回情况 , 如果请求成功 , 断路器切回闭路状态 (CLOSED) ,否则重新切换到开路状态 (OPEN) 。

6. 微服务的日志和监控

大多数 Java 开发人员习惯使用标准 API 生成日志。传统应用程序依赖本地存储来保存这些日志,容器化应用程序需要将所有日志事件发送到标准输出流和错误流。

为了更好地利用日志查询功能,应用程序应生成结构化日志,通常是 JSON 格式的消息,而不是纯文本行,最流行的 Java 日志框架支持自定义日志的格式。

在微服务中,目前比较常用的聚合日志套件是 EFK ( Elasticsearch+Flunetd+Kibana )或 ELK ( Elasticsearch+Logstash +Kibana )。红帽 OpenShift 的日志管理使用的是 EFK , Fluentd 是实时的日志收集、处理引擎,它汇聚数据到 ElasticSearch ; ElasticSearch 会处理收集到的大量数据,用于全文搜索、结构化搜索以及分析; Kibana 是日志前端展示工具。

关于监控, OpenShift 平台提供了 Prometheus + Grafana 的开源监控解决方案,可以看到丰富的微服务监控界面。

7. 微服务分布式追踪

在微服务环境中,最终用户或客户端应用程序请求可以跨越多个服务。在这种情况下,使用传统技术无法对此请求进行调试和分析,也无法隔离单个进程来观察和排除故障。监视单个服务也不会提示哪个发起请求引发了哪个调用。

分布式跟踪为每个请求分配唯一 ID 。此 ID 包含在所有相关服务调用中,并且这些服务在进行进一步的服务调用时也包含相同的 ID 。这样,就可以跟踪从始发请求到所有相关请求的调用链。

每个从属服务还会添加跨度 ID ,该 ID 应与先前服务请求的跨度 ID 相关。这样,可以在时间和空间上对来自相同始发请求的多个服务调用进行排序。请求 ID 对于调用链中的所有服务都是相同的。调用链中的每个服务的跨度 ID 不同。

应用程序记录请求和跨区 ID ,还可以提供其他数据,例如开始和停止时间戳以及相关业务数据。收集这些日志或将其发送到中央聚合器以进行存储和可视化。

分布式跟踪的一个流行标准是 OpenTracing API ,该标准的一个流行实现是 Jaeger 项目。

要实现微服务的分布式追踪,使用原生的 Spring Cloud ,需要对接 Jaeger 。基于 OpenShift 的 Spring Cloud ,则通过服务的方式对接 OpenShift 中部署的 Jaeger 即可。

8. 服务请求入口

在 Spring Cloud 中,微服务流量的起始入口是 API 网关。在 OpenShift 中,流量的起始入口是 Router 。如果在 OpenShift 中运行 Spring Cloud ,我们需要为最外围的微服务(可能是 API 网关,也可能是 UI 的微服务)创建路由。而 Router 会将入口流量以负载均衡的方式分发给多个最外围的微服务的 Pod 。

Router 默认支持三种负载均衡策略:

l RoundRobin :根据每个 Pod 的权重,平均轮询分配。在不改变 Routing 的默认规则下,每个 Pod 的权重一样, Router 转发包也是采取轮询的方式。

l Leastconn : Router 转发请求的时候,按照哪个 Pod 的连接数最少,将新的请求发给连接数最少的 Pod 。一般这种方式适合长连接,短链接不建议使用。

l Source :将源 IP 地址先进行哈希,然后除以正在运行的 Pod 总权重,然后算出哪个节点接受请求。这确保了只要没有服务器发生故障,相同的客户端 IP 地址将始终到达同一个 Pod 。

我们看到,基于 OpenShift 的 Spring Cloud ,比社区原生的 Spring Cloud 的复杂度大大降低、可维护性有了较大提升。归纳总结如下表 7-2 所示:

表 7-2 : Spring Cloud 在 OpenShift 上的实现


如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

5

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广