介绍
几个星期前我第一次遇到Envoy代理,当时我的一位博客读者建议我写一篇关于它的文章。我以前从未听说过,我的第一个想法是,这不是我的经验领域。事实上,这个工具并不像nginx或haproxy那样受欢迎,但它提供了一些有趣的功能,其中我们可以区分对MongoDB,Amazon RDS的开箱即用支持,发现和负载平衡的灵活性或生成很多有用的流量统计。好吧,我们对它的优势了解一点但是Envoy代理究竟是什么?'Envoy是一个开源边缘和服务代理,专为云原生应用而设计'。它最初由Lift开发,是一种高性能C ++分布式代理,专为独立服务和应用程序以及大型微服务服务网格而设计。现在听起来真的很棒。这就是为什么我决定仔细研究它并准备一个使用Envoy和基于Spring Boot的微服务实现的服务发现和分布式跟踪的示例。
特使配置
在以前基于Spring Cloud的大多数示例中,我们使用Zuul作为边缘和代理。Zuul是流行的Netflix OSS工具,在您的微服务架构中充当API网关。事实证明,它可以被Envoy代理成功取代。在Envoy中我真正喜欢的一件事就是创建配置的方法。默认格式为JSON,并根据JSON模式进行验证。这个JSON属性和模式记录良好,易于理解。正是您对现代解决方案的期望,推荐的开始使用方法是使用预先构建的Docker镜像。因此,在开始时我们必须创建Dockerfile以使用Envoy构建Docker镜像,并提供JSON格式的配置文件。这是我的Dockerfile。参数service-cluster
和service-node
是可选的,与提供的服务发现配置有关,我将在一分钟内详细说明。
1 2 3 4 |
|
我假设你有关于Docker及其命令的基本知识,此时这是强制性的。提供envoy.json
配置文件后,我们可以继续构建Docker镜像。
1 |
|
然后使用docker run
命令运行它。有用的端口应暴露在外面。
1 |
|
第一个非常有用的功能是本地HTTP管理员服务器。它可以在admin
属性内的JSON文件中配置。出于示例目的,我选择了端口9901,您可能已经注意到我也在Envoy Docker容器外部暴露了该端口。现在,管理控制台可以在 /下找到。如果调用该地址,则会打印所有可用命令。对我来说最有用的是统计数据,它会打印与代理和日志记录相关的所有重要统计信息,我可以在这里动态更改某些已定义类别的日志记录级别。所以,首先,如果你有任何问题,Envoy尝试通过调用/logging?name=level
并在运行docker logs envoy
命令后在Docker容器上观察它们来更改日志记录级别。
1 2 3 4 |
|
下一个必需的配置属性是listeners
。在那里,我们定义路由设置和Envoy将侦听传入TCP连接的地址。符号tcp://0.0.0.0:10000是具有端口10000的任何IPv4地址的通配符匹配。此端口也在Envoy Docker容器外部公开。在这种情况下,它将是我们的API网关,可在地址下获得。我们将在ltare阶段回到代理配置细节,现在让我们仔细研究一下这个示例的架构。
1 2 3 4 |
|
建筑
所示解决方案的架构在下图中可见。我们将Envoy代理作为API网关,这是我们系统的入口点。Envoy与Zipkin集成并向其发送跟踪消息,其中包含有关传入的HTTP请求和发回的响应的信息。两个示例微服务Person和Product在启动时在服务发现中注册,在注销时注销。它们隐藏在API网关后面的外部客户端。特使必须使用已注册服务的地址获取实际配置,并正确路由传入的HTTP请求。如果每个服务有多个实例可用,则应执行负载平衡。
事实证明,Envoy不支持像Consul或Zookeeper这样众所周知的发现服务器,但是定义了自己的基于REST的通用API,需要实现它才能启用集群成员获取。此API的主要方法GET /v1/registration/:service
用于获取当前已注册的服务实例列表。Lyft提供了Python的默认实现,但出于示例目的,我们使用Java和Spring Boot开发了自己的解决方案。GitHub上提供了示例应用程序源代码。除了服务发现实现,您还可以找到两个示例微服务。
服务发现
我们的自定义发现实现只是将基于REST的API暴露给注册,取消注册和获取服务实例的方法。GET方法需要返回与以下模式匹配的特定JSON结构。
1 2 3 4 五 6 7 |
|
这是带有发现API实现的REST控制器类。
1 2 3 4 五 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 |
|
让我们回到Envoy配置设置。假设我们从Dockerfile构建了一个可见的图像,然后在默认端口上运行容器,我们可以在地址下调用它。该地址应放在envoy.json
配置文件中。应在“Cluster Manager”部分中提供服务发现连接设置。
1 2 3 4 五 |
|
这是envoy.json
文件中的片段。应将服务发现的集群定义为全局SDS配置,必须在sds
property(1)中指定。最重要的是提供正确的URL(2),并在此基础上,Envoy自动尝试调用端点GET / v1 / registration / {service_name}。该部分的最后一个有趣的配置字段refresh_delay_ms
是负责设置提取在发现服务器中注册的服务列表之间的延迟。那不是全部。我们还必须定义集群成员。它们由名称(4)标识。它们的类型是sds(5),这意味着该集群使用服务发现服务器来定位调用微服务的网络地址,其名称在service-name
属性中定义。
1 2 3 4 五 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
为route_config
属性内的每个侦听器定义路由配置(1)。第一条路由配置为人员服务,由集群服务1(2)处理,第二条路由服务 2集群进行产品服务处理。因此,我们的服务可在和地址下找到。
1 2 3 4 五 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
构建微服务
Envoy代理上的路由已经配置。我们仍然没有运行微服务。它们的实现基于Spring Boot框架,除了公开REST API之外,它还提供对象列表上的简单操作以及在发现服务器上注册/取消注册服务。这是负责该注册的@Service bean。在正常关闭之前onApplicationEvent
,应用程序启动和destroy
方法之后会触发该方法。
1 2 3 4 五 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 三十 31 32 33 34 35 36 37 38 39 40 41 |
|
正确关闭Spring Boot应用程序的最佳方法是通过其Actuator端点。为服务启用此类端点包括spring-boot-starter-actuator
项目依赖项。默认情况下禁用关闭,因此我们应添加以下属性application.yml
以启用它,并另外禁用默认安全性(endpoints.shutdown.sensitive=false
)。现在,只需调用POST / shutdown,我们就可以停止Spring Boot应用程序并测试取消注册方法。
1 2 3 4 |
|
对于微服务我们也一样,我们也构建了docker镜像。这是人员服务Dockerfile,它允许覆盖默认服务和SDS端口。
1 2 3 4 五 6 |
|
要使用自定义侦听端口构建映像并运行服务容器,请键入以下docker命令。
1 2 |
|
分布式跟踪
现在是最后一块拼图的时候了 - Zipkin追踪。应在那里发送与所有传入请求相关的统计信息。Envoy代理中配置的第一部分是inside tracing
属性,它指定HTTP跟踪器的全局设置。
1 2 3 4 五 6 7 8 9 10 11 |
|
Zipkin连接的网络位置和设置应定义为集群成员。
1 2 3 4 五 6 7 8 9 10 11 |
|
我们还应该tracing
在HTTP连接管理器配置中添加新的部分(1)。字段operation_name
是必需的并设置范围名称。仅支持“入口”和“出口”值。
1 2 3 4 五 6 7 8 9 10 11 |
|
Zipkin服务器可以使用其Docker镜像启动。
1 |
|
概要
这是用于测试目的的运行Docker容器的列表。您可能还记得我们有Zipkin,Envoy,自定义发现,两个人员服务实例和一个产品服务实例。您可以通过调用POST / person添加一些人物对象,并通过调用GET / person显示所有人的列表。应根据服务发现中的条目在两个实例之间对请求进行负载平衡。
有关每个请求的信息将发送到Zipkin,服务名称为-service-cluster Envoy代理运行参数。