<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          哦,原來(lái)大廠(chǎng)是這樣發(fā)布應(yīng)用的!

          共 4523字,需瀏覽 10分鐘

           ·

          2022-01-22 14:59

          大家好,我是魚(yú)皮,今天我們來(lái)討論一個(gè)話(huà)題:一個(gè)項(xiàng)目上下線(xiàn)的正確姿勢(shì),由【碼?!坷蠋熤髦v??赡軙?huì)出現(xiàn)很多 “新鮮” 的名詞,大家慢慢消化~

          稍微正規(guī)一點(diǎn)的公司都會(huì)有自動(dòng)化上下線(xiàn)流程,因?yàn)樯舷戮€(xiàn)看起來(lái)簡(jiǎn)單,只有兩步,「停掉應(yīng)用」,「重啟應(yīng)用」,但里面其實(shí)還是有挺多門(mén)道的,比如:

          • 1. 如何優(yōu)雅地上下線(xiàn), 涉及到 dubbo 的優(yōu)雅停機(jī),服務(wù)上線(xiàn)時(shí)的 JVM 參數(shù)配置等

          • 2. 如何保證應(yīng)用發(fā)布上線(xiàn)發(fā)現(xiàn)問(wèn)題后快速回滾,或者上線(xiàn)后將新功能可能帶來(lái)的影響降至最小

          所以這套流程必須自動(dòng)化,以下我們就以 SpringBoot 工程部署為例來(lái)對(duì)優(yōu)雅的發(fā)布流程一探究竟

          先來(lái)看第一個(gè)問(wèn)題:

          如何優(yōu)雅上下線(xiàn)

          這里面涉及到兩個(gè)方面

          1. 如何優(yōu)雅的下線(xiàn)線(xiàn)上正在運(yùn)行的服務(wù)

          2. 如何優(yōu)雅上線(xiàn)將要發(fā)布的服務(wù)

          先來(lái)看第一個(gè)問(wèn)題

          如何優(yōu)雅停機(jī)

          目前業(yè)界在微服務(wù)架構(gòu)上大多使用了 dubbo ,我們的工程也不例外。

          我們知道 consumer 是通過(guò) registry 來(lái)感知到 provider 存在的,現(xiàn)在要將 provider 下線(xiàn)自然也要通過(guò) registry 來(lái)通知 consumer

          注冊(cè)中心一般為 ZK 或者 nacos,所以第一步,我們首先要讓服務(wù)提供者調(diào)用 unregister 以刪除其在注冊(cè)中心上的臨時(shí)節(jié)點(diǎn),這樣消費(fèi)者由于一直監(jiān)聽(tīng)此臨時(shí)節(jié)點(diǎn),所以能感知到,于是消費(fèi)者就不會(huì)再向此即將下線(xiàn)的提供者發(fā)起調(diào)用,但此時(shí)就能立刻停掉提供者的進(jìn)程了嗎?不能,因?yàn)橛锌赡芴峁┱哌€在執(zhí)行消費(fèi)者發(fā)起的請(qǐng)求,如果此時(shí)停掉很可能中斷正在執(zhí)行的請(qǐng)求導(dǎo)致報(bào)錯(cuò),所以我們還需要等待 10 s (一般 10s 足以處理完相關(guān)的請(qǐng)求)左右讓服務(wù)提供者把任務(wù)處理完成,然后就可以停掉當(dāng)前服務(wù)了

          可能有人會(huì)說(shuō)你這不是說(shuō)的 dubbo 的優(yōu)雅停機(jī)嗎,發(fā)起 kill 后讓 dubbo 優(yōu)雅停機(jī)停機(jī)即可,何必多此一舉呢?

          沒(méi)錯(cuò),理論上直接 kill 確實(shí)可以依賴(lài) dubbo 的優(yōu)雅停機(jī)做一些收尾的工作,但實(shí)際上在我們的下線(xiàn)腳本中,依然是手動(dòng)執(zhí)行了 unregister 并指定了 sleep 10s 然后才 kill 服務(wù)進(jìn)程,為什么呢,因?yàn)樵?dubbo 的 2.5.x 和 2.6.x 版本中優(yōu)雅停機(jī)其實(shí)存在一定的瑕疵及需要滿(mǎn)足一定的使用條件,在 2.7 版本中才算相對(duì)完美地實(shí)現(xiàn)了優(yōu)雅停機(jī)方案,而我們很長(zhǎng)一段時(shí)間使用的都是 2.6.x 的版本,所以我們相當(dāng)于前置了 dubbo 優(yōu)雅停機(jī)的一些工作以讓下線(xiàn)更可靠一些

          在執(zhí)行完 unregister 并 sleep 10s 后此時(shí)我們就可以「kill 服務(wù)進(jìn)程id」了,注意是 kill(-15) 而不是 kill -9,使用 kill -9 會(huì)立刻殺死 JVM 進(jìn)程,但實(shí)際上在關(guān)閉 JVM 進(jìn)程前,需要清理文件,網(wǎng)絡(luò)套接字等資源,所以使用 kill 會(huì)更合適,這樣的話(huà) JVM 就能接收到 kill 信號(hào),通過(guò) shutdown hook 就能做些系統(tǒng)資源清理方面的工作(dubbo 的優(yōu)雅停機(jī)也是依賴(lài)這個(gè)原理)了,如下

          當(dāng)執(zhí)行 kill 后,我們每隔一秒檢查一下 JVM 進(jìn)程是否還存活,共檢測(cè) 10 次,一共 10s

          畫(huà)外音:檢測(cè) 10s 足夠了,加上之前的 10s,總共有 20s 的時(shí)候讓服務(wù)提供者來(lái)執(zhí)行任務(wù)和清理資源,另外 dubbo 的優(yōu)雅停機(jī)默認(rèn)超時(shí)時(shí)間為 10s,超時(shí)則會(huì)強(qiáng)制關(guān)閉,所以 20s 理論上足夠了

          10s 后如果發(fā)現(xiàn)進(jìn)程還在,那此時(shí)就要祭出大招 kill -9 直接殺死進(jìn)程了,這種情況下直接殺死進(jìn)程是沒(méi)有問(wèn)題的,因?yàn)榇藭r(shí)服務(wù)已經(jīng)被摘除 20s 了,基本上可以認(rèn)為不會(huì)影響線(xiàn)上運(yùn)行。

          簡(jiǎn)單總結(jié)一下,服務(wù)下線(xiàn)流程如下

          經(jīng)過(guò)以上步驟我們才算做到了優(yōu)雅停機(jī),接下來(lái)我們?cè)倏纯慈绾蝺?yōu)雅地上線(xiàn)

          正確的上線(xiàn)姿勢(shì)

          可能有人會(huì)說(shuō)上線(xiàn)還不簡(jiǎn)單,通過(guò)以下形式來(lái)啟動(dòng) SpringBoot 不就完了

          java?-jar?jar包路徑?--spring.config.location=xxx?--spring.pid.file=xxx

          如果在業(yè)務(wù)剛起步階段這樣設(shè)置確實(shí)沒(méi)有問(wèn)題,畢竟本身也沒(méi)啥業(yè)務(wù)量,但如果你們的業(yè)務(wù)量上升到一定規(guī)模后這樣簡(jiǎn)單的啟動(dòng)是不行的,不然動(dòng)不動(dòng)就 YGC/FullGC 或者 ?OOM 了沒(méi)有日志咋辦,所以你需要根據(jù)你的業(yè)務(wù)量來(lái)壓測(cè),設(shè)置類(lèi)似如下的 JVM 的參數(shù)

          -server?-Xmx5g?-Xms5g?-Xmn2g?-XX:MetaspaceSize=256m?-XX:MaxMetaspaceSize=512m?-Xss256k?-XX:SurvivorRatio=8?\
          -XX:+UseParNewGC??-XX:+UseConcMarkSweepGC?-XX:CMSInitiatingOccupancyFraction=70?\
          -XX:+CMSParallelRemarkEnabled?-XX:+UseCMSCompactAtFullCollection?-XX:+UseFastAccessorMethods?-XX:+UseCMSInitiatingOccupancyOnly?-XX:+HeapDumpOnOutOfMemoryError?-XX:HeapDumpPath=${APPLICATION_LOG_DIR}?-Djava.security.egd=file:/dev/./urandom

          注意上面的參數(shù)中有個(gè)?-Djava.security.egd=file:/dev/./urandom?,這個(gè)是干啥用的呢?

          在工程中很可能會(huì)有使用隨機(jī)數(shù)的場(chǎng)景,SecureRandom 在 java 各種組件中使用廣泛,可以可靠的產(chǎn)生隨機(jī)數(shù),但大量產(chǎn)生隨機(jī)數(shù)據(jù)的時(shí)候,性能會(huì)降低,所以我們上面這個(gè)設(shè)置將會(huì)加快隨機(jī)數(shù)的產(chǎn)生過(guò)程。

          光設(shè)置 JVM 參數(shù)還不夠,你總要監(jiān)控你的應(yīng)用是否健康吧,這需要采集你機(jī)器的相關(guān)指標(biāo)以便以可視化的形式展現(xiàn)出來(lái),如下


          所以你需要安裝探針,我們用的 Skywalking,這樣就需要以 Java agent 的形式來(lái)啟動(dòng),如下

          -javaagent:$SW_AGENT_JAR?-Dskywalking_config=$SW_AGENT_CONFIG

          綜上,Java 的啟動(dòng)參數(shù)配置如下

          java?-jar?jar包路徑?--spring.config.location=xxx?--spring.pid.file=xxx?-server?-Xmx5g?-Xms5g?-Xmn2g?-XX:MetaspaceSize=256m?-XX:MaxMetaspaceSize=512m?-Xss256k?-XX:SurvivorRatio=8?\
          -XX:+UseParNewGC??-XX:+UseConcMarkSweepGC?-XX:CMSInitiatingOccupancyFraction=70?\
          -XX:+CMSParallelRemarkEnabled?-XX:+UseCMSCompactAtFullCollection?-XX:+UseFastAccessorMethods?-XX:+UseCMSInitiatingOccupancyOnly?-XX:+HeapDumpOnOutOfMemoryError?-XX:HeapDumpPath=${APPLICATION_LOG_DIR}?-Djava.security.egd=file:/dev/./urandom?-javaagent:$SW_AGENT_JAR?-Dskywalking_config=$SW_AGENT_CONFIG

          配置好之后終于可以啟動(dòng)了,項(xiàng)目大了后啟動(dòng)一般比較慢,所以我們可以等個(gè) 20s 然后再檢測(cè)是否啟動(dòng)成功,如果不成功通過(guò)告警的形式提醒開(kāi)發(fā)人員,但如果成功了的話(huà)你就可以放心上線(xiàn)了?非也,你還需要做健康檢查,檢測(cè) db 連接,redis 等是否真正可用,一般情況下, 項(xiàng)目都會(huì)有如下健康檢查邏輯

          @Service(protocol?=?{"rest"})
          public?class?HealthCheckServiceImpl?implements?HealthCheckService?{

          ????@Resource
          ????private?TestDAO?TestDAO;

          ????@Override
          ????public?String?getHealthStatus()?{
          ????????????List?testDOS?=
          ????????????????????TestDAO.getResult(123);
          ????????????Assert.isTrue(testDOS?!=?null,?"dao?有問(wèn)題?null");
          ????????????//?redis?檢測(cè)

          ????????????//?此處省略其它檢測(cè)

          ????????????return?"health";
          ????}
          }

          這樣 JVM 啟動(dòng)后腳本通過(guò)調(diào)用 curl http://ip:port/service/health/deepCheck 來(lái)判斷服務(wù)是否真正上線(xiàn)了,結(jié)果返回 「health」 才說(shuō)明服務(wù)真正可用了

          滾動(dòng)發(fā)布與藍(lán)綠發(fā)布

          接下來(lái)我們來(lái)看看業(yè)務(wù)普遍采用的兩種發(fā)布模式:滾動(dòng)發(fā)布和藍(lán)綠發(fā)布

          什么是滾動(dòng)發(fā)布

          滾動(dòng)發(fā)布:一般是取出一個(gè)或者多個(gè)服務(wù)器停止服務(wù),執(zhí)行更新,并重新將其投入使用。周而復(fù)始,直到集群中所有的實(shí)例都更新成新版本,一圖勝千言

          滾動(dòng)發(fā)布應(yīng)該是業(yè)界普遍采用的方案了,這種方案簡(jiǎn)單,但是如果一旦發(fā)現(xiàn)問(wèn)題要回滾就麻煩了,得把服務(wù)一臺(tái)臺(tái)停掉并啟用老的包,影響時(shí)間會(huì)比較長(zhǎng),于是人們又提出了藍(lán)綠部署

          什么是藍(lán)綠部署

          為了解決滾動(dòng)發(fā)布回滾慢的問(wèn)題,人們提出了藍(lán)綠發(fā)布,首先把新包部署到新集群上,待新集群部署成功后,在網(wǎng)關(guān)基于 dubbo 路由來(lái)將流量打到新集群

          這樣的話(huà)如果一旦發(fā)現(xiàn)新功能有問(wèn)題,網(wǎng)關(guān)可以根據(jù) tag 馬上將流量切回到老集群,相當(dāng)于實(shí)時(shí)回滾,用起來(lái)確實(shí)給力,唯一的缺點(diǎn)也是很明顯的,費(fèi)錢(qián)!因?yàn)橐獪?zhǔn)備和原集群一樣多的機(jī)器,所以適合土豪玩家,我們集團(tuán)曾經(jīng)搞過(guò),后來(lái)現(xiàn)金流緊張,把這玩意給停了

          以上就是發(fā)布服務(wù)上下線(xiàn)需要注意的一些點(diǎn),雖然本文發(fā)布是以 Java 項(xiàng)目為例,但其實(shí)其他項(xiàng)目發(fā)布注意的點(diǎn)也是大同小異的,無(wú)非就是兩點(diǎn)

          • 1 是注意下線(xiàn)時(shí)的優(yōu)雅停機(jī),預(yù)留足夠多的時(shí)候來(lái)讓服務(wù)做些資源清理的工作

          • 2 是發(fā)布上線(xiàn)時(shí)需要根據(jù)你的業(yè)務(wù)量提前做壓測(cè),做好監(jiān)控相關(guān)的工作以便提升服務(wù)的可用性

          ··············? END? ··············

          往期推薦

          迷的一批,上線(xiàn)了新功能,老功能就廢了!

          網(wǎng)站又被攻擊,我心態(tài)崩了

          絕了,小白都能用的反編譯神器!

          這個(gè) Bug,給我整得一愣一愣!

          2分鐘,我把網(wǎng)站性能優(yōu)化了3倍!

          瀏覽 46
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  婷婷伊人綜合中文字幕小说 | 黄色一级视频免费领 | 免费又色又爽又黄的成人用品 | 殴美肏屄视频免费看 | 激情五月色播五月 |