<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>

          40張圖看懂分布式追蹤系統(tǒng)

          共 8613字,需瀏覽 18分鐘

           ·

          2024-04-11 18:34

          前言

          在微服務(wù)架構(gòu)中,一次請求往往涉及到多個模塊,多個中間件,多臺機器的相互協(xié)作才能完成。這一系列調(diào)用請求中,有些是串行的,有些是并行的,那么如何確定這個請求背后調(diào)用了哪些應(yīng)用,哪些模塊,哪些節(jié)點及調(diào)用的先后順序?如何定位每個模塊的性能問題?本文將為你揭曉答案。

          本文將會從以下幾個方面來闡述

          • 分布式追蹤系統(tǒng)原理及作用
          • SkyWalking的原理及架構(gòu)設(shè)計
          • 我司在分布式調(diào)用鏈上的實踐

          分布式追蹤系統(tǒng)的原理及作用

          如何衡量一個接口的性能好壞,一般我們至少會關(guān)注以下三個指標(biāo)

          • 接口的 RT 你怎么知道?
          • 是否有異常響應(yīng)?
          • 主要慢在哪里?

          單體架構(gòu)

          在初期,公司剛起步的時候,可能多會采用如下單體架構(gòu),對于單體架構(gòu)我們該用什么方式來計算以上三個指標(biāo)呢?

          616c42a25c37b18f984948bda9169c88.webp

          最容易想到的顯然是用 AOP

          75e6787a23a9a7f8fc762b5d485f87f0.webp使用 AOP 在調(diào)用具體的業(yè)務(wù)邏輯前后分別打印一下時間即可計算出整體的調(diào)用時間,使用 AOP 來 catch 住異常也可知道是哪里的調(diào)用導(dǎo)致的異常。

          微服務(wù)架構(gòu)

          在單體架構(gòu)中由于所有的服務(wù),組件都在一臺機器上,所以相對來說這些監(jiān)控指標(biāo)比較容易實現(xiàn),不過隨著業(yè)務(wù)的快速發(fā)展,單體架構(gòu)必然會朝微服務(wù)架構(gòu)發(fā)展,如下

          d675f2c6704dae2076aad12dbbce917f.webp如圖示:一個稍微復(fù)雜的微服務(wù)架構(gòu)

          如果有用戶反饋某個頁面很慢,我們知道這個頁面的請求調(diào)用鏈?zhǔn)?A ----->  C ----->  B ----->  D,此時如何定位可能是哪個模塊引起的問題。每個服務(wù) Service A,B,C,D 都有好幾臺機器。怎么知道某個請求調(diào)用了服務(wù)的具體哪臺機器呢?

          f019545547265b8a73eeadb29ca3285f.webp 可以明顯看到,由于無法準(zhǔn)確定位每個請求經(jīng)過的確切路徑,在微服務(wù)這種架構(gòu)下有以下幾個痛點
          1. 排查問題難度大,周期長
          2. 特定場景難復(fù)現(xiàn)
          3. 系統(tǒng)性能瓶頸分析較難

          分布式調(diào)用鏈就是為了解決以上幾個問題而生,它主要的作用如下

          • 自動采取數(shù)據(jù)  
          • 分析數(shù)據(jù)產(chǎn)生完整調(diào)用鏈:有了請求的完整調(diào)用鏈,問題有很大概率可復(fù)現(xiàn)
          • 數(shù)據(jù)可視化:每個組件的性能可視化,能幫助我們很好地定位系統(tǒng)的瓶頸,及時找出問題所在

          通過分布式追蹤系統(tǒng)能很好地定位如下請求的每條具體請求鏈路,從而輕易地實現(xiàn)請求鏈路追蹤,每個模塊的性能瓶頸定位與分析。

          34118ed030b4e3c93629f04bc2f50467.webp


          分布式調(diào)用鏈標(biāo)準(zhǔn) - OpenTracing

          知道了分布式調(diào)用鏈的作用,那我們來看下如何實現(xiàn)分布式調(diào)用鏈的實現(xiàn)及原理, 首先為了解決不同的分布式追蹤系統(tǒng) API 不兼容的問題,誕生了 OpenTracing 規(guī)范,OpenTracing 是一個輕量級的標(biāo)準(zhǔn)化層,它位于應(yīng)用程序/類庫和追蹤或日志分析程序之間。

          820f56abd7d273cc677f058abeba0b59.webp這樣 OpenTracing 通過提供平臺無關(guān),廠商無關(guān)的 API,使得開發(fā)人員能夠方便地添加追蹤系統(tǒng)的實現(xiàn)。

          說到這大家是否想過 Java 中類似的實現(xiàn)?還記得 JDBC 吧,通過提供一套標(biāo)準(zhǔn)的接口讓各個廠商去實現(xiàn),程序員即可面對接口編程,不用關(guān)心具體的實現(xiàn)。這里的接口其實就是標(biāo)準(zhǔn),所以制定一套標(biāo)準(zhǔn)非常重要,可以實現(xiàn)組件的可插拔。

          e3fa1a9977c372f305a42cf475bfc604.webp

          接下來我們來看 OpenTracing 的數(shù)據(jù)模型,主要有以下三個

          • Trace:一個完整請求鏈路
          • Span:一次調(diào)用過程(需要有開始時間和結(jié)束時間)
          • SpanContext:Trace 的全局上下文信息, 如里面有traceId

          理解這三個概念非常重要,為了讓大家更好地理解這三個概念,我特意畫了一張圖9868f7e6a1cf0ba95458f31da65bee2a.webp

          如圖示,一次下單的完整請求完整就是一個 Trace, 顯然對于這個請求來說,必須要有一個全局標(biāo)識來標(biāo)識這一個請求,每一次調(diào)用就稱為一個 Span,每一次調(diào)用都要帶上全局的 TraceId, 這樣才可把全局 TraceId 與每個調(diào)用關(guān)聯(lián)起來,這個 TraceId 就是通過 SpanContext 傳輸?shù)模热灰獋鬏旓@然都要遵循協(xié)議來調(diào)用。如圖示,我們把傳輸協(xié)議比作車,把 SpanContext 比作貨,把 Span 比作路應(yīng)該會更好理解一些。

          理解了這三個概念,接下來我看看分布式追蹤系統(tǒng)如何采集統(tǒng)一圖中的微服務(wù)調(diào)用鏈

          3ac8eb25a873945b5d6cf2268b05818e.webp

          我們可以看到底層有一個 Collector 一直在默默無聞地收集數(shù)據(jù),那么每一次調(diào)用 Collector 會收集哪些信息呢。

          1. 全局 trace_id:這是顯然的,這樣才能把每一個子調(diào)用與最初的請求關(guān)聯(lián)起來
          2. span_id: 圖中的 0,1,1.1,2,這樣就能標(biāo)識是哪一個調(diào)用
          3. parent_span_id:比如 b 調(diào)用 d 的  span_id 是 1.1,那么它的 parent_span_id 即為 a 調(diào)用 b 的 span_id 即 1,這樣才能把兩個緊鄰的調(diào)用關(guān)聯(lián)起來。

          有了這些信息,Collector 收集的每次調(diào)用的信息如下

          18c09114314470f03b025a6d9025459f.webp

          根據(jù)這些圖表信息顯然可以據(jù)此來畫出調(diào)用鏈的可視化視圖如下

          a64ca9ffd4afd3cc042c39080163c641.webp

          于是一個完整的分布式追蹤系統(tǒng)就實現(xiàn)了。

          以上實現(xiàn)看起來確實簡單,但有以下幾個問題需要我們仔細(xì)思考一下

          1. 怎么自動采集 span 數(shù)據(jù):自動采集,對業(yè)務(wù)代碼無侵入
          2. 如何跨進(jìn)程傳遞 context
          3. traceId 如何保證全局唯一
          4. 請求量這么多采集會不會影響性能

          接下我來看看 SkyWalking 是如何解決以上四個問題的

          如果想學(xué)Java項目的,強烈推薦我的??項目消息推送平臺Austin10K stars),可以用作畢業(yè)設(shè)計,可以用作校招,可以看看生產(chǎn)環(huán)境是怎么推送消息的。 

          倉庫地址(可點擊閱讀原文跳轉(zhuǎn)):https://gitee.com/zhongfucheng/austin

          SkyWalking的原理及架構(gòu)設(shè)計

          怎么自動采集 span 數(shù)據(jù)

          SkyWalking 采用了插件化 + javaagent 的形式來實現(xiàn)了 span 數(shù)據(jù)的自動采集,這樣可以做到對代碼的 無侵入性,插件化意味著可插拔,擴(kuò)展性好(后文會介紹如何定義自己的插件)

          ba5670695b2e9b3723b2bdaf4f3a22bf.webp


          如何跨進(jìn)程傳遞 context

          我們知道數(shù)據(jù)一般分為 header 和 body, 就像 http 有 header 和 body, RocketMQ 也有 MessageHeader,Message Body, body 一般放著業(yè)務(wù)數(shù)據(jù),所以不宜在 body 中傳遞 context,應(yīng)該在 header 中傳遞 context,如圖示

          c229ba527ce767d8768f3e180c55163d.webpdubbo 中的 attachment 就相當(dāng)于 header ,所以我們把 context 放在 attachment 中,這樣就解決了 context 的傳遞問題。
          e3550805f55bc1a57c2fad12c7104b18.webp 小提示:這里的傳遞 context 流程均是在 dubbo plugin 處理的,業(yè)務(wù)無感知,這個 plugin 是怎么實現(xiàn)的呢,下文會分析

          traceId 如何保證全局唯一

          要保證全局唯一 ,我們可以采用分布式或者本地生成的 ID,使用分布式話需要有一個發(fā)號器,每次請求都要先請求一下發(fā)號器,會有一次網(wǎng)絡(luò)調(diào)用的開銷,所以 SkyWalking 最終采用了本地生成 ID 的方式,它采用了大名鼎鼎的 snowflow 算法,性能很高。

          4fafac50786fd133c819db1cc4ba2f9e.webp


          圖示: snowflake 算法生成的 id

          不過 snowflake 算法有一個眾所周知的問題:時間回?fù)?/strong>,這個問題可能會導(dǎo)致生成的 id 重復(fù)。那么 SkyWalking 是如何解決時間回?fù)軉栴}的呢。

          0d3464fcf9990bce3a0ab8b7f126ba4d.webp每生成一個 id,都會記錄一下生成 id 的時間(lastTimestamp),如果發(fā)現(xiàn)當(dāng)前時間比上一次生成 id 的時間(lastTimestamp)還小,那說明發(fā)生了時間回?fù)埽藭r會生成一個隨機數(shù)來作為 traceId。 這里可能就有同學(xué)要較真了,可能會覺得生成的這個隨機數(shù)也會和已生成的全局 id 重復(fù),是否再加一層校驗會好點。

          這里要說一下系統(tǒng)設(shè)計上的方案取舍問題了,首先如果針對產(chǎn)生的這個隨機數(shù)作唯一性校驗無疑會多一層調(diào)用,會有一定的性能損耗,但其實時間回?fù)馨l(fā)生的概率很小(發(fā)生之后由于機器時間紊亂,業(yè)務(wù)會受到很大影響,所以機器時間的調(diào)整必然要慎之又慎),再加上生成的隨機數(shù)重合的概率也很小,綜合考慮這里確實沒有必要再加一層全局惟一性校驗。對于技術(shù)方案的選型,一定要避免過度設(shè)計,過猶不及。

          請求量這么多,全部采集會不會影響性能?

          如果對每個請求調(diào)用都采集,那毫無疑問數(shù)據(jù)量會非常大,但反過來想一下,是否真的有必要對每個請求都采集呢,其實沒有必要,我們可以設(shè)置采樣頻率,只采樣部分?jǐn)?shù)據(jù),SkyWalking 默認(rèn)設(shè)置了 3 秒采樣 3 次,其余請求不采樣,如圖示

          6db1a9e6cb8b8624645a0ab151e20f87.webp這樣的采樣頻率其實足夠我們分析組件的性能了,按 3 秒采樣 3 次這樣的頻率來采樣數(shù)據(jù)會有啥問題呢。理想情況下,每個服務(wù)調(diào)用都在同一個時間點(如下圖示)這樣的話每次都在同一時間點采樣確實沒問題 643961ead8b7d6d6a099876a028188cd.webp但在生產(chǎn)上,每次服務(wù)調(diào)用基本不可能都在同一時間點調(diào)用,因為期間有網(wǎng)絡(luò)調(diào)用延時等,實際調(diào)用情況很可能是下圖這樣

          c9b608a3f2e920121b502aaf8835b8b6.webp這樣的話就會導(dǎo)致某些調(diào)用在服務(wù) A 上被采樣了,在服務(wù) B,C 上不被采樣,也就沒法分析調(diào)用鏈的性能,那么 SkyWalking 是如何解決的呢。

          它是這樣解決的:如果上游有攜帶 Context 過來(說明上游采樣了),則下游強制采集數(shù)據(jù)。這樣可以保證鏈路完整。

          SkyWalking 的基礎(chǔ)架構(gòu)

          SkyWalking 的基礎(chǔ)如下架構(gòu),可以說幾乎所有的的分布式調(diào)用都是由以下幾個組件組成的

          b1ca34d8da6b5c8c224ead26725afa71.webp首先當(dāng)然是節(jié)點數(shù)據(jù)的定時采樣,采樣后將數(shù)據(jù)定時上報,將其存儲到 ES, MySQL 等持久化層,有了數(shù)據(jù)自然而然可根據(jù)數(shù)據(jù)做可視化分析。


          SkyWalking 的性能如何

          接下來大家肯定比較關(guān)心 SkyWalking 的性能,那我們來看下官方的測評數(shù)據(jù)

          8ed65dff076ee700c581eed9d17927b5.webp

          圖中藍(lán)色代表未使用 SkyWalking 的表現(xiàn),橙色代表使用了 SkyWalking 的表現(xiàn),以上是在 TPS 為 5000 的情況下測出的數(shù)據(jù),可以看出,不論是 CPU,內(nèi)存,還是響應(yīng)時間,使用 SkyWalking 帶來的性能損耗幾乎可以忽略不計。

          接下來我們再來看 SkyWalking 與另一款業(yè)界比較知名的分布式追蹤工具 Zipkin, Pinpoint 的對比(在采樣率為 1 秒 1 個,線程數(shù) 500,請求總數(shù)為 5000 的情況下做的對比),可以看到在關(guān)鍵的響應(yīng)時間上, Zipkin(117ms),PinPoint(201ms)遠(yuǎn)遜色于 SkyWalking(22ms)!1b20618032b423c7c9fe15045535ab1f.webp

          從性能損耗這個指標(biāo)上看,SkyWalking 完勝!

          再看下另一個指標(biāo):對代碼的侵入性如何,ZipKin 是需要在應(yīng)用程序中埋點的,對代碼的侵入強,而 SkyWalking 采用 javaagent + 插件化這種修改字節(jié)碼的方式可以做到對代碼無任何侵入,除了性能和對代碼的侵入性上 SkyWaking 表現(xiàn)不錯外,它還有以下優(yōu)勢幾個優(yōu)勢

          • 對多語言的支持,組件豐富:目前其支持 Java, .Net Core, PHP, NodeJS, Golang, LUA 語言,組件上也支持dubbo, mysql 等常見組件,大部分能滿足我們的需求。

          • 擴(kuò)展性:對于不滿足的插件,我們按照 SkyWalking 的規(guī)則手動寫一個即可,新實現(xiàn)的插件對代碼無入侵。

          我司在分布式調(diào)用鏈上的實踐

          SkyWalking 在我司的應(yīng)用架構(gòu)

          由上文可知 SkyWalking 有很多優(yōu)點,那么是不是我們用了它的全部組件了呢,其實不然,來看下其在我司的應(yīng)用架構(gòu)

          961c89f47552e51769a1b9edd6efb112.webp

          從圖中可以看出我們只采用了 SkyWalking 的 agent 來進(jìn)行采樣,放棄了另外的「數(shù)據(jù)上報及分析」,「數(shù)據(jù)存儲」,「數(shù)據(jù)可視化」三大組件,那為啥不直接采用 SkyWalking 的整套解決方案呢,因為在接入 SkyWalking 之前我們的 Marvin 監(jiān)控生態(tài)體系已經(jīng)相對比較完善了,如果把其整個替換成  SkyWalking,一來沒有必要,Marvin 在大多數(shù)場景下都能滿足我們的需求,二來系統(tǒng)替換成本高,三來如果重新接入用戶學(xué)習(xí)成本很高。

          這也給我們一個啟示:任何產(chǎn)品搶占先機很重要,后續(xù)產(chǎn)品的替換成本會很高,搶占先機,也就是搶占了用戶的心智,這就像微信雖然 UI,功能上制作精良,但在國外照樣干不過 Whatsapp 一樣,因為先機已經(jīng)沒了。

          從另一方面來看,對架構(gòu)來說,沒有最好的,最有最合適的,結(jié)合當(dāng)前業(yè)務(wù)場景去平衡折中才是架構(gòu)設(shè)計的本質(zhì)

          我司對 SkyWalking 作了哪些改造和實踐

          我司主要作了以下改造和實踐

          1. 預(yù)發(fā)環(huán)境由于調(diào)試需要強制采樣
          2. 實現(xiàn)更細(xì)粒度的采樣?
          3. 日志中嵌入traceId
          4. 自研實現(xiàn)了 SkyWalking 插件

          預(yù)發(fā)環(huán)境由于調(diào)試需要強制采樣

          從上文分析可知 Collector 是在后臺定時采樣的,這不挺好的嗎,為啥要實現(xiàn)強制采樣呢。還是為了排查定位問題,有時線上出現(xiàn)問題,我們希望在預(yù)發(fā)上能重現(xiàn),希望能看到這個請求的完整調(diào)用鏈,所以在預(yù)發(fā)上實現(xiàn)強制采樣很有必要。所以我們對 Skywalking 的 dubbo 插件進(jìn)行了改造,實現(xiàn)強制采樣

          我們在請求的 Cookie 上帶上一個類似 force_flag = true 這樣的鍵值對來表示我們希望強制采樣,在網(wǎng)關(guān)收到這個 Cookie 后,就會在 dubbo 的 attachment 里帶上force_flag = true 這個鍵值對,然后 skywalking 的 dubbo 插件就可以據(jù)此來判斷是否是強制采樣了,如果有這個值即強制采樣,如果沒有這個值,則走正常的定時采樣。

          a0eacbd8e685297654baa0fe6a6a1556.webp

          實現(xiàn)更細(xì)粒度的采樣?

          哈叫更細(xì)粒度的采樣。先來看下 skywalking 默認(rèn)的采樣方式 ,即統(tǒng)一采樣

          85d2e223b1d4abaa067b21ed58c7dc37.webp我們知道這種方式默認(rèn)是 3 秒采樣前 3 次,其他請求都丟棄,這樣的話有個問題,假設(shè)在這臺機器上在 3 秒內(nèi)有多個 dubbo,mysql,redis 調(diào)用,但在如果前三次都是 dubbo 調(diào)用的話,其他像 mysql, redis 等調(diào)用就采樣不到了,所以我們對 skywalking 進(jìn)行了改造,實現(xiàn)了分組采樣,如下
          4fbb319d65e8f3e22c2a327b8deeade5.webp就是說 3 秒內(nèi)進(jìn)行 3 次 redis, dubbo, mysql 等的采樣,也就避免了此問題

          日志中如何嵌入traceId?

          輸出日志中嵌入 traceId 便于我們排查問題,所以打出出 traceId 非常有必要,該怎么在日志中嵌入 traceId 呢?我們用的是 log4j,這里就要了解一下 log4j 的插件機制了,log4j 允許我們自定義插件來輸出日志的格式,首先我們需要定義日志的格式,在自定義的日志格式中嵌入 %traceId, 作為占位符,如下

          ad8d93feed0a2bf8dc15b8b10dc81a2d.webp

          然后我們再實現(xiàn)一個 log4j 的插件,如下

          7d5a609a84385f9391dd07232bd6c35a.webp首先 log4j 的插件要定義一個類,這個類要繼承 LogEventPatternConverter 這個類,并且用標(biāo)準(zhǔn) Plugin 將其自身聲明為 Plugin,通過 @ConverterKeys 這個注解指定了要替換的占位符,然后在 format 方法里將其替換掉。這樣在日志中就會出現(xiàn)我們想要的 TraceId ,如下 754f55c27085e3dea727c07d10a11246.webp

          我司自研了哪些 skywalking 插件

          SkyWalking 實現(xiàn)了很多插件,不過未提供 memcached 和 druid 的插件,所以我們根據(jù)其規(guī)范自研了這兩者的插件

          257e8837939bdc436e0aa3902a1e97f2.webp

          插件如何實現(xiàn)呢,可以看到它主要由三個部分組成

          1. 插件定義類: 指定插件的定義類,最終會根據(jù)這里的定義類打包生成 plugin
          2. Instrumentation: 指定切面,切點,要對哪個類的哪個方法進(jìn)行增強
          3. Interceptor,指定步驟 2 中要在方法的前置,后置還是異常中寫增強邏輯

          可能大家看了還是不懂,那我們以 dubbo plugin 來簡單講解一下,我們知道在 dubbo 服務(wù)中,每個請求從 netty 接收到消息,遞交給業(yè)務(wù)線程池處理開始,到真正調(diào)用到業(yè)務(wù)方法結(jié)束,中間經(jīng)過了十幾個 Filter 的處理

          76c8a2ad945b95e4f074f9661ed1febb.webp而 MonitorFilter 可以攔截所有客戶端發(fā)出請求或者服務(wù)端處理請求,所以我們可以對 MonitorFilter 作增強,在其調(diào)用 invoke 方法前,將全局 traceId  注入到其 Invocation 的 attachment 中,這樣就可以確保在請求到達(dá)真正的業(yè)務(wù)邏輯前就已經(jīng)存在全局 traceId。

          所以顯然我們需要在插件中指定我們要增強的類(MonitorFilter),對其方法(invoke)做增強,要對這個方法做哪些增強呢,這就是攔截器(Inteceptor)要做的事,來看看 Dubbo 插件中的 instrumentation(DubboInstrumentation)

          00a44b79b2f3c6b766f67925ada60251.webp

          我們再看看下代碼中描寫的攔截器(Inteceptor)干了什么事,以下列出關(guān)鍵步驟

          abf1f091d72a51e286af56b33916e998.webp

          首先 beforeMethod 代表在執(zhí)行 MonitorFilter 的 invoke 方法前會調(diào)用這里的方法,與之對應(yīng)的是 afterMethod,代表在執(zhí)行 invoke 方法后作增強邏輯。

          其次我們從第 2,3點可以看到,不管是 consumer 還是 provider, 都對其全局 ID 作了相應(yīng)處理,這樣確保到達(dá)真正的業(yè)務(wù)層的時候保證有了此全局 traceid,定義好 Instrumentation 和 Interceptor 后,最后一步就是在 skywalking.def 里指定定義的類

                // skywalking-plugin.def 文件
          dubbo=org.apache.skywalking.apm.plugin.asf.dubbo.DubboInstrumentation

          這樣打包出來的插件就會對 MonitorFilter 的  invoke 方法進(jìn)行增強,在 invoke 方法執(zhí)行前對期 attachment 作注入全局 traceId 等操作,這一切都是靜默的,對代碼無侵入的。

          總結(jié)

          本文由淺入深地介紹了分布式追蹤系統(tǒng)的原理,相信大家對其作用及工作機制有了比較深的理解,特別需要注意的是,引入某項技巧,一定要結(jié)合現(xiàn)有的技術(shù)架構(gòu)作出最合理的選擇,就像 SkyWalking 有四個模塊,我司只采用其 agent 采樣功能一樣,沒有最好的技術(shù),只有最合適的技術(shù),通過此文,相信大家應(yīng)該對 SkyWalking 的實現(xiàn)機制有了比較清晰的認(rèn)識,文中只是介紹了一下 SkyWalking 的插件實現(xiàn)方式,不過其畢竟是工業(yè)級軟件,要了解其博大精深,還要多讀源碼哦。

          Java項目訓(xùn)練營

          我開通了 項目股東服務(wù) ,已經(jīng)有不少消息推送平臺項目股東拿了阿里/vivo等大廠offer了。 我是沒找到網(wǎng)上有跟我提供相同的服務(wù),價格還比我低的

          ??一對一周到的服務(wù): 有很多人的自學(xué)能力和基礎(chǔ)確實不太行,不知道怎么開始學(xué)習(xí),從哪開始看起,學(xué)習(xí)項目的過程中會走很多彎路,很容易就迷茫了。付費最跟自學(xué)最主要的區(qū)別就是我的服務(wù)會更周到。我會告訴你怎么開始學(xué)這個開源項目,哪些是重點需要掌握的,如何利用最短的時間把握整個系統(tǒng)架構(gòu)和編碼的設(shè)計,把時間節(jié)省下來去做其他事情。學(xué)習(xí)經(jīng)驗/路線/簡歷編寫/面試經(jīng)驗知無不言

          ??本地直連遠(yuǎn)程服務(wù): 生產(chǎn)環(huán)境的應(yīng)用系統(tǒng)肯定會依賴各種中間件,我專門買了兩臺服務(wù)器已經(jīng)搭建好必要的環(huán)境??,在本地就可以直接啟動運行體驗和學(xué)習(xí),無須花額外的時間自行搭建調(diào)試。

          ??細(xì)致的文檔&視頻: 巨細(xì)致的語雀文檔11W+ 字,共106個文檔,項目視頻還在持續(xù)制作更新中(20個),不怕你學(xué)不會。

          ??付費社群 優(yōu)質(zhì)的社群里需篩選過濾,學(xué)習(xí)氛圍是很重要的,多跟同輩或前輩聊聊,會少走很多彎路??

          ??清爽干練commit: 專屬股東倉庫,一步一步從零復(fù)現(xiàn)austin,每個commit都帶著文檔&視頻學(xué)習(xí)。

          如果想獲取上面的權(quán)益,可以看看?? Java項目訓(xùn)練營

          瀏覽 64
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  玖玖视频这里只有精品 | 18禁黄网站网址免费入口 | 日韩高清中文字幕 | 美女拍拍视频免费 | 青娱乐成人在线视频 |