Apache Bookkeeper的啟動流程解析

Apache Bookkeeper的啟動流程解析

全局main函數(shù)實現(xiàn)

啟動代碼

位于bookkeeper-server/src/main/java/org/apache/bookkeeper/server/Main.java

public static void main(String[] args) {
        int retCode = doMain(args);
        Runtime.getRuntime().exit(retCode);
    }

    static int doMain(String[] args) {
        ServerConfigurtion conf;
        // 0. parse command line
        try {
            conf = parseCommandLine(args);
        } catch (IllegalArgumentException iae) {
            return ExitCode.INVALID_CONF;
        }

        // 1. building the component stack:
        LifecycleComponent server;
        try {
            server = buildBookieServer(new BookieConfiguration(conf));
        } catch (Exception e) {
            log.error("Failed to build bookie server", e);
            return ExitCode.SERVER_EXCEPTION;
        }

        // 2. start the server
        try {
            ComponentStarter.startComponent(server).get();
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
            // the server is interrupted
            log.info("Bookie server is interrupted. Exiting ...");
        } catch (ExecutionException ee) {
            log.error("Error in bookie shutdown", ee.getCause());
            return ExitCode.SERVER_EXCEPTION;
        }
        return ExitCode.OK;
    }

啟動代碼很簡潔浊洞,且作了簡要注釋,主要啟動流程都封裝在了LifecycleComponent中;

配置解析
  • 目前所有的配置項都可以通過配置文件來設(shè)置,這也是推薦的方式。因此大部分情況下啟動參數(shù)只需要傳一個配置文件的路徑即可;
  • private static ServerConfiguration parseCommandLine(String[] args) 主要是從配置文件里加載各種配置懂诗,最后生成ServerConfiguration`對象,后續(xù)所有配置的讀取和修改都通過這個對象來操作;
服務(wù)構(gòu)建
  • 每個bookie包括若干個子服務(wù),每個子服務(wù)對應(yīng)一個Component, 需要一一啟動和關(guān)閉孵睬,這里使用LifecycleComponent來管理所有子服務(wù)的生命周期;
  • 我們來看一下LifecycleComponet:
public class LifecycleComponentStack implements LifecycleComponent {
   public static Builder newBuilder() {
       return new Builder();
   }

   /**
    * Builder to build a stack of {@link LifecycleComponent}s.
    */
   public static class Builder {
       ...
       private final List<LifecycleComponent> components;

       private Builder() {
           components = Lists.newArrayList();
       }

       public Builder addComponent(LifecycleComponent component) {
           checkNotNull(component, "Lifecycle component is null");
           components.add(component);
           return this;
       }

       public LifecycleComponentStack build() {
           checkNotNull(name, "Lifecycle component stack name is not provided");
           checkArgument(!components.isEmpty(), "Lifecycle component stack is empty : " + components);
           return new LifecycleComponentStack(
               name,
               ImmutableList.copyOf(components));
       }
   }

   private final String name;
   private final ImmutableList<LifecycleComponent> components;

   private LifecycleComponentStack(String name,
                                   ImmutableList<LifecycleComponent> components) {
       this.name = name;
       this.components = components;
   }
   ....
   @Override
   public void start() {
       components.forEach(component -> component.start());
   }

   @Override
   public void stop() {
       components.reverse().forEach(component -> component.stop());
   }

   @Override
   public void close() {
       components.reverse().forEach(component -> component.close());
   }
}
  1. 首先它內(nèi)置了Builder類,通過其addComponent方法將子組件加入進來伶跷,然后通過其build方法生成LifecycleComponent;
  2. 從定義上來看LifecycleComponent也實現(xiàn)了LifecycleComponent,因此它也實現(xiàn)了start stop close, 只不過這些方 法操作的是其包含的合部Component;
  3. 構(gòu)建啟動所需的所有子服務(wù)掰读,實現(xiàn)在buildBookieServer
public static LifecycleComponentStack buildBookieServer(BookieConfiguration conf) throws Exception {
       LifecycleComponentStack.Builder serverBuilder = LifecycleComponentStack.newBuilder().withName("bookie-server");

       // 1. build stats provider
       serverBuilder.addComponent(statsProviderService);

       // 2. build bookie server
       serverBuilder.addComponent(bookieService);

       if (conf.getServerConf().isLocalScrubEnabled()) {
           serverBuilder.addComponent(
                   new ScrubberService(
                           rootStatsLogger.scope(ScrubberStats.SCOPE),
                   conf, bookieService.getServer().getBookie().getLedgerStorage()));
       }

       // 3. build auto recovery
           serverBuilder.addComponent(autoRecoveryService);
           log.info("Load lifecycle component : {}", AutoRecoveryService.class.getName());

       // 4. build http service
           serverBuilder.addComponent(httpService);

       // 5. build extra services
       ...
       
       return serverBuilder.build();
   }

這里需要啟動組件主要有:StatsProviderService, BookieService, ScrubberService, AutoRecoverryService和HttpService

服務(wù)啟動
  • 組件啟動使用ComponentStarter來實現(xiàn)
public static CompletableFuture<Void> startComponent(LifecycleComponent component) {
        CompletableFuture<Void> future = new CompletableFuture<>();
        final Thread shutdownHookThread = new Thread(
            new ComponentShutdownHook(component, future),
            "component-shutdown-thread"
        );

        // register a shutdown hook
        Runtime.getRuntime().addShutdownHook(shutdownHookThread);

        // register a component exception handler
        component.setExceptionHandler((t, e) -> {
            // start the shutdown hook when an uncaught exception happen in the lifecycle component.
            shutdownHookThread.start();
        });

        component.start();
        return future;
    }

這個函數(shù)返回CompletableFuture<Void> future,當整個bookie結(jié)束或者拋出了未捕獲的異常時叭莫,這個future將被complete蹈集,對應(yīng)doMain中的代碼就是

    try {
            ComponentStarter.startComponent(server).get();
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
            // the server is interrupted
            log.info("Bookie server is interrupted. Exiting ...");
        } catch (ExecutionException ee) {
            log.error("Error in bookie shutdown", ee.getCause());
            return ExitCode.SERVER_EXCEPTION;
        }

其中ComponentStarter.startComponent(server).get()將阻塞等待future完成

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市雇初,隨后出現(xiàn)的幾起案子拢肆,更是在濱河造成了極大的恐慌,老刑警劉巖靖诗,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件善榛,死亡現(xiàn)場離奇詭異,居然都是意外死亡呻畸,警方通過查閱死者的電腦和手機移盆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伤为,“玉大人咒循,你說我怎么就攤上這事〗视蓿” “怎么了叙甸?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長位衩。 經(jīng)常有香客問我裆蒸,道長,這世上最難降的妖魔是什么糖驴? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任僚祷,我火速辦了婚禮,結(jié)果婚禮上贮缕,老公的妹妹穿的比我還像新娘辙谜。我一直安慰自己,他們只是感情好感昼,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布装哆。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜕琴。 梳的紋絲不亂的頭發(fā)上萍桌,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音凌简,去河邊找鬼上炎。 笑死,一個胖子當著我的面吹牛号醉,可吹牛的內(nèi)容都是我干的反症。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼畔派,長吁一口氣:“原來是場噩夢啊……” “哼铅碍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起线椰,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤胞谈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后憨愉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烦绳,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年配紫,在試婚紗的時候發(fā)現(xiàn)自己被綠了径密。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡躺孝,死狀恐怖享扔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情植袍,我是刑警寧澤惧眠,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站于个,受9級特大地震影響氛魁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜厅篓,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一秀存、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贷笛,春花似錦应又、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至汇荐,卻和暖如春洞就,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掀淘。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工旬蟋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人革娄。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓倾贰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拦惋。 傳聞我的和親對象是個殘疾皇子匆浙,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容