写点什么

通过容器编排和服务网格来改进 Java 微服务的可测性

  • 2018-08-09
  • 本文字数:4774 字

    阅读完需:约 16 分钟

关键要点

  • 在企业测试中,测试软件的方式应该与软件在生产环境中运行的方式相同,以便确保软件能够按预期的方式运行。
  • 常见的挑战是微服务应用程序直接或间接依赖需要在测试场景中编排的其他服务。
  • 本文展示了容器编排如何在服务实例之上提供抽象,并使用模拟实例来替代真实实例。
  • 此外,服务网格让我们能够重新路由流量,并通过注入错误响应或延迟来验证服务的弹性。
  • 本文包含了一个示例代码,代码来自一个基于 Java 的咖啡店应用程序,该应用程序将被部署到 Kubernetes 和 Istio 上,并对其进行测试。

在企业测试中,测试软件的方式应该与软件在生产环境中运行的方式相同,以便确保软件能够按预期的方式运行。常见的挑战是微服务应用程序直接或间接依赖需要在测试场景中编排的其他服务。

本文展示了容器编排如何在服务实例之上提供抽象,并使用桩实例来替代真实实例。此外,服务网格让我们能够重新路由流量,并通过注入错误响应或延迟来验证服务的弹性。

我们将使用一个咖啡店示例应用程序,这个应用程序被部署在一个容器和服务网格集群中。我们选择Kubernetes 和Istio 作为实例运行环境。

测试场景

假设我们想要在不考虑其他外部服务的情况下测试应用程序的行为。应用程序的运行方式和配置方式应该与生产环境相同,以便确保以后它在生产环境中的行为是一致的。在测试中,我们将使用定义好的通信接口连接应用程序。

但是,外部服务不应成为测试场景的一部分。通常,在测试时我们应该关注被测试的对象,并忽略掉其他对象。因此,我们使用模拟服务器来替代外部服务。



容器编排

使用模拟服务器而不是真实实例与以与生产环境相同的方式运行微服务的想法相矛盾,因为到了生产环境配置会发生改变。但是,如果我们的应用程序部署到容器编排集群(例如 Kubernetes),就可以将抽象的服务名称用作配置,并让集群自己去解析后端服务实例。

以下示例是一个网关类,它是咖啡店应用程序的一部分,连接到端口 8080 上的 coffee-processor。

复制代码
public class OrderProcessor {
    // definitions omitted ...
    @PostConstruct
    private void initClient() {
        final Client client = ClientBuilder.newClient();
        target = client.target("http://coffee-processor:8080/processes");
    }
   @Transactional(Transactional.TxType.REQUIRES_NEW)
    public void processOrder(Order order) {
        OrderStatus status = retrieveOrderStatus(order);
        order.setStatus(status);
        entityManager.merge(order);
    }
    // ...
    private JsonObject sendRequest(final JsonObject requestBody) {
        Response response = target.request()
               .buildPost(Entity.json(requestBody))
                .invoke();
        // ...
        return response.readEntity(JsonObject.class);
    }
    // definitions omitted ...
}

主机名通过 Kubernetes 群集 DNS 解析,将流量引导到其中一个正在运行的处理器实例。然而,coffee-processor 的实例将成为一个模拟服务器,在我们的示例中使用了 WireMock 。这种替换对我们的应用来说是透明的。

在测试场景中,不仅会连接到应用程序来调用业务逻辑,还会与模拟服务器发生通信,在单独的管理界面上控制响应行为,并验证应用程序是否以正确的方式调用模拟服务器。这与类级别的单元测试类似,通常使用 JUnit 和 Mockito 实现。



外部服务

上述的设置可以让我们模拟和控制在容器编排集群内运行的服务。那么那些在集群之外的外部服务该怎么办呢?

通常,我们可以创建一个不带有选择器的Kubernetes 服务,让它指向一个外部IP,并重写我们的应用程序,让它始终使用由群集解析的服务名。这样一来,我们定义了一个单一的点,服务将被路由到这个点上。

以下的代码片段显示了一个外部 Kubernetes 服务和端点定义,它将 coffee-shop-db 路由到外部 IP 地址 1.2.3.4:

复制代码
kind: Service
apiVersion: v1
metadata:
  name: coffee-shop-db
spec:
  ports:
  - protocol: TCP
    port: 5432
---
kind: Endpoints
apiVersion: v1
metadata:
  name: coffee-shop-db
subsets:
  - addresses:
      - ip: 1.2.3.4
    ports:
      - port: 5432

在不同的环境中,服务可能会被路由到不同的数据库实例。

服务网格

服务网格能够帮助我们处理微服务间的通信问题。目前,Istio 是最常用的服务网格技术之一。它增加了与应用程序容器共存的边车代理容器,可以解决微服务间的通信问题,并且还可以用来操纵或减慢连接,以便进行弹性测试。

在端到端测试中,我们可以引入错误或缓慢的响应来验证应用程序是否能够正确处理这些问题场景。

以下的代码片段显示了一个 Istio 虚拟服务的定义,其中到 coffee-processor 的路由有 50% 的延迟为 3 秒,10%的响应是失败的。

复制代码
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: coffee-processor
spec:
  hosts:
  - coffee-processor
  http:
  - route:
    - destination:
        host: coffee-processor
        subset: v1
    fault:
      delay:
        fixedDelay: 3s
        percent: 50
      abort:
        httpStatus: 500
        percent: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: coffee-processor
spec:
  host: coffee-processor
  subsets:
  - name: v1
    labels:
      version: v1

现在,我们可以运行其他测试,并验证应用程序将如何处理这些增加的响应时间和故障状况。

除了可以注入错误响应之外,服务网格技术还可以用来从环境中添加弹性。代理容器可以处理超时,实现断路器和隔板,而应用程序无需关心这些问题。

结论

容器编排和服务网格通过将应用程序的关注点转移到环境中来提高微服务应用程序的可测试性。有了服务抽象,我们就可以透明地替换服务或进行重新路由。服务网格不仅支持更复杂的路由,还允许我们注入故障或减慢响应,让应用程序处于压力之下,以此来验证其相应的行为。

更多资源

关于作者

 Sebastian Daschner 是一名自由 Java 顾问、作家和培训师,对编程和 Java 充满热情。他是“Architecting Modern Java EE Applications”一书的作者。Sebastian 正在参与 JCP,协助制定 Java EE 的未来标准,是 JAX-RS、JSON-P 和 Config 专家组的成员,并在各种开源项目上进行协作。由于在 Java 社区和生态系统中的贡献,他获得了 Java Champion、Oracle Developer Champion 和 2016 年 JavaOne Rockstar 的殊荣。除了 Java 之外,Sebastian 还是 Linux 和云原生技术的重要用户。他通过博客和Twitter(@DaschnerS)传播计算机科学实践。工作之余,他喜欢乘飞机或骑摩托车旅行。

查看英文原文 Improving Testability of Java Microservices with Container Orchestration and a Service Mesh

2018-08-09 18:272406
用户头像

发布了 731 篇内容, 共 451.9 次阅读, 收获喜欢 2002 次。

关注

评论

发布
暂无评论
发现更多内容

TPC藏宝计划IDO自由协议复利模式开发功能分析

开发微hkkf5566

聚焦数据来源、数据质量和模型性能构建小微企业信用画像

易观分析

数据技术 小微企业

【有话耀说】开发小达人们,荣耀开发者服务平台正式入驻InfoQ社区啦~

荣耀开发者服务平台

基于 Next.js实现在线Excel

葡萄城技术团队

前端 在线excel nextjs 表格 控件

化繁为简,聊一聊复制状态机系统架构抽象

阿里技术

数据库 架构

炫酷又高效的数据可视化大屏,做起来真的没那么难!丨极客星球

MobTech袤博科技

产品设计 数据可视化

数据中台建设(九):数据中台资产运营机制

Lansonli

数据中台 8月月更

技术分享| 小程序实现音视频通话

anyRTC开发者

小程序 uni-app 音视频 语音通话 视频通话

智能电视可以打开小程序应用,再也不用头痛内存了

Geek_99967b

小程序

信创是什么意思?涉及哪些行业?为什么要发展信创?

行云管家

信息安全 信创

中大型商业银行堡垒机升级改造就用行云管家!必看!

行云管家

信息安全 银行 堡垒机 IT安全

JS逆向字体反爬,某供应商平台反爬实践

梦想橡皮擦

Python 爬虫 8月月更

分布式链路追踪Jaeger + 微服务Pig在Rainbond上的实践分享

北京好雨科技有限公司

开源 Kubernetes 云原生 SpringCloud Jaeger

运维:Centos8安装supervisor守护Nginx进程笔记

天使不哭

#开源 8月月更

未来已来,只是尚未流行

石云升

读书感悟 未来社会 8月月更 未来以来

leetcode 48. Rotate Image 旋转图像(Medium)

okokabcd

数组 LeetCode 数据结构与算法

如何在Linux (CentOS7.3) 下安装JDK1.8?【一篇文章教会你】

Bug终结者

java; Linux Kenel 8月月更

Tapdata 开源项目基础教程:功能特性及实操演示

tapdata

Tapdata 开源社区

企业应当实施的5个云安全管理策略

SEAL安全

云计算 容器 DevOps 云原生 DevSecOps

手把手教你用 Jenkins 自动部署 SpringBoot

江南一点雨

Java spring jenkins springboot

【SpringBoot 二】spring.factories加载时机分析

石臻臻的杂货铺

springboot 8月月更

并发程序的隐藏杀手——假共享(False Sharing)

了不起的程序猿

编程 高并发 java程序员

活动报名:如何高效应对当下的实时场景需求?

tapdata

Tapdata 实时数据

干货丨数学规划视角下的分货优化解题思路

杉数科技

运筹优化 智能分货 供应链计划 仓储优化 门店分货

开发者独立搭建一个跨模态搜索应用有多难?

Jina AI

深度学习 云原生 神经搜索 跨模态应用 多模态数据

隐私计算与数据流通:关系、作用及功能

Jessica@数牍

隐私保护 隐私计算 数据流通 数据交易 数牍科技

什么是 DevOps?看这一篇就够了!

玩转Devop和研发效能DevStream/DevLake

DevOps

全面认识MOS管,一篇文章就够了

矜辰所致

电路设计 8月月更 电子设计基础 MOS管

【SpringBoot 一】SpringApplication启动类的Args详解

石臻臻的杂货铺

spring-boot 8月月更

如何通过使用“缓存”相关技术,解决“高并发”的业务场景案例?

冉然学Java

高并发 java; 单线程 redis'

《中国综合算力指数》《中国算力白皮书》《中国存力白皮书》《中国运力白皮书》在首届算力大会上重磅发出

GPU算力

通过容器编排和服务网格来改进Java微服务的可测性_Java_Sebastian Daschner_InfoQ精选文章