网格化服务 java
Java EE,云原生和服务网格-听起来确实不太合适。 还是呢? 是否有可能开发满足可伸缩性,监视,跟踪或路由等问题的现代云原生Java Enterprise应用程序,而无需自己实现所有功能? 如果是这样,怎么办?
在微服务的企业环境中,面临着以一致的方式向多个或所有服务添加技术关注点(例如发现,安全性,监视,跟踪,路由或故障处理)的挑战。 软件团队可以使用不同的技术来实现其单独的服务,但是他们需要遵守组织标准。 添加诸如API网关之类的共享资产会使服务纠缠在一起,并以某种方式破坏了微服务架构的目的。 但是,也应避免冗余。
服务网格透明地增强了作为网格一部分的每个微服务,具有一致的技术问题。 这些增强功能以与技术无关的方式添加,而不会影响应用程序。 因此,该应用程序专注于实现业务逻辑。 环境将技术必要性放在首位。
我们将要使用的展示应用程序是一个仪器制造厂和一个3D打印机制造商机器人。 想象一下一个仪器手Craft.io品店SaaS应用程序,客户可以在其中订购手工乐器。 我们的商店不提供最优质的乐器,而仅将请求转发给制造商机器人后端,该机器人通过3D打印我们的乐器。
这两个云原生微服务在Java EE 8中实现,被部署到Kubernetes集群,并由Istio管理。
为了使用Kubernetes和Istio管理Java EE应用程序,我们需要将它们打包为容器。 Docker映像是通过定义Dockerfile创建的。 这些基础结构代码文件指定整个应用程序的运行时,包括配置,Java运行时(即JRE和应用程序容器)以及所需的操作系统二进制文件。 目标环境仅从该映像启动完全配置的容器。
下面显示了打包的乐器Craft.io品商店应用程序的Dockerfile,该文件使用包括OpenLiberty应用程序服务器的自定义基本映像:
FROM docker.example.com/open-liberty:1
COPY target/instrument-craft-shop.war $DEPLOYMENT_DIR
OpenLiberty基本映像已经包括运行应用程序服务器所需的内容。 应用程序的Dockerfile将添加潜在的配置,并在最后一步添加应用程序存档。 通过使用瘦部署工件方法,我们利用了Docker的写时复制文件系统,并获得了极快的构建和较短的传输时间。
生成的映像将在协调的环境中运行,在我们的示例中是Kubernetes集群。
因此,还成为应用程序存储库一部分的是Kubernetes环境的基础结构代码文件。 YAML描述符包括集群应如何运行,分发和组织我们的应用程序,我们的Docker容器。
下面显示了instrument-craft-shop
的服务定义。 Kubernetes服务是对应用程序的逻辑抽象。
kind: Service
apiVersion: v1
metadata:
name: instrument-craft-shop
labels:
app: instrument-craft-shop
spec:
selector:
app: instrument-craft-shop
ports:
- port: 9080
name: http
该服务将负载平衡请求到实际正在运行的实例。 容器由Kubernetes部署管理。 部署定义了如何执行Kubernetes Pod,实际运行的工作负载以及需要多少个副本:
kind: Deployment
apiVersion: apps/v1beta1
metadata:
name: instrument-craft-shop
spec:
replicas: 1
template:
metadata:
labels:
app: instrument-craft-shop
version: v1
spec:
containers:
- name: instrument-craft-shop
image: docker.example.com/instrument-craft-shop:1
imagePullPolicy: IfNotPresent
restartPolicy: Always
该服务将考虑与定义的选择器匹配的容器。 此处的app
标签实际上是标准名称,与我们的应用匹配。 最好还定义一个version
标签,以便在多个应用程序版本同时存在时能够进一步自定义服务路由。
仪表车间将由客户端从集群外部调用。 Kubernetes入口资源会将入口流量路由到相应的服务:
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: instrument-craft-shop
annotations:
kubernetes.io/ingress.class: istio
spec:
rules:
- http:
paths:
- path: /instrument-craft-shop/.*
backend:
serviceName: instrument-craft-shop
servicePort: 9080
该ingress.class
注释指定istio
作为入口实施。 因此,Kubernetes将为我们的系统部署正确的Istio入口。
仪器厂应用程序将通过HTTP与制造商机器人后端进行通信。 maker bot应用程序定义了类似的名为maker-bot
Kubernetes服务和部署资源。
由于这两个应用程序都是Kubernetes集群的一部分,因此它们可以使用服务定义作为主机名进行通信。 Kubernetes在内部通过DNS解析服务名称。
下图显示了maker bot
客户端,该客户端是工具车车间应用程序的一部分:
@ApplicationScoped
public class MakerBot {
private Client client;
private WebTarget target;
@PostConstruct
private void initClient() {
client = ClientBuilder.newBuilder()
.connectTimeout(1, TimeUnit.SECONDS)
.readTimeout(3, TimeUnit.SECONDS)
.build();
target = client.target("http://maker-bot:9080/maker-bot/resources/jobs");
}
public void printInstrument(InstrumentType type) {
JsonObject requestBody = createRequestBody(type);
Response response = sendRequest(requestBody);
validateResponse(response);
}
private JsonObject createRequestBody(InstrumentType type) {
return Json.createObjectBuilder()
.add("instrument", type.name().toLowerCase())
.build();
}
private Response sendRequest(JsonObject requestBody) {
try {
return target
.request()
.post(Entity.json(requestBody));
} catch (Exception e) {
throw new IllegalStateException("Could not print instrument, reason: "
+ e.getMessage(), e);
}
}
private void validateResponse(Response response) {
if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL)
throw new IllegalStateException("Could not print instrument, status: "
+ response.getStatus());
}
@PreDestroy
private void closeClient() {
client.close();
}
}
从Java EE 8开始,JAX-RS客户端构建器API支持connectTimeout
和readTimeout
方法。 强烈建议设置这些超时以防止长时间阻塞线程。
如您所见,通过主机名maker-bot
和匹配Kubernetes服务定义的端口9080
来配置maker bot后端。 这使我们摆脱了服务发现配置,例如为不同的环境定义了不同的目标端点,IP地址或主机名。 该URL在所有Kubernetes集群环境中都是稳定的,并已适当解析。
我们将展示Istio,它是Java / JVM世界中最广泛使用的服务网格示例之一。
Istio透明地向应用程序添加了跨领域的技术问题。 它使用代理Sidecar容器增强了应用程序容器,这些容器捕获了来自主容器和去往主容器的入站和出站流量。 主应用程序容器连接到所需的服务,并且不了解代理。 我们可以将Istio视为面向方面的编程中的方面,以透明的方式添加到应用程序中。 Istio可以使用几种编排框架实现,包括Kubernetes
我们的示例应用程序已部署到Kubernetes集群,该集群通过Istio和自动侧车注入功能得到了增强。 边车注入器会自动将Istio代理容器添加到每个吊舱。
Istio Pilot负责配置有关路由和弹性的Sidecar代理。 我们在声明性YAML文件中配置Istio方面,类似于Kubernetes资源。
作为最佳实践,我们为相应的应用程序服务添加默认路由:
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: instrument-craft-shop-default
spec:
destination:
name: instrument-craft-shop
precedence: 1
route:
- weight: 100
labels:
version: v1
此路由规则指定所有到instrument-craft-shop
服务的流量都是到v1
版实例的路由。 Istio资源以与Kubernetes资源相同的方式添加到集群,例如通过kubectl
命令行。 现在,我们可以进一步完善这些路线。
厂商bot后端的以下路由规则增加了2秒的超时时间:
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: maker-bot-default
spec:
destination:
name: maker-bot
precedence: 1
route:
- weight: 100
labels:
version: v1
httpReqTimeout:
simpleTimeout:
timeout: 2s
超时将独立于其他应用程序级别超时触发,并将导致代理返回503错误代码。 即使没有定义MakerBot
类中的JAX-RS客户端配置之类的超时,这也可以防止系统无限阻塞。 客户端将收到超时,以先触发者为准。
Istio的另一个功能是添加断路器,以防止应用程序过载和整体故障。 制造商漫游器后端的以下目标策略增加了断路行为:
apiVersion: config.istio.io/v1alpha2
kind: DestinationPolicy
metadata:
name: maker-bot-circuit-breaker
spec:
destination:
name: maker-bot
circuitBreaker:
simpleCb:
httpConsecutiveErrors: 1
sleepWindow: 10s
httpDetectionInterval: 10s
httpMaxEjectionPercent: 100
maxConnections: 1
httpMaxPendingRequests: 1
httpMaxRequestsPerConnection: 1
此过于严格的目标策略一次仅允许一个连接,并且将拒绝其他连接。 有多种方法可以配置电路的打开和关闭方式,需要针对特定的系统设置进行调整。
透明地添加到现有应用程序中的其他方面是监视,日志记录和跟踪以及身份验证。 Sidecar容器中包含的Envoy代理添加了这些跨领域关注点,并将其暴露于环境中。
DevOps工程师可以访问所需的信息,例如通过检查Grafana和Prometheus扩展或属于Istio集群的跟踪解决方案。 通过相互加密Sidecar代理之间的连接来添加身份验证。 用户可以添加自己的证书,还可以配置允许通信的策略。
Java EE非常适合服务网格背后的想法。 诸如路由,弹性或身份验证之类的技术交叉问题成为服务网格环境的责任。
实际上,Java EE始终围绕着这个想法而构建。 应用程序本身应将自己与业务逻辑,实际要解决的问题领域结合起来。 这最终为应用程序的用户提供了价值。 但是,诸如生命周期管理,依赖项注入,事务或线程之类的技术职责是应用程序容器的一部分。
编排框架和服务网格进一步采用了这种方法,并使服务发现,弹性,身份验证,监视或跟踪环境负责。 因此,这些责任不再是应用程序代码的问题。 他们不应该; 应用程序应专注于实现业务逻辑。
将来,打包的应用程序将使用纯Java EE 8或Jakarta EE充分构建。 从应用程序外部添加了技术横切关注点。
如果域需要其他关注事项,例如与业务相关的指标,则可以通过集成第三方扩展(例如MicroProfile指标)来添加这些关注点。 使用支持MicroProfile的容器或将第三方库安装到应用程序容器作为较低的Docker映像层,仍然使我们能够利用精简部署工件的优势。 这个想法符合关注点分离的原则。
因此,将诸如Docker,Kubernetes和Istio之类的云原生技术与Java EE或未来的Jakarta EE结合起来,是实现生产型企业应用程序的面向未来的选择。
更多资源
翻译自: https://www.infoq.com/articles/cloud-native-service-mesh-java-ee/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1
网格化服务 java