面向开发人员的 7 个微服务最佳实践
微服务最佳实践
别忘了你的安全带……
除非你一直在山洞里开发软件,否则你可能听过人们对微服务的赞美。它们敏捷、简单,并且比单体架构和面向服务架构时代有了全面的改进。当然,微服务在带来诸多好处的同时,也带来了一系列新的挑战。
在本文中,我们将探讨一些微服务的最佳实践。此外,我们还将推荐一些行之有效的方法,帮助您设计、编排和保护微服务架构。了解这些实践,将有助于您在项目成功道路上取得先机。
微服务的优势与挑战
然而,在深入研究微服务最佳实践之前,我们应该首先讨论一下微服务的一些好处和挑战,以及为什么首先要使用它们。
简而言之,微服务是一种改进的软件架构,它允许您:
- 部署和扩展速度更快。更小的应用程序域责任允许实现自动化,从而加快部署和扩展速度。
- 减少停机时间。限制一项不可用的服务对主要业务功能的影响,从而提高整体业务正常运行时间。
- 确保可用性。保持微服务之间的功能离散,从而限制实例故障时的影响。
当然,伴随着这些好处,我们也面临着一系列新的挑战,包括服务间通信、安全性和可扩展性。
- 服务间通信。在单体应用中,所有模块本质上都可以相互通信。您只需管理一个证书,请求一旦通过身份验证和授权,即可顺利遍历代码路径。当您将函数从单体架构中提取到微服务应用中时,曾经的内部函数调用就变成了外部 API 调用,需要外部微服务进行身份验证和授权。
- 安全层。在单体应用中,身份验证和授权可以在入口点一次性处理。随着向微服务架构的转变,每个微服务都需要执行身份验证和授权来强制执行访问控制。要求用户每次使用不同的微服务时都登录是不现实的,因此需要建立全面的身份验证策略。
- 可扩展性。虽然微服务允许您快速扩展独立功能,但要有效地实现这一点,需要良好的应用管理,甚至更强大的工具。可扩展性的有效性取决于您的微服务编排平台,我们将在下文中详细讨论。
微服务最佳实践
简要概述了微服务的优势和挑战,现在让我们深入探讨一些最佳实践。这些最佳实践将帮助您创建一个健壮、易于管理、可扩展且安全的微服务互通系统。
1. 应用领域小
采用微服务策略需要遵循单一职责原则。通过限制单个服务的职责范围,我们可以限制该服务故障带来的负面影响。如果单个微服务承担过多职责,其故障或不可用将对系统其他部分产生多米诺骨牌效应。
微服务就应该如此:微型。保持微服务的应用域较小,专注于单一逻辑功能。这样可以减少特定微服务出现问题时造成的影响。此外,较小的服务更易于维护。最终结果是更新更容易,开发速度更快。
这在实践中是什么样的?例如,假设我们的微服务是一个 API 服务器,它接受获取数据的请求,并且这些请求必须附带授权令牌。在刚开始时,这是唯一需要授权令牌的微服务。为什么不直接将身份验证和令牌生成作为微服务的一部分呢?乍一看,这样做的好处是移动部件更少,管理起来也更轻松。
当然,总有一天你会有其他需要授权令牌的服务。你很快就会发现,你原来的微服务既充当 API 服务器,又充当身份验证服务器。如果你的 API 服务器宕机了,那么你的身份验证服务器也会随之宕机。这样一来,其他所有需要授权令牌的服务也会随之宕机。
为你的将来着想:保持你的微服务规模较小。
2. 数据存储分离
连接到同一数据库的多个微服务本质上仍然是单体架构。单体架构仅位于数据库层,而非应用层,因此同样脆弱。每个微服务都应尽可能拥有自己的数据持久层。这不仅确保了与其他微服务的隔离,还能最大限度地减少特定数据集不可用时的影响范围。
有时,不同的微服务访问同一数据库中的数据似乎合情合理。然而,深入研究后可能会发现,一个微服务仅处理数据库表的子集,而另一个微服务仅处理完全不同的表子集。如果这两个数据子集完全正交,那么将数据库拆分成多个独立服务就是一个很好的例子。这样,单个服务依赖于其专用的数据存储,而该数据存储的故障不会影响除该数据存储之外的任何服务。
我们可以对文件存储做一个类似的案例。采用微服务架构时,独立的微服务不必使用相同的文件存储服务。除非文件存在实际重叠,否则独立的微服务应该拥有独立的文件存储。
这种数据分离带来了更高的灵活性。例如,假设我们有两个微服务,它们都与云提供商共享同一个文件存储服务。其中一个微服务定期访问大量资产,但文件大小较小。另一个微服务只定期访问几个文件,但这些文件的大小却高达数百 GB。
为两个微服务使用通用的文件存储服务会降低您优化成本的灵活性,因为您混合了大文件和小文件,并且需要定期和周期性访问。如果每个微服务都有自己的数据持久层(当然,这可以是一个单独的微服务),那么您就能更灵活地找到最适合该微服务需求的提供商或服务。
成本优化、选项的灵活性以及减少对可能失败的单一解决方案的依赖——这些都是分离不同微服务数据的原因。
3.沟通渠道
微服务之间如何通信(尤其是关于相关事件的通信)需要深思熟虑。否则,一个服务不可用就可能导致通信中断,最终导致整个应用程序崩溃。
想象一下一个在线商店的微服务系统。一个微服务负责接收网站下达的订单。另一个微服务负责向客户发送短信通知,告知订单已收到。还有一个微服务负责通知仓库发货。最后,还有一个微服务负责更新库存数量。
微服务之间有两种通信类型:同步和异步。如果我们使用同步通信来处理上述示例,Web 服务器可能会首先向客户通知服务发送请求来处理新订单。在客户通知服务响应后,Web 服务器会向仓库通知服务发送请求,然后再次等待响应。最后,Web 服务器向库存更新器发送请求。我们的同步方法如下所示:
微服务之间的同步通信
当然,假设客户通知服务碰巧宕机了。在这种情况下,通知客户的请求可能会超时或返回错误,甚至可能导致 Web 服务器无限期地等待响应。仓库通知服务可能永远无法收到发货请求。微服务之间的同步通信可能会创建一个依赖链,如果链中任何一个环节中断,依赖链就会断裂。
在异步通信中,服务发送请求后会继续运行,无需等待响应。在一种可能的异步方法中,Web 服务器可能会发送“通知客户”请求,然后完成其任务。客户通知服务负责通知客户,并向仓库通知服务发送异步请求,仓库通知服务负责向库存更新服务发送请求。它可能如下所示:
微服务之间的链式异步通信
当然,在这个模型中,我们看到异步通信仍然会导致链依赖,并且单个服务的故障仍然会破坏应用程序。
一种简单而有效的异步通信方法是采用发布/订阅模式。当感兴趣的事件发生时,生产者(在本例中为微服务)会将该事件的记录发布到消息队列服务。任何其他对该类型事件感兴趣的微服务都会作为该事件的消费者订阅该消息队列服务。微服务之间仅与消息队列服务通信和监听,彼此之间不进行通信和监听。
对于我们的例子来说,它可能看起来像这样:
通过消息队列服务实现异步通信
消息队列本身是一个独立的服务,与所有微服务解耦。它负责接收已发布的事件并通知订阅者。这确保了即使某个微服务的故障(可能导致消息传递延迟),对其他相关但不相关的服务的影响也最小。
有很多工具可以实现这种异步通信(例如 Kafka 或 RabbitMQ)。请尝试将这些工具集成到微服务中,作为异步通信的主干。
在某些情况下,微服务之间需要同步通信。大多数请求-响应交互都是同步的,这是必然的。例如,查询数据库的 API 服务器必须等待查询响应;获取缓存数据的 Web 服务器必须等待键值存储的响应。
当需要同步通信时,您将需要使用开源Kong Gateway来确保您的通信快速可靠地路由到正确的微服务。
4.兼容性
尽可能保持向后兼容性,以免用户遇到损坏的 API。常用的方法是遵循路径级别的兼容性保证,例如/api/v1
或/api/v2
。任何不向后兼容的更改都会转移到新的路径,例如/api/v3
。
然而,尽管我们软件工程师竭尽全力,有时仍需要弃用 API,以免永远运行它们。借助API 网关请求转换插件,您的微服务可以轻松地在原始 API 响应中注入弃用通知,或附加类似Kubernetes的“弃用标头”,从而提醒 API 使用者。
5. 编排微服务
微服务的编排是流程和工具成功的关键因素。从技术上讲,您可以使用类似systemd
Docker 或 Kubernetes 的podman
工具在虚拟机上运行容器,但这无法提供与容器编排平台同等级别的弹性。这会对采用微服务架构所带来的正常运行时间和可用性优势产生负面影响。为了有效地进行微服务编排,您需要依赖久经考验的容器编排平台;而Kubernetes无疑是该领域的领军者。
Kubernetes 管理所有容器的配置和部署,同时处理负载平衡、扩展、高可用性副本集和网络通信问题。
您可以在本地部署裸 Kubernetes,也可以使用 Azure Kubernetes 服务、Red Hat OpenShift 或 Amazon Elastic Kubernetes 服务等云发行版。Kubernetes 内置的调度、复制和网络功能使微服务编排比在传统操作系统上更加容易。
将 Kubernetes 与Kuma服务网格和Kong Ingress Controller结合起来,您就拥有了可发现、可监控且具有弹性的微服务——就像魔术一样。
6. 微服务安全
随着您的应用程序包含越来越多的微服务,确保适当的安全性可能会变得非常复杂。一个集中式的安全策略执行系统对于保护您的整个应用程序免受恶意用户、入侵机器人和错误代码的侵害至关重要。无论您是在虚拟机还是在 Kubernetes 上运行, Kong都应该是您使用微服务构建安全故事的起点。Kong 维护的丰富安全插件让您可以轻松满足一些最常见的微服务需求,包括身份验证、授权、流量控制和速率限制。
示例:使用 Kong Ingress 控制器进行速率限制
为了演示安全插件的实际应用,我们将部署 Kong 的Rate Limiting 插件,以展示 Kong 如何阻止过多的入站请求进入您的应用程序。我们将创建一个本地 Kubernetes 集群,kind
然后按照以下说明部署 Kong Ingress Controller 。
创建集群并部署 Kong Ingress Controller 后,我们的第一步是设置 Rate Limiting 插件。您可以为不同的范围设置插件。我们将使用 Kubernetes 集群上的默认项目作为我们的用例,并将插件的范围设置为该默认命名空间。
$ echo 'apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: rate-limiting-example
namespace: default
config:
second: 5
hour: 10000
policy: local
plugin: rate-limiting' | kubectl apply -f -
kongplugin.configuration.konghq.com/rate-limiting-example created
现在,我们将创建一个“echo 服务”以及该服务的入口。在本例中,我们借用了 Kong 的《Kubernetes Ingress Controller 入门》文档中的示例:
$ kubectl apply -f https://bit.ly/echo-service
service/echo created
deployment.apps/echo created
$ echo "
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: demo
annotations:
kubernetes.io/ingress.class: kong
konghq.com/plugins: rate-limiting-example
spec:
rules:
- http:
paths:
- path: /foo
backend:
serviceName: echo
servicePort: 80
" | kubectl apply -f -
我们要做的最后一件事就是测试!我们将借用shell-demo
Kubernetes文档中的集群内测试:
$ kubectl apply -f https://k8s.io/examples/application/shell-demo.yaml -n default
在进入我们的 shell pod 之前,我们需要集群 IP kong-proxy
:
$ kubectl get svc/kong-proxy -n kong -o jsonpath='{.spec.clusterIP}'
10.96.74.69
现在,我们可以获得 pod 的 shell 访问权限并测试速率限制:
$ kubectl exec --stdin --tty shell-demo -- /bin/bash
# curl -I 10.96.74.69/foo
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Connection: keep-alive
X-RateLimit-Limit-Second: 5
X-RateLimit-Remaining-Hour: 9998
X-RateLimit-Limit-Hour: 10000
RateLimit-Reset: 1
RateLimit-Remaining: 4
RateLimit-Limit: 5
X-RateLimit-Remaining-Second: 4
Date: Sat, 24 Jul 2021 20:01:35 GMT
Server: echoserver
X-Kong-Upstream-Latency: 0
X-Kong-Proxy-Latency: 0
Via: kong/2.4.1
对于大多数云提供商来说,使用中间 Pod 来测试速率限制这一额外步骤并非必需,因为它们会提供开箱即用的负载均衡器。在本例中,由于我们使用的是 Pod kind
,因此没有预置负载均衡器,因此我们的测试来自集群内部。如果有负载均衡器可用,同样的测试也可以在集群外部进行。
速率限制只是 Kong 融入您整体微服务战略和最佳实践的安全考量中的一个例子,但它可以轻松提供全面的解决方案。Kong 维护着多个插件和产品,以确保您的通信渠道坚不可摧,API 变更的影响最小化,并使您的应用程序域易于管理。此外,它兼容大多数编程语言和供应商选项。
7. 指标和监控
基于微服务架构的架构可以实现数百甚至数千个小型模块化服务的大规模扩展。虽然这在提升速度、可用性和覆盖范围方面拥有巨大的潜力,但庞大的微服务系统需要一种战略性和系统性的监控方法。通过密切关注所有微服务,您可以确保它们正常运行、可供用户使用,并合理地利用资源。如果任何一项预期未得到满足,您可以采取适当的措施来应对。
幸运的是,在监控方面,您无需重新设计。目前已有多种广泛采用的监控解决方案,可以无缝集成到您的基础架构中。一些解决方案使用指标导出器 SDK,只需在微服务中添加一两行代码即可集成。其他解决方案可以作为插件与您的 API 网关或服务网格集成,用于监控网络问题和资源使用情况。
当您的监控工具收集指标时,这些指标可以通过可视化工具(美观的仪表板)来使用,帮助您查看微服务背后的数据。上周四晚上 8:00 有多少用户在线?自从我们发布新功能以来,CPU 负载增加了多少?我们的产品发货 API 和发票 API 之间的延迟是多少?
通过监控您的微服务并清晰地呈现您的实际数据,您可以做出明智的决策,确保微服务健康且可用。如此一来,您的用户也会感到满意。
别忘了你的安全带……
微服务就像一场狂野之旅!首先,您将获得令人难以置信的优势:更快的部署速度和可扩展性,更少的停机时间,以及全面提升业务可用性。然后,您将加入编排平台,并结合一些由 Kong 及其插件提供支持的最佳实践,轰!您的微服务之间将拥有安全、可靠且坚不可摧的数据包交响乐。我们只介绍了 Kong 功能的一小部分,因此我强烈建议您查看Kong Hub,了解所有可用功能,以帮助您轻松迈向微服务的涅槃!
文章来源:https://dev.to/mbogan/7-microservices-best-practices-for-developers-ec5