日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 拉起服务_技术开发者应该如何构建小团队的微服务方案?

發布時間:2023/12/2 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 拉起服务_技术开发者应该如何构建小团队的微服务方案? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者 | 徐鵬

責編 | 劉靜

出品 | CSDN(ID:CSDNnews)

我們的產品是Linkflow,企業運營人員使用的客戶數據平臺(CDP)。產品的一個重要部分類似企業版的”捷徑”,讓運營人員可以像搭樂高積木一樣創建企業的自動化流程,無需編程即可讓數據流動起來。從這一點上,我們的業務特點就是聚少成多,把一個個服務連接起來就成了數據的海洋。理念上跟微服務一致,一個個獨立的小服務最終實現大功能。當然我們一開始也沒有使用微服務,當業務還未成型就開始考慮架構,那么就是”過度設計”。另一方面需要考慮的因素就是”人”,有沒有經歷過微服務項目的人,團隊是否有devops文化等等,綜合考量是否需要微服務化。

要不要微服務

微服務的好處是什么?

  • 相比于單體應用,每個服務的復雜度會下降,特別是數據層面(數據表關系)更清晰,不會一個應用上百張表,新員工上手快;

  • 對于穩定的核心業務可以單獨成為一個服務,降低該服務的發布頻率,也減少測試人員壓力;

  • 可以將不同密集型的服務搭配著放到物理機上,或者單獨對某個服務進行擴容,實現硬件資源的充分利用;

  • 部署靈活,在私有化項目中,如果客戶有不需要的業務,那么對應的微服務就不需要部署,節省硬件成本,就像上文提到的樂高積木理念。

微服務有什么挑戰?

  • 一旦設計不合理,交叉調用,相互依賴頻繁,就會出現牽一發動全身的局面。想象單個應用內service層依賴復雜的場面就明白了;

  • 項目多了,輪子需求也會變多,需要有人專注公共代碼的開發;

  • 開發過程的質量需要通過持續集成(CI)嚴格把控,提高自動化測試的比例,因為往往一個接口改動會涉及多個項目,光靠人工測試很難覆蓋所有情況;

  • 發布過程會變得復雜,因為微服務要發揮全部能力需要容器化的加持,容器編排就是最大的挑戰;

  • 線上運維,當系統出現問題需要快速定位到某個機器節點或具體服務,監控和鏈路日志分析都必不可少。

下面詳細說說我們是怎么應對這些挑戰的:

開發過程的挑戰

持續集成:

  • 通過CI將開發過程規范化,串聯自動化測試和人工Review;

  • 我們使用Gerrit作為代碼&分支管理工具,在流程管理上遵循Gitlab的工作流模型;

  • 開發人員提交代碼至Gerrit的magic分支;

  • 代碼Review人員Review代碼并給出評分;

  • 對應Repo的Jenkins job監聽分支上的變動,觸發Build job。經過IT和Sonar的靜態代碼檢查給出評分;

  • Review和Verify皆通過之后,相應Repo的負責人將代碼merge到真實分支上若有一項不通過,代碼修改后重復過程;

  • Gerrit將代碼實時同步備份至的兩個遠程倉庫中。

集成測試

一般來說代碼自動執行的都是單元測試(Unit Test),即不依賴任何資源(數據庫,消息隊列)和其他服務,只測試本系統的代碼邏輯。但這種測試需要mock的部分非常多,一是寫起來復雜,二是代碼重構起來跟著改的測試用例也非常多,顯得不夠敏捷。而且一旦要求開發團隊要達到某個覆蓋率,就會出現很多造假的情況。所以我們選擇主要針對API進行測試,即針對controller層的測試。另外對于一些公共組件如分布式鎖,json序列化模塊也會有對應的測試代碼覆蓋。測試代碼在運行時會采用一個隨機端口拉起項目,并通過http client對本地API發起請求,測試只會對外部服務做mock,數據庫的讀寫,消息隊列的消費等都是真實操作,相當于把Jmeter的事情在Java層面完成一部分。Spring Boot項目可以很容易的啟動這樣一個測試環境,代碼如下:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

測試過程的http client推薦使用io.rest-assured:rest-assured支持JsonPath,十分好用。

測試時需要注意的一個點是測試數據的構造和清理。構造又分為schema的創建和測試數據的創建。

  • schema由flyway處理,在啟用測試環境前先刪除所有表,再進行表的創建;

  • 測試數據可以通過@Sql讀取一個sql文件進行創建,在一個用例結束后再清除這些數據。

順帶說一下,基于flyway的schema upgrade功能我們封成了獨立的項目,每個微服務都有自己的upgrade項目,好處一是支持command-line模式,可以細粒度的控制升級版本,二是也可以支持分庫分表以后的schema操作。upgrade項目也會被制作成docker image提交到docker hub。

測試在每次提交代碼后都會執行,Jenkins監聽gerrit的提交,通過docker run -rm {upgrade項目的image}先執行一次schema upgrade,然后gradle test執行測試。最終會生成測試報告和覆蓋率報告,覆蓋率報告采用jacoco的gradle插件生成。如圖:

這里多提一點,除了集成測試,服務之間的接口要保證兼容,實際上還需要一種consumer-driven testing tool,就是說接口消費端先寫接口測試用例,然后發布到一個公共區域,接口提供方發布接口時也會執行這個公共區域的用例,一旦測試失敗,表示接口出現了不兼容的情況。比較推薦大家使用Pact或是Spring Cloud Contact。我們目前的契約基于”人的信任“,畢竟服務端開發者還不多,所以沒有必要使用這樣一套工具。

集成測試的同時還會進行靜態代碼檢查,我們用的是sonar,當所有檢查通過后jenkins會+1分,再由reviewer進行代碼review。

自動化測試

單獨拿自動化測試出來說,就是因為它是質量保證的非常重要的一環,上文能在CI中執行的測試都是針對單個微服務的,那么當所有服務(包括前端頁面)都在一起工作的時候是否會出現問題,就需要一個更接近線上的環境來進行測試了。

在自動化測試環節,我們結合Docker提高一定的工作效率并提高測試運行時環境的一致性以及可移植性。在準備好基礎的Pyhton鏡像以及Webdriver(selenium)之后,我們的自動化測試工作主要由以下主要步驟組成:

  • 測試人員在本地調試測試代碼并提交至Gerrit;

  • Jenkins進行測試運行時環境的鏡像制作,主要將引用的各種組件和庫打包進一個Python的基礎鏡像;

  • 通過Jenkins定時或手動觸發,調用環境部署的job將專用的自動化測試環境更新,然后拉取自動化測試代碼啟動一次性的自動化測試運行時環境的Docker容器,將代碼和測試報告的路徑鏡像至容器內;

  • 自動化測試過程將在容器內進行;

  • 測試完成之后,不必手動清理產生的各種多余內容,直接在Jenkins上查看發布出來的測試結果與趨勢。

關于部分性能測試的執行,我們同樣也將其集成到Jenkins中,在可以直觀的通過一些結果數值來觀察版本性能變化情況的回歸測試和基礎場景,將會很大程度的提高效率、便捷的觀察趨勢。

  • 測試人員在本地調試測試代碼并提交至Gerrit;

  • 通過Jenkins定時或手動觸發,調用環境部署的job將專用的性能測試環境更新以及可能的Mock Server更新;

  • 拉取最新的性能測試代碼,通過Jenkins的性能測試插件來調用測試腳本;

  • 測試完成之后,直接在Jenkins上查看通過插件發布出來的測試結果與趨勢。

布過程的挑戰

上面提到微服務一定需要結合容器化才能發揮全部優勢,容器化就意味線上有一套容器編排平臺。我們目前采用是Redhat的Openshift。所以發布過程較原來只是啟動jar包相比要復雜的多,需要結合容器編排平臺的特點找到合適的方法。

鏡像準備

公司開發基于gitlab的工作流程,git分支為master,pre-production和prodution三個分支,同時生產版本發布都打上對應的tag。每個項目代碼里面都包含dockerfile與jenkinsfile,通過jenkins的多分支pipeline來打包docker鏡像并推送到harbor私庫上。

docker鏡像的命令方式為 項目名/分支名:git_commit_id,如 funnel/production:4ee0b052fd8bd3c4f253b5c2777657424fccfbc9,tag版本的docker鏡像命名為 項目名/release:tag名,如 funnel/release:18.10.R1

在jenkins中執行build docker image job時會在每次pull代碼之后調用harbor的api來判斷此版本的docker image是否已經存在,如果存在就不執行后續編譯打包的stage。在jenkins的發布任務中會調用打包job,避免了重復打包鏡像,這樣就大大的加快了發布速度。

數據庫Schema升級

數據庫的升級用的是flyway,打包成docker鏡像后,在openshift中創建job去執行數據庫升級。job可以用最簡單的命令行的方式去創建:

oc run upgrade-foo --image=upgrade/production --replicas=1 --restart=OnFailure --command -- java -jar -Dprofile=production /app/upgrade-foo.jar

腳本升級任務也集成在jenkins中。

容器發布

openshift有個特別概念叫DeploymentConfig,原生k8s Deployment與之相似,但openshift的DeploymentConfig功能更多些。

Deploymentconfig關聯了一個叫做ImageStreamTag的東西,而這個ImagesStreamTag和實際的鏡像地址做關聯,當ImageStreamTag關聯的鏡像地址發生了變更,就會觸發相應的DeploymentConfig重新部署。我們發布是使用了jenkins+openshift插件,只需要將項目對應的ImageStreamTag指向到新生成的鏡像上,就觸發了部署。

如果是服務升級,已經有容器在運行怎么實現平滑替換而不影響業務呢?

配置Pod的健康檢查,Health Check只配置了ReadinessProbe,沒有用LivenessProbe。因為LivenessProbe在健康檢查失敗之后,會將故障的pod直接干掉,故障現場沒有保留,不利于問題的排查定位。而ReadinessProbe只會將故障的pod從service中踢除,不接受流量。使用了ReadinessProbe后,可以實現滾動升級不中斷業務,只有當pod健康檢查成功之后,關聯的service才會轉發流量請求給新升級的pod,并銷毀舊的pod。

readinessProbe:
failureThreshold: 4
httpGet:
path: /actuator/metrics
port: 8090
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 15
successThreshold: 2
timeoutSeconds: 2

線上運維的挑戰

服務間調用

Spring Cloud使用eruka接受服務注冊請求,并在內存中維護服務列表。當一個服務作為客戶端發起跨服務調用時,會先獲取服務提供者列表,再通過某種負載均衡算法取得具體的服務提供者地址(ip + port),即所謂的客戶端服務發現。在本地開發環境中我們使用這種方式。

由于Openshift天然就提供服務端服務發現,即service模塊,客戶端無需關注服務發現具體細節,只需知道服務的域名就可以發起調用。由于我們有nodejs應用,在實現eureka的注冊和去注冊的過程中都遇到過一些問題,不能達到生產級別。所以決定直接使用service方式替換掉eureka,也為以后采用service mesh做好鋪墊。具體的做法是,配置環境變量EUREKA_CLIENT_ENABLED=false,RIBBON_EUREKA_ENABLED=false,并將服務列表如 FOO_RIBBON_LISTOFSERVERS: '[http://foo:8080](http://foo:8080/)' 寫進configmap中,以envFrom: configMapRef方式獲取環境變量列表。

如果一個服務需要暴露到外部怎么辦,比如暴露前端的html文件或者服務端的gateway。

Openshift內置的haproxy router,相當于k8s的ingress,直接在Openshift的web界面里面就可以很方便的配置。我們將前端的資源也作為一個Pod并有對應的Service,當請求進入haproxy符合規則就會轉發到ui所在的Service。router支持A/B test等功能,唯一的遺憾是還不支持url rewrite。

對于需要url rewrite的場景怎么辦?那么就直接將nginx也作為一個服務,再做一層轉發。流程變成 router → nginx pod → 具體提供服務的pod。

鏈路跟蹤

開源的全鏈路跟蹤很多,比如spring cloud sleuth + zipkin,國內有美團的CAT等等。其目的就是當一個請求經過多個服務時,可以通過一個固定值獲取整條請求鏈路的行為日志,基于此可以再進行耗時分析等,衍生出一些性能診斷的功能。不過對于我們而言,首要目的就是trouble shooting,出了問題需要快速定位異常出現在什么服務,整個請求的鏈路是怎樣的。

為了讓解決方案輕量,我們在日志中打印RequestId以及TraceId來標記鏈路。RequestId在gateway生成表示唯一一次請求,TraceId相當于二級路徑,一開始與RequestId一樣,但進入線程池或者消息隊列后,TraceId會增加標記來標識唯一條路徑。舉個例子,當一次請求會向MQ發送一個消息,那么這個消息可能會被多個消費者消費,此時每個消費線程都會自己生成一個TraceId來標記消費鏈路。加入TraceId的目的就是為了避免只用RequestId過濾出太多日志。

實現上,通過ThreadLocal存放APIRequestContext串聯單服務內的所有調用,當跨服務調用時,將APIRequestContext信息轉化為Http Header,被調用方獲取到Http Header后再次構建APIRequestContext放入ThreadLocal,重復循環保證RequestId和TraceId不丟失即可。如果進入MQ,那么APIRequestContext信息轉化為Message Header即可(基于Rabbitmq實現)。

當日志匯總到日志系統后,如果出現問題,只需要捕獲發生異常的RequestId或是TraceId即可進行問題定位。

經過一年來的使用,基本可以滿足絕大多數trouble shooting的場景,一般半小時內即可定位到具體業務。

容器監控

容器化前監控用的是telegraf探針,容器化后用的是prometheus,直接安裝了openshift自帶的cluster-monitoring-operator。自帶的監控項目已經比較全面,包括node,pod資源的監控,在新增node后也會自動添加進來。

Java項目也添加了prometheus的監控端點,只是可惜cluster-monitoring-operator提供的配置是只讀的,后期將研究怎么將java的jvm監控這些整合進來。

MORE

開源軟件是對中小團隊的一種福音,無論是Spring Cloud還是k8s都大大降低了團隊在基礎設施建設上的時間成本。當然其中有更多的話題,比如服務升降級,限流熔斷,分布式任務調度,灰度發布,功能開關等等都需要更多時間來探討。對于小團隊,要根據自身情況選擇微服務的技術方案,不可一味追新,適合自己的才是最好的。

作者簡介:徐鵬, Linkflow運維開發負責人

聲明:本文為作者投稿,版權歸作者個人所有。

【END】

總結

以上是生活随笔為你收集整理的java 拉起服务_技术开发者应该如何构建小团队的微服务方案?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。