微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

來源:http://dockone.io/article/8564

翻譯:池劍鋒

【編者的話】本文通過一個詳細的購物例子,展示瞭如何利用消息隊列,Spring Boot 和Kubernetes進行微服務的開發,並闡述了針對微服務的伸縮,監控等方式,幫助用戶快速利用這些工具開發健壯的系統。

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

當你設計和構建大規模應用時,你將面臨兩個重大挑戰: 可伸縮性和健壯性

你應該這樣設計你的服務,即使它受到間歇性的重負載,它仍能可靠地運行。

以Apple Store為例。

每年都有數百萬的Apple客戶預先註冊購買新的iPhone。

這是數百萬人同時購買物品。

如果你要將Apple商店的流量描述為每秒的請求數量,那麼它可能是下圖的樣子:

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

現在想象一下,你的任務是構建這樣的應用程序。

你正在建立一個商店,用戶可以在那裡購買自己喜歡的商品。

你構建一個微服務來呈現網頁並提供靜態資產。 你還構建了一個後端REST API來處理傳入的請求。

你希望將兩個組件分開,因為這樣可以使用相同的REST API,為網站和移動應用程序提供服務。

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

今天是重要的一天,你的商店上線了。

你決定將應用程序擴展為前端四個實例和後端四個實例,因為你預測網站比平常更繁忙。

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

你開始接收越來越多的流量。

前端服務正在很好得處理流量。 但是你注意到連接到數據庫的後端正在努力跟上事務的數量。

不用擔心,你可以將後端的副本數量擴展到8。

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

你收到的流量更多,後端無法應對。

一些服務開始丟棄連接。 憤怒的客戶與你的客服取得聯繫。 而現在你被淹沒在大量流量中。

你的後端無法應付它,它會失去很多連接。

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

你剛丟了一大筆錢,你的顧客也不高興。

你的應用程序並沒有設計得健壯且高可用:

  • 前端和後端緊密耦合 - 實際上它不能在沒有後端的情況下處理應用
  • 前端和後端必須一致擴展 - 如果沒有足夠的後端,你可能會淹沒在流量中
  • 如果後端不可用,則無法處理傳入的事務。

失去事務意味著收入損失。

你可以重新設計架構,以便將前端和後端用隊列分離。

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

前端將消息發佈到隊列,而後端則一次處理一個待處理消息。

新架構有一些明顯的好處:

  • 如果後端不可用,則隊列充當緩衝區
  • 如果前端產生的消息多於後端可以處理的消息,則這些消息將緩衝在隊列中
  • 你可以獨立於前端擴展後端 - 即你可以擁有數百個前端服務和後端的單個實例

太好了,但是你如何構建這樣的應用程序?

你如何設計可處理數十萬個請求的服務? 你如何部署動態擴展的應用程序?

在深入瞭解部署和擴展的細節之前,讓我們關注應用程序。

編寫Spring應用程序

該服務有三個組件:前端,後端和消息代理。

前端是一個簡單的Spring Boot Web應用程序,帶有Thymeleaf模板引擎。

後端是一個消耗隊列消息的工作者。

由於Spring Boot與JSM能出色得集成,因此你可以使用它來發送和接收異步消息。

你可以在learnk8s / spring-boot-k8s-hpa中找到一個連接到JSM的前端和後端應用程序的示例項目。

請注意,該應用程序是用Java 10編寫的,以利用改進的Docker容器集成能力。

只有一個代碼庫,你可以將項目配置為作為前端或後端運行。

你應該知道該應用程序具有:

/health
/submit
/metrics

該應用程序可以在兩種模式下運行:

作為前端,應用程序呈現人們可以購買物品的網頁。

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

作為工作者,應用程序等待隊列中的消息並處理它們。

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

請注意,在示例項目中,使用 Thread.sleep(5000) 等待五秒鐘來模擬處理。

你可以通過更改 application.yaml 中的值來在任一模式下配置應用程序。

模擬應用程序的運行

默認情況下,應用程序作為前端和工作程序啟動。

你可以運行該應用程序,只要你在本地運行ActiveMQ實例,你就應該能夠購買物品並讓系統處理這些物品。

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

如果檢查日誌,則應該看到工作程序處理項目。

它確實工作了! 編寫Spring Boot應用程序很容易。

一個更有趣的主題是學習如何將Spring Boot連接到消息代理。

使用JMS發送和接收消息

Spring JMS(Java消息服務)是一種使用標準協議發送和接收消息的強大機制。

如果你以前使用過JDBC API,那麼你應該熟悉JMS API,因為它的工作方式很類似。

你可以按JMS方式來使用的最流行的消息代理是ActiveMQ - 一個開源消息服務器。

使用這兩個組件,你可以使用熟悉的接口(JMS)將消息發佈到隊列(ActiveMQ),並使用相同的接口來接收消息。

更妙的是,Spring Boot與JMS的集成非常好,因此你可以立即加快速度。

實際上,以下短類封裝了用於與隊列交互的邏輯:

@Component
public class QueueService implements MessageListener {
private static final Logger LOGGER = LoggerFactory.getLogger(QueueService.class);
@Autowired
private JmsTemplate jmsTemplate;
public void send(String destination, String message) {
LOGGER.info("sending message='{}' to destination='{}'", message, destination);
jmsTemplate.convertAndSend(destination, message);
}
@Override
public void onMessage(Message message) {
if (message instanceof ActiveMQTextMessage) {

ActiveMQTextMessage textMessage = (ActiveMQTextMessage) message;
try {
LOGGER.info("Processing task " textMessage.getText());
Thread.sleep(5000);
LOGGER.info("Completed task " textMessage.getText());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (JMSException e) {
e.printStackTrace();
}
} else {
LOGGER.error("Message is not a text message " message.toString());
}
}

}

你可以使用 send 方法將消息發佈到命名隊列。

此外,Spring Boot將為每個傳入消息執行 onMessage 方法。

最後一個難題是指示Spring Boot使用該類。

你可以通過在Spring Boot應用程序中註冊偵聽器來在後臺處理消息,如下所示:

@SpringBootApplication
@EnableJms
public class SpringBootApplication implements JmsListenerConfigurer {
@Autowired
private QueueService queueService;
public static void main(String[] args) {
SpringApplication.run(SpringBootApplication.class, args);
}
@Override
public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
endpoint.setId("myId");
endpoint.setDestination("queueName");
endpoint.setMessageListener(queueService);
registrar.registerEndpoint(endpoint);
}

}

其中 id 是使用者的唯一標識符, destination 是隊列的名稱。

你可以從GitHub上的項目中完整地讀取Spring隊列服務的源代碼。

回顧一下你是如何在少於40行代碼中編寫可靠隊列的。

你一定很喜歡Spring Boot。

你在部署時節省的所有時間都可以專注於編碼

你驗證了應用程序的工作原理,現在是時候部署它了。

此時,你可以啟動VPS,安裝Tomcat,並花些時間製作自定義腳本來測試,構建,打包和部署應用程序。

或者你可以編寫你希望擁有的描述:一個消息代理和兩個使用負載均衡器部署的應用程序。

諸如Kubernetes之類的編排器可以閱讀你的願望清單並提供正確的基礎設施。

由於花在基礎架構上的時間減少意味著更多的時間編碼,這次你將把應用程序部署到Kubernetes。但在開始之前,你需要一個Kubernetes集群。

你可以註冊Google雲平臺或Azure,並使用Kubernetes提供的雲提供商服務。或者,你可以在將應用程序移動到雲上之前在本地嘗試Kubernetes。

minikube 是一個打包為虛擬機的本地Kubernetes集群。如果你使用的是Windows,Linux和Mac,那就太好了,因為創建群集需要五分鐘。

你還應該安裝 kubectl ,即連接到你的群集的客戶端。

你可以從官方文檔中找到有關如何安裝 minikube 和 kubectl 的說明。

如果你在Windows上運行,則應查看有關如何安裝Kubernetes和Docker的詳細指南。

你應該啟動一個具有8GB RAM和一些額外配置的集群:

minikube start \
--memory 8096 \
--extra-config=controller-manager.horizontal-pod-autoscaler-upscale-delay=1m \
--extra-config=controller-manager.horizontal-pod-autoscaler-downscale-delay=2m \
--extra-config=controller-manager.horizontal-pod-autoscaler-sync-period=10s

請注意,如果你使用的是預先存在的 minikube 實例,則可以通過銷燬VM來重新調整VM的大小。 只需添加 --memory 8096 就不會有任何影響。

驗證安裝是否成功。 你應該看到以列表形式展示的一些資源。 集群已經準備就緒, 也許你應該立即開始部署?

還不行。

你必須先裝好你的東西。

什麼比uber-jar更好?容器

部署到Kubernetes的應用程序必須打包為容器。畢竟,Kubernetes是一個容器編排器,所以它本身無法運行你的jar。

容器類似於fat jar:它們包含運行應用程序所需的所有依賴項。 甚至JVM也是容器的一部分 。所以他們在技術上是一個更胖的fat-jar。

將應用程序打包為容器的流行技術是Docker。

雖然Docker是最受歡迎的,但它並不是唯一能夠運行容器的技術。其他受歡迎的選項包括 rkt和 lxd 。

如果你沒有安裝Docker,可以按照Docker官方網站上的說明進行操作。

通常,你構建容器並將它們推送到倉庫。它類似於向Artifactory或Nexus推送jar包。但在這種特殊情況下,你將在本地工作並跳過倉庫部分。實際上,你將直接在 minikube 中創建容器鏡像。

首先,按照此命令打印的說明將Docker客戶端連接到 minikube :

minikube docker-env

請注意,如果切換終端,則需要重新連接 minikube 內的Docker守護程序。 每次使用不同的終端時都應遵循相同的說明。

並從項目的根目錄構建容器鏡像:

docker build -t spring-k8s-hp0a .

你可以驗證鏡像是否已構建並準備好運行:

docker images |grep spring 

很好。

群集已準備好,你打包應用程序, 也許你已準備好立即部署?

是的,你最終可以要求Kubernetes部署應用程序。

將你的應用程序部署到Kubernetes

你的應用程序有三個組件:

  • 呈現前端的Spring Boot應用程序
  • ActiveMQ作為消息代理
  • 處理事務的Spring Boot後端

你應該分別部署這三個組件。

對於每個組件你都應該創建:

  • Deployment 對象,描述部署的容器及其配置
  • 一個 Service 對象,充當 Deployment 部署創建的應用程序的所有實例的負載均衡器

部署中的每個應用程序實例都稱為 Pod

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

部署ActiveMQ

讓我們從ActiveMQ開始吧。

你應該創建一個 activemq-deployment.yaml 文件,其中包含以下內容:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: queue
spec:
replicas: 1
template:
metadata:
labels:
app: queue
spec:
containers:
- name: web
image: webcenter/activemq:5.14.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 61616
resources:
limits:
memory: 512Mi

該模板冗長但直接易讀:

  • 你從名為webcenter / activemq的官方倉庫中請求了一個activemq容器
  • 容器在端口61616上公開消息代理
  • 為容器分配了512MB的內存
  • 你要求提供單個副本 - 你的應用程序的單個實例

使用以下內容創建 activemq-service.yaml 文件:

apiVersion: v1
kind: Service
metadata:
name: queue
spec:
ports:
- port: 61616
targetPort: 61616
selector:
app: queue

幸運的是,這個模板更短!

這個yaml表示:

app:queue
targetPort

你可以使用以下命令創建資源:

kubectl create -f activemq-deployment.yaml
kubectl create -f activemq-service.yaml

你可以使用以下命令驗證數據庫的一個實例是否正在運行:

kubectl get pods -l=app=queue

部署前端

使用以下內容創建 fe-deployment.yaml 文件:

apiVersion: extensions/v1beta1 

kind: Deployment
metadata:
name: frontend
spec:
replicas: 1
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: spring-boot-hpa
imagePullPolicy: IfNotPresent
env:
- name: ACTIVEMQ_BROKER_URL
value: "tcp://queue:61616"
- name: STORE_ENABLED
value: "true"
- name: WORKER_ENABLED
value: "false"
ports:
- containerPort: 8080
livenessProbe:
initialDelaySeconds: 5
periodSeconds: 5
httpGet:
path: /health
port: 8080
resources:
limits:
memory: 512Mi

Deployment看起來很像前一個。

但是有一些新的字段:

  • 有一個section可以注入環境變量
  • 還有liveness探針,可以告訴你應用程序何時可以接受流量

使用以下內容創建 fe-service.yaml 文件:

apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
ports:
- nodePort: 32000
port: 80
targetPort: 8080
selector:
app: frontend
type: NodePort

你可以使用以下命令創建資源:

kubectl create -f fe-deployment.yaml
kubectl create -f fe-service.yaml

你可以使用以下命令驗證前端應用程序的一個實例是否正在運行:

kubectl get pods -l=app=frontend

部署後端

使用以下內容創建 backend-deployment.yaml 文件:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: backend
spec:
replicas: 1
template:
metadata:
labels:
app: backend
annotations:
prometheus.io/scrape: 'true'
spec:

containers:
- name: backend
image: spring-boot-hpa
imagePullPolicy: IfNotPresent
env:
- name: ACTIVEMQ_BROKER_URL
value: "tcp://queue:61616"
- name: STORE_ENABLED
value: "false"
- name: WORKER_ENABLED
value: "true"
ports:
- containerPort: 8080
livenessProbe:
initialDelaySeconds: 5
periodSeconds: 5
httpGet:
path: /health
port: 8080
resources:
limits:
memory: 512Mi

使用以下內容創建 backend-service.yaml 文件:

apiVersion: v1
kind: Service
metadata:
name: backend
spec:
ports:
- nodePort: 31000
port: 80
targetPort: 8080
selector:
app: backend
type: NodePort

你可以使用以下命令創建資源:

kubectl create -f backend-deployment.yaml
kubectl create -f backend-service.yaml

你可以驗證後端的一個實例是否正在運行:

kubectl get pods -l=app=backend

部署完成。

它真的有效嗎?

你可以使用以下命令在瀏覽器中訪問該應用程序:

minikube service backend

minikube service frontend

如果它有效,你應該嘗試購買一些物品!

工作者在處理交易嗎?

是的,如果有足夠的時間,工作人員將處理所有待處理的消息。

恭喜!

你剛剛將應用程序部署到Kubernetes!

手動擴展以滿足不斷增長的需求

單個工作程序可能無法處理大量消息。 實際上,它當時只能處理一條消息。

如果你決定購買數千件物品,則需要數小時才能清除隊列。

此時你有兩個選擇:

  • 你可以手動放大和縮小
  • 你可以創建自動縮放規則以自動向上或向下擴展

讓我們先從基礎知識開始。

你可以使用以下方法將後端擴展為三個實例:

kubectl scale --replicas=5 deployment/backend

你可以驗證Kubernetes是否創建了另外五個實例:

kubectl get pods

並且應用程序可以處理五倍以上的消息。

一旦工人排空隊列,你可以縮小:

kubectl scale --replicas=1 deployment/backend

如果你知道最多的流量何時達到你的服務,手動擴大和縮小都很棒。

如果不這樣做,設置自動縮放器允許應用程序自動縮放而無需手動干預。

你只需要定義一些規則。

公開應用程序指標

Kubernetes如何知道何時擴展你的申請?

很簡單,你必須告訴它。

自動調節器通過監控指標來工作。 只有這樣,它才能增加或減少應用程序的實例。

因此,你可以將隊列長度公開為度量標準,並要求autoscaler觀察該值。 隊列中的待處理消息越多,Kubernetes將創建的應用程序實例就越多。

那麼你如何公開這些指標呢?

應用程序具有 /metrics 端點以顯示隊列中的消息數。 如果你嘗試訪問該頁面,你會注意到以下內容:

# HELP messages Number of messages in the queue

TYPE messages gauge

messages 0

應用程序不會將指標公開為JSON格式。 格式為純文本,是公開Prometheus指標的標準。 不要擔心記憶格式。 大多數情況下,你將使用其中一個Prometheus客戶端庫。

在Kubernetes中使用應用程序指標

你幾乎已準備好進行自動縮放 - 但你應首先安裝度量服務器。 實際上,默認情況下,Kubernetes不會從你的應用程序中提取指標。 如果你願意,可以啟用Custom Metrics API。

要安裝Custom Metrics API,你還需要Prometheus - 時間序列數據庫。 安裝Custom Metrics API所需的所有文件都可以方便地打包在learnk8s / spring-boot-k8s-hpa中。

你應下載該存儲庫的內容,並將當前目錄更改為該項目的 monitoring 文件夾。

cd spring-boot-k8s-hpa/monitoring

從那裡,你可以創建自定義指標API:

kubectl create -f ./metrics-server
kubectl create -f ./namespaces.yaml
kubectl create -f ./prometheus
kubectl create -f ./custom-metrics-api

你應該等到以下命令返回自定義指標列表:

kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1" | jq .

任務完成!

你已準備好使用指標。

實際上,你應該已經找到了隊列中消息數量的自定義指標:

kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/messages" | jq .

恭喜,你有一個公開指標的應用程序和使用它們的指標服務器。

你最終可以啟用自動縮放器!

在Kubernetes中進行自動擴展部署

Kubernetes有一個名為Horizontal Pod Autoscaler的對象,用於監視部署並上下調整Pod的數量。

你將需要其中一個來自動擴展實例。

你應該創建一個包含以下內容的 hpa.yaml 文件:

apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: spring-boot-hpa
spec:
scaleTargetRef:
apiVersion: extensions/v1beta1
kind: Deployment
name: backend
minReplicas: 1
maxReplicas: 10
metrics:
- type: Pods
pods:
metricName: messages
targetAverageValue: 10

這個文件很神秘,所以讓我為你翻譯一下:

  • Kubernetes監視 scaleTargetRef 中指定的部署。 在這種情況下,它是工人。
  • 你正在使用 messages 指標來擴展你的 Pod 。 當隊列中有超過十條消息時,Kubernetes將觸發自動擴展。
  • 至少,部署應該有兩個 Pod 。 10個 Pod 是上限。

你可以使用以下命令創建資源:

kubectl create -f hpa.yaml

提交自動縮放器後,你應該注意到後端的副本數量是兩個。 這是有道理的,因為你要求自動縮放器始終至少運行兩個副本。

你可以檢查觸發自動縮放器的條件以及由此產生的事件:

kubectl describe hpa

自動定標器表示它能夠將Pod擴展到2,並且它已準備好監視部署。

令人興奮的東西,但它有效嗎?

負載測試

只有一種方法可以知道它是否有效:在隊列中創建大量消息。

轉到前端應用程序並開始添加大量消息。 在添加消息時,使用以下方法監視Horizontal Pod Autoscaler的狀態:

kubectl describe hpa

Pod的數量從2上升到4,然後是8,最後是10。

該應用程序隨消息數量而變化! 歡呼!

你剛剛部署了一個完全可伸縮的應用程序,可根據隊列中的待處理消息數進行擴展。

另外,縮放算法如下:

MAX(CURRENT_REPLICAS_LENGTH * 2, 4)

在解釋算法時,文檔沒有多大幫助。 你可以在代碼中找到詳細信息。

此外,每分鐘都會重新評估每個放大,而每兩分鐘縮小一次。

以上所有都是可以調整的設置。

但是你還沒有完成。

什麼比自動縮放實例更好? 自動縮放群集。

跨節點縮放Pod非常有效。 但是,如果群集中沒有足夠的容量來擴展Pod,該怎麼辦?

如果達到峰值容量,Kubernetes將使Pods處於暫掛狀態並等待更多資源可用。

如果你可以使用類似於Horizontal Pod Autoscaler的自動縮放器,但對於節點則會很棒。

好消息!

你可以擁有一個群集自動縮放器,可以在你需要更多資源時為Kubernetes群集添加更多節點。

微服務:如何使用消息隊列、Spring Boot和Kubernetes擴展微服務

群集自動縮放器具有不同的形狀和大小。它也是特定於雲提供商的。

請注意,你將無法使用 minikube 測試自動縮放器,因為它根據定義是單節點。

你可以在Github上找到有關集群自動調節器和雲提供程序實現的更多信息。

概覽

設計大規模應用程序需要仔細規劃和測試。

基於隊列的體系結構是一種出色的設計模式,可以解耦你的微服務並確保它們可以獨立擴展和部署。

雖然你可以用腳本來擴展你的應用,但可以更輕鬆地利用容器編排器(如Kubernetes)自動部署和擴展應用程序。

今天先說到這裡。

英文標題: How to scale Microservices with Message Queues, Spring Boot, and Kubernetes

原文網址:https://medium.freecodecamp.org/how-to-scale-microservices-with-message-queues-spring-boot-and-kubernetes-f691b7ba3acf


分享到:


相關文章: