基於 Kubernetes 的微服務專案設計與實現

語言: CN / TW / HK

來源:http://dwz.date/eFPd

隨著網際網路的發展,後端服務和容器編排技術的日益成熟,微服務成為了後端服務的首選,Kubernetes 也已經成為目前容器編排的事實標準, 微服務擁抱容器時代已經來臨。

筆者結合自己的經驗,寫了這篇微服務+ Kubernetes 入門寶典,希望能夠拋磚引玉。能讓大家瞭解 微服務和 Kubernetes 如何配合。

上卷主要描述 微服務設計,專案實現,kubernetes 部署,微服務的部署 高可用和監控 這幾個部分。

下卷計劃討論服務化網格和資料持久化, 有狀態服務,operator 這幾部分。

本文由我獨立完成([email protected])如有任何錯誤,是我個人原因,請直接和我聯絡,謝謝!您可以在https://github.com/xiaojiaqi/deploy-microservices-to-a-Kubernetes-cluster 找到本文的全文和相關資料。

本文會從設計開始,設計一個簡單的前後端分離的專案,並將它部署在 kubernetes 叢集上,期間我們將關注微服務和 kubernetes 配合的各個方面,並且從 系統的可用性,可靠性、強壯性、可擴充套件進行討論,最終設計一個可以真正實用的系統。

整體上我們從4個章節描述這個目標,分別是:

第一章:微服務專案的設計

第二章:微服務專案的具體實現

第三章:kubernetes的部署

第四章:微服務高可用部署及驗證

微服務是一種設計思想,它並不侷限於任何開發語言,在本例中我們選擇java的spring boot 框架來實現微服務。 微服務之間的 RPC 方案也很多,我們這裡選擇RESTFUL 這種最常見的方案。 為了專案的簡潔,專案也沒有涉及資料庫和快取,配置中心相關的內容。 我們主要注重專案的設計思想實踐和專案改進。

第一章:微服務專案的設計

1.1 微服務設計的思想

首先我們簡單地回顧一下微服務,微服務的定義當來自 Martin flowerlerhttps://martinfowler.com/articles/microservices.html 一文,借用大佬的一張圖 描述了微服務最本質的東西。

微服務把各個功能拆開了,每個模組的功能更加獨立,也更加單一。每個模組都獨立發展,可以說做到了功能的高內聚,低偶合。

再借一張,這樣資料庫也被徹底拆分開了。一個巨大複製的單體資料庫也按照功能拆成了小的獨立資料庫。

微服務就是這麼簡單嗎?當然不是,裡面有很多細節需要考慮,紙上得來終覺淺,絕知此事要躬行。這次讓我們開始從0開始真正的設計整套系統。

1.2 實踐設計和改進

現在我們要設計一個最簡單的微服務架構。為了更貼近真實的業務。我們假設這個系統是這樣的。

整個系統的前端是一個有著前後端分離站點,使用者訪問了www.demo.com 這個前端站點,通過前端頁面發起請求,www.demo.com 伺服器將請求發往a.demo.com.  然後a.demo.com 再請求b.demo.com ,b.demo.com 再請求 c.demo.com。c.demo.com 將結果返回後,不斷返回,最終顯示在前端站點,完成微服務的全套呼叫流程。[ 一般業務系統 在前端和微服務直接還存在一個閘道器部分,閘道器一般用於鑑權,請求分類,監控等功能, 這裡因為比較簡單,所以省略了這個部分]

最終我們將這套架構將部署在kubernetes 上,開始真正的服務使用者。

1.3 改進專案

從圖一我們可以看到這是一個非常簡單而單薄的架構,存在很多問題,我們需要不斷地解決它們。下面我們開始改進專案。

首先,我們要解決節點的可靠性。在圖一所有的節點都只有一個例項,任何節點的崩潰都將造成專案無法執行,在真正的專案中這是不可接受的。怎麼解決呢?當然是多個例項

1.3.1 加入多例項及註冊中心

我們將各個模組的例項數目增加,多個例項才能保證整個系統的可靠性。如果一個例項有問題,我們還是可以其他相同的例項進行服務。

但是多個例項又帶來一個問題,各個元件之間如何定位呢?如果有10個b.demo.com 例項,它的上下游又該如何找到它們呢?解決方案之一是註冊中心。註冊中心解決的是應用之間的定址問題。有了它,上下游之間的應用可以相互定址,並且獲知那些例項是可用的,應用挑選可用的例項進行工作。註冊中心的方案很多,有eureka,zookeeper, console, Nacos 等等,關於討論各種註冊中心是AP、CP的區別,優劣的文章很多,這篇文章不是一篇微服務的開發教程,我們選擇比較常見的eureka為演示的註冊中心。

注:在kubernetes 中部署微服務,對註冊中心是沒有任何限制的。所以不要被某些文章誤導,按照這篇文章做,你完全可以做到程式碼零修改,直接在kubernetes 上執行。

1.3.2 監控系統 Metrics

在完成了註冊中心的功能後,雖然整個系統可以運行了,我們會發現沒有應用監控的情況下,我們對系統運轉狀態是完全摸黑的,這樣相當於盲人騎馬,非常危險。我們需要知道所有微服務執行的狀態,必須將各個微服務的狀態監控起來,只有這樣才能做到 運籌帷幄,決勝千里。

在這裡,我們選擇使用Prometheus和Grafana這套監控組合。Prometheus + Grafana是一個比較常見的組合, 基本是現在容器監控的標準配置。

在kubernetes 上,我們需要每個微服務的例項裡開啟監控資料到匯出功能。同時利用Prometheus 的自動發現功能, 這樣Prometheus 可以將資料收集儲存起來。這裡的資料包括每個應用的各項指標比如記憶體大小,200錯誤數目,500錯誤數目, JVM裡執行緒數量,GC時間大小。配合granfana的聚合顯示能力,我們可以直觀地對整個系統有完整把控。在應用開發過程中,我們只需要在程式碼里加入一個類庫就可以實現資訊的匯出,不需要專門寫程式碼。

1.3.3 日誌系統 logging

目前已經有了監控,日誌還有存在的必要嗎?當然 下面這個圖就反應監控的3個維度。

這3個維度分別是Mertics Tracing 和logging

Metrics  主要就是指剛才說的監控,它主要反應的就是一個聚合的資料,比如今天200錯誤是多少,QPS是多少?它指的是一段時間內的資料聚合。

Logging 就是我們現在討論的日誌。的它描述一些離散的(不連續的)事件。比如各個系統裡的錯誤,告警。所以我們需要將日誌收集起來。

Tracing 則關注單次請求中資訊。我們關注請求的質量和服務可行性,是我們優化系統,排查問題的工具。

說到了日誌,在一個分散式系統,日誌是非常重要的一環。因為微服務和容器的緣故,導致日誌收集不是這麼簡單了。因為在kubernetes 裡 容器的銷燬和重啟都是經常可能出現的,我們需要第一時間就把日誌收集起來。

日誌收集的方案有很多,有些方案是在本地啟動一個收集程序,將落地的日誌轉發到kakfa元件再轉發日誌中心,也有的方案是直接寫到kafka元件直接進入日誌中心。兩者各有優劣。

在這裡,我們的方案選擇了後者。我們簡單地利用一個元件將日誌直接打入kafka 元件。這種方案的好處是我們日誌不再落地,日誌IO被消除了,日誌的儲存也和容器做到了分離。我們再也不用擔心日誌IO對宿主機造成的系統壓力了。

圖片

1.3.4      追蹤系統 Tracing

剛才我們討論了監控 (Metric)和日誌(Logging),還有一個維度就是追蹤(Tracing).

隨著微服務的例項越來越多,有一個很現實的問題出現了,當大規模分散式叢集出現了,應用構建在不同的容器叢集裡、有可能布在了幾千臺容器裡,橫跨多個不同的資料中心。因此,就需要一些可以幫助理解系統行為、用於分析效能問題的工具。這該怎麼解決呢?可以看看google的論文 google dapper

Google 的論文描述一種解決辦法,我們一般稱作APM(Application Performance Monitor). 它把一次呼叫加入一個獨立無二的標記,並且在各個系統裡透傳標記,從而達到追蹤整個訊息處理過程的能力。市面上大多數實現都是基於這一思想,可選方案的有很多,如 cat pip, zipkin, skywalkin。它們有需要程式碼注入的,有無注入的。關於他們的優劣也有很多文章評述。在這裡我們選用zipkin 。Zipkin 需要在專案中加入一個庫,並不需要寫程式碼,這對業務的入侵做到了很少,非常方便。

1.3.5 流量控制

你認為這一切就完了嗎?當然不是,微服務裡還有一項非常重要的功能:流量控制,我們還沒有做。

當海量的請求來臨的時候,我們可以用增加容器數量的辦法來提高我們的服務能力,但是簡單地新增例項是很危險的,因為整個系統的服務能力是被系統短板所限制的,簡單地新增例項,並不是總能起到提高服務能力的作用。反而可能引起反作用,最終導致整個系統的崩潰。

我們對整個系統的負載容量是有一個設計的,當超出我們設計的能力時,我們需要對多餘的請求說No。相應的方案分別是熔斷、限流和降級。目前java領域的這方面的hystrix,sentinel 在這方面都做得很好。Sentinel 在阿里接受了考驗,並且使用起來也很簡單,所以我們選它。現在我們在整個系統里加上一個流量控中心。這樣一個基本完整的 可靠的 高可靠的系統就基本完成了。

(在實際開發中,其實還有最關鍵的配置中心(apollo),資料庫(db),快取(redis) 等元件, 服務化網格, 我們可以把這些元件暫時放在kubernetes 之外,仍然是可以起到同樣的效果)

好了設計部分,先到這裡,開始實現。

第二章:微服務專案的具體實現

從 前端向後端開始實現

2.1 前端站點

前端站點的邏輯很簡單,就是顯示一個頁面,頁面中有一個按鍵。當你點選按鍵的時候,前端頁面發起ajax請求,訪問前端站點本身的一個介面,這個介面被nginx代理,轉發到a.demo.com 微服務上,a. demo.com 微服務再將請求轉發到b. demo.com, b. demo.com 再將請求轉發到c. demo.com. 最終將結果返回給前端。前端站點再將結果顯示在頁面上。我們通過

結果顯示,就能知道 這次請求通過了那些伺服器,每臺伺服器的服務執行時間大概是多少。

前端站點程式碼 大體如下:

然後看a、b、 c 應用部分的java程式碼,這就是個普通的多模組Maven專案。

專案很簡單,分成了3個部分,一個是註冊中心,也就是利用eureka實現註冊中心服務,另一個則是基礎庫專案,大部分功能都在這裡實現,最後則是各個微服務專案,微服務專案只需要簡單呼叫基礎庫就能完成。

2.2 註冊中心

註冊中心的程式碼非常簡單,只需要加一個簡單的宣告

這是註冊中心的配置檔案,在kubernetes叢集裡執行時,我們會執行3個節點組成高可用的註冊中心叢集。這時 這個配置項需要相應的修改。

2.3 基礎庫

在基礎庫專案裡,我們將很多的依賴都放在裡面,這樣應用專案只需要簡單依賴基礎庫就可以,能夠做到統一修改。

同時我們也可以看到大部分依賴庫只需要加入就可以,並不需編寫程式碼就可以工作,這讓開發工作變得輕鬆。

對於微服務的返回結果,我們做了一些美化格式。這樣可以在檢查結果時,比較容易。

簡單的定義了一些返回的結構,可以通過這些結構,微服務可以把處理時的時間戳,執行緒號,例項ip這些資訊返回出來。

基礎模組的日誌實現,從github 找的例子簡單地進行了修改。(簡單實現,不要用於生產)這時我們利用logback.xml 的配置,可以選擇我們是把日誌寫入本地磁碟還是直接寫入kafka.

2.4 a.demo.com b.demo.com c.demo.com 應用實現

實現很簡單,只是簡單地呼叫基礎庫就可以了。注意 每個應用需要實現一個探活介面 /hs. 這樣kubernetes 系統可以通過這個介面來探活,獲知你這個應用是不是準備好了,能不能接入流量。否則 你這個應用可能還在啟動過程中,但是流量已經接入了,那麼肯定會出問題。

在每個應用的配置裡,我們都預置了各個配置的專案,在本地執行的時候,我們可以填注入本地的配置,在kubernetes 裡 以容器形式進行執行,我們可以利用yaml來動態地修改它們,做到2種情況下完全相容。

第三章:kubernetes的部署

在完成應用的編寫後,我們需要安裝kubernetes系統了,如果已經有kubernetes 叢集的,就可以直接跳過這個部分了,請看下一章。除了kubernetes 叢集以外,你還需要Prometheus and Grafana這樣的監控元件。所以這裡我推薦一個牛逼的安裝工具,和所有現有的Kubernetes 安裝工具比,它是最好的,沒有之一。

它的名字是 K8seasy, 它的優點在於

  1. 可以一鍵安裝整體kubernetes 系統,無需瞭解任何背景知識
  2. 所有的映象都已經內建,不會因為下載映象失敗而導致失敗
  3. 安裝支援各種不同版本kubernetes版本
  4. 安裝的服務是二進位制版本的,非容器版本, 穩定高效
  5. 支援安裝3節點 高可用的生產環境叢集

3.1 安裝過程

下載K8seasy,官方主頁 https://github.com/xiaojiaqi/K8seasy_release_page

安裝下載頁:http://dl.K8seasy.com/

將3個安裝檔案都下載下來, 其中 pack.2020.10.02.bin 和installer 都是安裝檔案, kubernetes-server-linux-amd64.tar.gz 是kubernetes 的官方軟體包,你可以自己選擇一個最新的版本。

如果要選擇一個其他版本的kubernetes

安裝的過程很簡單,2條命令即可,這裡我們假設 需要安裝Kubernetes的網路為 192.168.2.0, master 主機為192.168.2.50

1 建立金鑰

sudo ./installer --genkey -hostlist=192.168.2.1

2 建立叢集

sudo ./installer -kubernetestarfile kubernetes-server-linux-amd64v1.18.2.tar.gz -masterip 192.168.2.50

稍等一會兒 就能看到類似如下輸出

就這麼簡單,一個Kubernetes已經裝好了。此時相關的所有監控已經被完全安裝好了。

3. 各項監控

以master 節點為 192.168.2.50 為例子

http://192.168.2.50:10000 可以直接開啟dashboard, 對整個叢集有一個全面瞭解

開啟 http://192.168.2.50:8080  可以直接訪問alertmanager

開啟 http://192.168.2.50:8081 你可以直接使用 Grafana (使用者 admin, 密碼admin)

開啟 http://192.168.2.50:8082 你可以訪問 Prometheus.

4. 多套環境監控

這一切就完了嗎?當然不是,為了支援多叢集管理,再推薦一個工具。剛才我們說到直接使用 http://192.168.2.50:1000 這個頁面可以直接管理整個叢集,但是在公司裡如果有多個叢集,該如何管理呢? 別擔心,K8seasy 已經有對應的解決方案

仔細看剛才的安裝好的日誌,裡面提示你 專門生產了一個 lens.kubeconfig 的配置檔案, 並且有一個 域名和 ip 的對應表。這時候,你只需要 首先在本地Host 檔案里加入這個對應

然後去 https://Kuberneteslens.dev/

下載一個lens的安裝包。安裝lens以後,你只需要將 lens.kubeconfig 匯入到lens裡

匯入完成後,你就可以遠端管理這個叢集了。這樣有多個叢集,你也可以只用一套lens 進行管理了。

Lens的介面優美,使用方便,快試試吧。

好了 Kubernetes 的安裝完成了。當然了K8seasy 的功能是非常強大的,你可以用 sudo ./installer -h 檢視幫助, 也可以使用 sudo ./installer -demo 檢視各種場景的安裝幫助。

第四章:微服務高可用部署及驗證

Kubernetes 裝好了,現在開始將微服務部署上去了。我們剛才的程式碼只是Java 原始碼,我們還需要將它們編譯成Jar包,然後再打成docker 映象才能部署,這部分比較簡單,所以我不演示如何完成了,我將相關的Dockerfile 和 最終Yaml 都放在Github 裡了,在開始開發時,我提到將日誌寫入Kafka, 所以有2套配置,一套使用了Kafak 一套沒有使用Kafka。請注意區別,有因為沒有Kafka 比較容易實施,我這裡就演示沒有Kafak的版本。這樣所有隻要有一臺Linux 就可以保證將整個流程實施成功。

4.1  服務部署上去

依次執行每條部署Yaml的命令即可,不需要做其他的操作。

注意,映象在Docker-Hub, 可能需要一定時間能下載。

執行後在 Dashboard 檢視,你可以看到類似的資訊,所有的服務都已經成功執行。

檢視Dashboard

此時修改你本地的Hosts

這樣的話,因為我們的Kubernetes 是支援 nginx-ingress的,所以你可以直接訪問Master的物理IP來訪問這些服務,不需要做任何轉換。

首先我們可以開啟dashboard 從中查到eureka.伺服器的具體ip, 然後訪問eurka 服務。

檢視註冊中心

在頁面中你可以發現,在Kubernetes叢集裡,我們啟動了3個eureka服務,它們相互註冊,組成了一個高可用叢集。

其次,我們在Grafana 中匯入 jvm 的監控專案

這樣Grafana可以幫助我們把 各個Java服務的具體狀態做一個收集,完成我們需要的監控。

前端驗證

此時 我們開啟 http://www.demo.com 的網頁。

我們可以點選頁面上的 get 請求按鍵,模擬發出請求,隨後我們就會發現頁面裡顯示出的資訊在不斷變化。

在頁面顯示的內容裡,我們可以清楚地發現,我們的訊息在不同例項裡處理,如果有一個例項出現了故障是不會影響我們現在的業務的。

好了開始驗證整個系統。

模擬驗證

使用一個簡單的指令碼 模擬每3秒從前端訪問一次後端。

呼叫關係驗證

首先開啟zipkin  zipkin.demo.com

點選具體的請求,可以檢視到每次請求在內部的細節。

限流熔斷驗證

其次 開啟 sentinel 站點,這個站點可以監控,也可以對微服務進行限流,限速,熔斷等操作。(密碼口令都是 sentinel)

進入控制檯後,我們可以發現所有的服務已經自動被發現,並存在於左邊的選單。

分別點開 a b c 3個服務,可以看到規律的週期訪問,和我們的指令碼的測試速度是一致的。

Sentinel 裡面內含強大的監控,流控 降級等功能,具體的使用,可以慢慢學習,相信你一定會受益良多。

應用狀態驗證

開啟Grafana的監控頁,你可以檢視所有應用的狀態,包括heap 大小,啟動時間,錯誤數目 等等。

通過這張圖你可以瞭解每個應用本身的狀態,使用了多少記憶體,響應的程式碼是多少,jvm 使用情況。相信此時 你已經對各個元件的情況,監控都有了一個全面瞭解。一個基於 Kubernetes 的微服務架構已經開始工作了。

最後送一張常用的系統架構圖,希望大家能通過本文對高可用微服務如何架設 Kubernetes 上有一個基本的瞭解,將本文討論的東西用於實踐。謝謝!


如果此文對你有所幫助,希望能隨手點個轉發!



End




乾貨分享



這裡為大家準備了一份小小的禮物,關注公眾號,輸入如下程式碼,即可獲得百度網盤地址,無套路領取!

001:《程式設計師必讀書籍》
002:《從無到有搭建中小型網際網路公司後臺服務架構與運維架構》
003:《網際網路企業高併發解決方案》
004:《網際網路架構教學視訊》
006:《SpringBoot實現點餐系統》
007:《SpringSecurity實戰視訊》
008:《Hadoop實戰教學視訊》
009:《騰訊2019Techo開發者大會PPT》

010: 微信交流群


我就知道你“在看”






本文分享自微信公眾號 - JAVA日知錄(javadaily)。
如有侵權,請聯絡 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。