Nacos配置中心

客戶端與配置中心的數(shù)據(jù)交互方式其實(shí)無(wú)非就兩種猾骡,要么推push晒来,要么拉pull。

推模型

客戶端與服務(wù)端建立TCP長(zhǎng)連接空郊,當(dāng)服務(wù)端配置數(shù)據(jù)有變動(dòng)宫莱,立刻通過(guò)建立的長(zhǎng)連接將數(shù)據(jù)推送給客戶端缀雳。

優(yōu)勢(shì):長(zhǎng)鏈接的優(yōu)點(diǎn)是實(shí)時(shí)性,一旦數(shù)據(jù)變動(dòng)梢睛,立即推送變更數(shù)據(jù)給客戶端,而且對(duì)于客戶端而言识椰,這種方式更為簡(jiǎn)單绝葡,只建立連接接收數(shù)據(jù),并不需要關(guān)心是否有數(shù)據(jù)變更這類邏輯的處理腹鹉。
弊端:長(zhǎng)連接可能會(huì)因?yàn)榫W(wǎng)絡(luò)問(wèn)題藏畅,導(dǎo)致不可用,也就是俗稱的假死功咒。連接狀態(tài)正常愉阎,但實(shí)際上已無(wú)法通信,所以要有的心跳機(jī)制KeepAlive來(lái)保證連接的可用性力奋,才可以保證配置數(shù)據(jù)的成功推送榜旦。

拉模型

客戶端主動(dòng)的向服務(wù)端發(fā)請(qǐng)求拉配置數(shù)據(jù),常見的方式就是輪詢景殷,比如每3s向服務(wù)端請(qǐng)求一次配置數(shù)據(jù)溅呢。
輪詢的優(yōu)點(diǎn)是實(shí)現(xiàn)比較簡(jiǎn)單。但弊端也顯而易見猿挚,輪詢無(wú)法保證數(shù)據(jù)的實(shí)時(shí)性咐旧,什么時(shí)候請(qǐng)求?間隔多長(zhǎng)時(shí)間請(qǐng)求一次绩蜻?都是不得不考慮的問(wèn)題铣墨,而且輪詢方式對(duì)服務(wù)端還會(huì)產(chǎn)生不小的壓力。

nacos采用的是客戶端主動(dòng)拉pull模型办绝,應(yīng)用長(zhǎng)輪詢(Long Polling)的方式來(lái)獲取配置數(shù)據(jù)伊约。

以前只聽過(guò)輪詢姚淆,長(zhǎng)輪詢又是什么鬼?它和傳統(tǒng)意義上的輪詢(暫且叫短輪詢吧碱妆,方便比較)有什么不同呢肉盹?

短輪詢

不管服務(wù)端配置數(shù)據(jù)是否有變化,不停的發(fā)起請(qǐng)求獲取配置疹尾,比如支付場(chǎng)景中前段JS輪詢訂單支付狀態(tài)上忍。
這樣的壞處顯而易見,由于配置數(shù)據(jù)并不會(huì)頻繁變更纳本,若是一直發(fā)請(qǐng)求窍蓝,勢(shì)必會(huì)對(duì)服務(wù)端造成很大壓力。還會(huì)造成推送數(shù)據(jù)的延遲繁成,比如:每10s請(qǐng)求一次配置吓笙,如果在第11s時(shí)配置更新了,那么推送將會(huì)延遲9s巾腕,等待下一次請(qǐng)求面睛。
為了解決短輪詢的問(wèn)題,有了長(zhǎng)輪詢方案尊搬。

長(zhǎng)輪詢

長(zhǎng)輪詢可不是什么新技術(shù)叁鉴,它不過(guò)是由服務(wù)端控制響應(yīng)客戶端請(qǐng)求的返回時(shí)間,來(lái)減少客戶端無(wú)效請(qǐng)求的一種優(yōu)化手段佛寿,其實(shí)對(duì)于客戶端來(lái)說(shuō)與短輪詢的使用并沒(méi)有本質(zhì)上的區(qū)別幌墓。
客戶端發(fā)起請(qǐng)求后,服務(wù)端不會(huì)立即返回請(qǐng)求結(jié)果冀泻,而是將請(qǐng)求掛起等待一段時(shí)間常侣,如果此段時(shí)間內(nèi)服務(wù)端數(shù)據(jù)變更,立即響應(yīng)客戶端請(qǐng)求弹渔,若是一直無(wú)變化則等到指定的超時(shí)時(shí)間后響應(yīng)請(qǐng)求胳施,客戶端重新發(fā)起長(zhǎng)鏈接。

幾個(gè)概念

Nacos配置中心的幾個(gè)核心概念:dataId捞附、group巾乳、namespace

dataId:是配置中心里最基礎(chǔ)的單元,它是一種key-value結(jié)構(gòu)鸟召,key通常是我們的配置文件名稱胆绊,比如:application.yml、mybatis.xml欧募,而value是整個(gè)文件下的內(nèi)容压状。
目前支持JSON、XML、YAML等多種配置格式种冬。

group:dataId配置的分組管理镣丑,比如同在dev環(huán)境下開發(fā),但同環(huán)境不同分支需要不同的配置數(shù)據(jù)娱两,這時(shí)就可以用分組隔離莺匠,默認(rèn)分組DEFAULT_GROUP。

namespace:項(xiàng)目開發(fā)過(guò)程中肯定會(huì)有dev十兢、test趣竣、pro等多個(gè)不同環(huán)境,namespace則是對(duì)不同環(huán)境進(jìn)行隔離旱物,默認(rèn)所有配置都在public里遥缕。

nacos配置中心的流程。

客戶端宵呛、控制臺(tái)通過(guò)發(fā)送Http請(qǐng)求將配置數(shù)據(jù)注冊(cè)到服務(wù)端单匣,服務(wù)端持久化數(shù)據(jù)到Mysql。

客戶端拉取配置數(shù)據(jù)宝穗,并批量設(shè)置對(duì)dataId的監(jiān)聽發(fā)起長(zhǎng)輪詢請(qǐng)求户秤,如服務(wù)端配置項(xiàng)變更立即響應(yīng)請(qǐng)求,如無(wú)數(shù)據(jù)變更則將請(qǐng)求掛起一段時(shí)間逮矛,直到達(dá)到超時(shí)時(shí)間虎忌。為減少對(duì)服務(wù)端壓力以及保證配置中心可用性,拉取到配置數(shù)據(jù)客戶端會(huì)保存一份快照在本地文件中橱鹏,優(yōu)先讀取。

這里省略了比較多的細(xì)節(jié)堪藐,如鑒權(quán)莉兰、負(fù)載均衡、高可用方面的設(shè)計(jì)(其實(shí)這部分才是真正值得學(xué)的礁竞,后邊另出文講吧)糖荒,主要弄清客戶端與服務(wù)端的數(shù)據(jù)交互模式。

客戶端源碼分析

Nacos配置中心的客戶端源碼在nacos-client項(xiàng)目模捂,其中NacosConfigService實(shí)現(xiàn)類是所有操作的核心入口捶朵。

說(shuō)之前先了解個(gè)客戶端數(shù)據(jù)結(jié)構(gòu)cacheMap,這里大家重點(diǎn)記住它狂男,因?yàn)樗鼛缀踟灤┝薔acos客戶端的所有操作综看,由于存在多線程場(chǎng)景為保證數(shù)據(jù)一致性,cacheMap采用了AtomicReference原子變量實(shí)現(xiàn)岖食。

/**
 * groupKey -> cacheData.
 */
private final AtomicReference<Map<String, CacheData>> cacheMap = new AtomicReference<Map<String, CacheData>>(new HashMap<>());

cacheMap是個(gè)Map結(jié)構(gòu)红碑,key為groupKey,是由dataId, group, tenant(租戶)拼接的字符串;value為CacheData對(duì)象析珊,每個(gè)dataId都會(huì)持有一個(gè)CacheData對(duì)象羡鸥。

獲取配置

Nacos獲取配置數(shù)據(jù)的邏輯比較簡(jiǎn)單,先取本地快照文件中的配置忠寻,如果本地文件不存在或者內(nèi)容為空惧浴,則再通過(guò)HTTP請(qǐng)求從遠(yuǎn)端拉取對(duì)應(yīng)dataId配置數(shù)據(jù),并保存到本地快照中奕剃,請(qǐng)求默認(rèn)重試3次衷旅,超時(shí)時(shí)間3s。

獲取配置有g(shù)etConfig()和getConfigAndSignListener()這兩個(gè)接口祭饭,但getConfig()只是發(fā)送普通的HTTP請(qǐng)求芜茵,而getConfigAndSignListener()則多了發(fā)起長(zhǎng)輪詢和對(duì)dataId數(shù)據(jù)變更注冊(cè)監(jiān)聽的操作addTenantListenersWithContent()。

@Override
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {
    return getConfigInner(namespace, dataId, group, timeoutMs);
}

@Override
public String getConfigAndSignListener(String dataId, String group, long timeoutMs, Listener listener)
        throws NacosException {
    String content = getConfig(dataId, group, timeoutMs);
    worker.addTenantListenersWithContent(dataId, group, content, Arrays.asList(listener));
    return content;
}
注冊(cè)監(jiān)聽

客戶端注冊(cè)監(jiān)聽倡蝙,先從cacheMap中拿到dataId對(duì)應(yīng)的CacheData對(duì)象九串。

public void addTenantListenersWithContent(String dataId, String group, String content,
                                          List<? extends Listener> listeners) throws NacosException {
    group = blank2defaultGroup(group);
    String tenant = agent.getTenant();
    // 1、獲取dataId對(duì)應(yīng)的CacheData寺鸥,如沒(méi)有則向服務(wù)端發(fā)起長(zhǎng)輪詢請(qǐng)求獲取配置
    CacheData cache = addCacheDataIfAbsent(dataId, group, tenant);
    synchronized (cache) {
        // 2猪钮、注冊(cè)對(duì)dataId的數(shù)據(jù)變更監(jiān)聽
        cache.setContent(content);
        for (Listener listener : listeners) {
            cache.addListener(listener);
        }
        cache.setSyncWithServer(false);
        agent.notifyListenConfig();
    }
}

如沒(méi)有則向服務(wù)端發(fā)起長(zhǎng)輪詢請(qǐng)求獲取配置,默認(rèn)的Timeout時(shí)間為30s胆建,并把返回的配置數(shù)據(jù)回填至CacheData對(duì)象的content字段烤低,同時(shí)用content生成MD5值;再通過(guò)addListener()注冊(cè)監(jiān)聽器笆载。

CacheData也是個(gè)出場(chǎng)頻率非常高的一個(gè)類扑馁,我們看到除了dataId、group凉驻、tenant腻要、content這些相關(guān)的基礎(chǔ)屬性,還有幾個(gè)比較重要的屬性如:listeners涝登、md5(content真實(shí)配置數(shù)據(jù)計(jì)算出來(lái)的md5值)雄家,以及注冊(cè)監(jiān)聽、數(shù)據(jù)比對(duì)胀滚、服務(wù)端數(shù)據(jù)變更通知操作都在這里趟济。

其中l(wèi)isteners是對(duì)dataId所注冊(cè)的所有監(jiān)聽器集合,其中的ManagerListenerWrap對(duì)象除了持有Listener監(jiān)聽類咽笼,還有一個(gè)lastCallMd5字段顷编,這個(gè)屬性很關(guān)鍵,它是判斷服務(wù)端數(shù)據(jù)是否更變的重要條件剑刑。

在添加監(jiān)聽的同時(shí)會(huì)將CacheData對(duì)象當(dāng)前最新的md5值賦值給ManagerListenerWrap對(duì)象的lastCallMd5屬性勾效。

public void addListener(Listener listener) {
    ManagerListenerWrap wrap =
        (listener instanceof AbstractConfigChangeListener) ? new ManagerListenerWrap(listener, md5, content)
            : new ManagerListenerWrap(listener, md5);
}

看到這對(duì)dataId監(jiān)聽設(shè)置就完事了?我們發(fā)現(xiàn)所有操作都圍著cacheMap結(jié)構(gòu)中的CacheData對(duì)象,那么大膽猜測(cè)下一定會(huì)有專門的任務(wù)來(lái)處理這個(gè)數(shù)據(jù)結(jié)構(gòu)层宫。

變更通知

客戶端又是如何感知服務(wù)端數(shù)據(jù)已變更呢杨伙?

我們還是從頭看,NacosConfigService類的構(gòu)造器中初始化了一個(gè)ClientWorker萌腿,而在ClientWorker類的構(gòu)造器中又啟動(dòng)了一個(gè)線程池來(lái)輪詢cacheMap限匣。

而在executeConfigListen()方法中有這么一段邏輯,檢查cacheMap中dataId的CacheData對(duì)象內(nèi)毁菱,MD5字段與注冊(cè)的監(jiān)聽listener內(nèi)的lastCallMd5值米死,不相同表示配置數(shù)據(jù)變更則觸發(fā)safeNotifyListener方法,發(fā)送數(shù)據(jù)變更通知贮庞。

void checkListenerMd5() {
    for (ManagerListenerWrap wrap : listeners) {
        if (!md5.equals(wrap.lastCallMd5)) {
            safeNotifyListener(dataId, group, content, type, md5, encryptedDataKey, wrap);
        }
    }
}

safeNotifyListener()方法單獨(dú)起線程峦筒,向所有對(duì)dataId注冊(cè)過(guò)監(jiān)聽的客戶端推送變更后的數(shù)據(jù)內(nèi)容。

客戶端接收通知窗慎,直接實(shí)現(xiàn)receiveConfigInfo()方法接收回調(diào)數(shù)據(jù)物喷,處理自身業(yè)務(wù)就可以了。

configService.addListener(dataId, group, new Listener() {
    @Override
    public void receiveConfigInfo(String configInfo) {
        System.out.println("receive:" + configInfo);
    }

    @Override
    public Executor getExecutor() {
        return null;
    }
});

為了理解更直觀我用測(cè)試demo演示下遮斥,獲取服務(wù)端配置并設(shè)置監(jiān)聽峦失,每當(dāng)服務(wù)端配置數(shù)據(jù)變化,客戶端監(jiān)聽都會(huì)收到通知术吗,一起看下效果尉辑。

public static void main(String[] args) throws NacosException, InterruptedException {
    String serverAddr = "localhost";
    String dataId = "test";
    String group = "DEFAULT_GROUP";
    Properties properties = new Properties();
    properties.put("serverAddr", serverAddr);
    ConfigService configService = NacosFactory.createConfigService(properties);
    String content = configService.getConfig(dataId, group, 5000);
    System.out.println(content);
    configService.addListener(dataId, group, new Listener() {
        @Override
        public void receiveConfigInfo(String configInfo) {
            System.out.println("數(shù)據(jù)變更 receive:" + configInfo);
        }
        @Override
        public Executor getExecutor() {
            return null;
        }
    });

    boolean isPublishOk = configService.publishConfig(dataId, group, "我是新配置內(nèi)容~");
    System.out.println(isPublishOk);

    Thread.sleep(3000);
    content = configService.getConfig(dataId, group, 5000);
    System.out.println(content);
}

結(jié)果和預(yù)想的一樣,當(dāng)向服務(wù)端publishConfig數(shù)據(jù)變化后较屿,客戶端可以立即感知隧魄,愣是用主動(dòng)拉pull模式做出了服務(wù)端實(shí)時(shí)推送的效果。

服務(wù)端源碼分析

Nacos配置中心的服務(wù)端源碼主要在nacos-config項(xiàng)目的ConfigController類隘蝎,服務(wù)端的邏輯要比客戶端稍復(fù)雜一些堤器,這里我們重點(diǎn)看下。

處理長(zhǎng)輪詢
服務(wù)端對(duì)外提供的監(jiān)聽接口地址/v1/cs/configs/listener末贾,這個(gè)方法內(nèi)容不多,順著doPollingConfig往下看整吆。

服務(wù)端根據(jù)請(qǐng)求header中的Long-Pulling-Timeout屬性來(lái)區(qū)分請(qǐng)求是長(zhǎng)輪詢還是短輪詢拱撵,這里咱們只關(guān)注長(zhǎng)輪詢部分,接著看LongPollingService(記住這個(gè)service很關(guān)鍵)類中的addLongPollingClient()方法是如何處理客戶端的長(zhǎng)輪詢請(qǐng)求的表蝙。

正乘┎猓客戶端默認(rèn)設(shè)置的請(qǐng)求超時(shí)時(shí)間是30s,但這里我們發(fā)現(xiàn)服務(wù)端“偷偷”的給減掉了500ms府蛇,現(xiàn)在超時(shí)時(shí)間只剩下了29.5s集索,那為什么要這樣做呢?

用官方的解釋之所以要提前500ms響應(yīng)請(qǐng)求,為了最大程度上保證客戶端不會(huì)因?yàn)榫W(wǎng)絡(luò)延時(shí)造成超時(shí)务荆,考慮到請(qǐng)求可能在負(fù)載均衡時(shí)會(huì)耗費(fèi)一些時(shí)間妆距,畢竟Nacos最初就是按照阿里自身業(yè)務(wù)體量設(shè)計(jì)的嘛!

此時(shí)對(duì)客戶端提交上來(lái)的groupkey的MD5與服務(wù)端當(dāng)前的MD5比對(duì)函匕,如md5值不同娱据,則說(shuō)明服務(wù)端的配置項(xiàng)發(fā)生過(guò)變更,直接將該groupkey放入changedGroupKeys集合并返回給客戶端盅惜。

如未發(fā)生變更中剩,則將客戶端請(qǐng)求掛起,這個(gè)過(guò)程先創(chuàng)建一個(gè)名為ClientLongPolling的調(diào)度任務(wù)Runnable抒寂,并提交給scheduler定時(shí)線程池延后29.5s執(zhí)行结啼。

ConfigExecutor.executeLongPolling(
                new ClientLongPolling(asyncContext, clientMd5Map, ip, probeRequestSize, timeout, appName, tag));

這里每個(gè)長(zhǎng)輪詢?nèi)蝿?wù)攜帶了一個(gè)asyncContext對(duì)象,使得每個(gè)請(qǐng)求可以延遲響應(yīng)屈芜,等延時(shí)到達(dá)或者配置有變更之后,調(diào)用asyncContext.complete()響應(yīng)完成郊愧。

asyncContext 為 Servlet 3.0新增的特性,異步處理沸伏,使Servlet線程不再需要一直阻塞糕珊,等待業(yè)務(wù)處理完畢才輸出響應(yīng);可以先釋放容器分配給請(qǐng)求的線程與相關(guān)資源毅糟,減輕系統(tǒng)負(fù)擔(dān)红选,其響應(yīng)將被延后,在處理完業(yè)務(wù)或者運(yùn)算后再對(duì)客戶端進(jìn)行響應(yīng)姆另。

ClientLongPolling任務(wù)被提交進(jìn)入延遲線程池執(zhí)行的同時(shí)喇肋,服務(wù)端會(huì)通過(guò)一個(gè)allSubs隊(duì)列保存所有正在被掛起的客戶端長(zhǎng)輪詢請(qǐng)求任務(wù),這個(gè)是客戶端注冊(cè)監(jiān)聽的過(guò)程迹辐。

如延時(shí)期間客戶端據(jù)數(shù)一直未變化蝶防,延時(shí)時(shí)間到達(dá)后將本次長(zhǎng)輪詢?nèi)蝿?wù)從allSubs隊(duì)列剔除,并響應(yīng)請(qǐng)求response明吩,這是取消監(jiān)聽间学。收到響應(yīng)后客戶端再次發(fā)起長(zhǎng)輪詢,循環(huán)往復(fù)印荔。

到這我們知道服務(wù)端是如何掛起客戶端長(zhǎng)輪詢請(qǐng)求的低葫,一旦請(qǐng)求在掛起期間,用戶通過(guò)管理平臺(tái)操作了配置項(xiàng)仍律,或者服務(wù)端收到了來(lái)自其他客戶端節(jié)點(diǎn)修改配置的請(qǐng)求嘿悬。

怎么能讓對(duì)應(yīng)已掛起的任務(wù)立即取消,并且及時(shí)通知客戶端數(shù)據(jù)發(fā)生了變更呢水泉?

數(shù)據(jù)變更

管理平臺(tái)或者客戶端更改配置項(xiàng)接位置ConfigController中的publishConfig方法善涨。
值得注意得是窒盐,在publishConfig接口中有這么一段邏輯,某個(gè)dataId配置數(shù)據(jù)被修改時(shí)會(huì)觸發(fā)一個(gè)數(shù)據(jù)變更事件Event钢拧。

ConfigChangePublisher.notifyConfigChange(new ConfigDataChangeEvent(false, dataId, group, tenant, time.getTime()));

仔細(xì)看LongPollingService會(huì)發(fā)現(xiàn)在它的構(gòu)造方法中蟹漓,正好訂閱了數(shù)據(jù)變更事件,并在事件觸發(fā)時(shí)執(zhí)行一個(gè)數(shù)據(jù)變更調(diào)度任務(wù)DataChangeTask娶靡。

DataChangeTask內(nèi)的主要邏輯就是遍歷allSubs隊(duì)列牧牢,上邊我們知道,這個(gè)隊(duì)列中維護(hù)的是所有客戶端的長(zhǎng)輪詢請(qǐng)求任務(wù)姿锭,從這些任務(wù)中找到包含當(dāng)前發(fā)生變更的groupkey的ClientLongPolling任務(wù)塔鳍,以此實(shí)現(xiàn)數(shù)據(jù)更變推送給客戶端,并從allSubs隊(duì)列中剔除此長(zhǎng)輪詢?nèi)蝿?wù)呻此。

而我們?cè)诳唇o客戶端響應(yīng)response時(shí)轮纫,調(diào)用asyncContext.complete()結(jié)束了異步請(qǐng)求。

參考:
https://gitee.com/source-code-collection/nacos

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末焚鲜,一起剝皮案震驚了整個(gè)濱河市掌唾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌忿磅,老刑警劉巖糯彬,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異葱她,居然都是意外死亡撩扒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門吨些,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)搓谆,“玉大人,你說(shuō)我怎么就攤上這事豪墅∪郑” “怎么了?”我有些...
    開封第一講書人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵偶器,是天一觀的道長(zhǎng)斩萌。 經(jīng)常有香客問(wèn)我,道長(zhǎng)屏轰,這世上最難降的妖魔是什么颊郎? 我笑而不...
    開封第一講書人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮亭枷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘搀崭。我一直安慰自己叨粘,他們只是感情好猾编,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著升敲,像睡著了一般答倡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上驴党,一...
    開封第一講書人閱讀 52,337評(píng)論 1 310
  • 那天瘪撇,我揣著相機(jī)與錄音,去河邊找鬼港庄。 笑死倔既,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鹏氧。 我是一名探鬼主播渤涌,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼把还!你這毒婦竟也來(lái)了实蓬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤吊履,失蹤者是張志新(化名)和其女友劉穎安皱,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艇炎,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酌伊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冕臭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腺晾。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖辜贵,靈堂內(nèi)的尸體忽然破棺而出悯蝉,到底是詐尸還是另有隱情,我是刑警寧澤托慨,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布鼻由,位于F島的核電站,受9級(jí)特大地震影響厚棵,放射性物質(zhì)發(fā)生泄漏蕉世。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一婆硬、第九天 我趴在偏房一處隱蔽的房頂上張望狠轻。 院中可真熱鬧,春花似錦彬犯、人聲如沸向楼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)湖蜕。三九已至逻卖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昭抒,已是汗流浹背评也。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灭返,地道東北人盗迟。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像婆殿,于是被迫代替她去往敵國(guó)和親诈乒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

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

  • 動(dòng)態(tài)配置管理是 Nacos 的三大功能之一婆芦,通過(guò)動(dòng)態(tài)配置服務(wù)怕磨,我們可以在所有環(huán)境中以集中和動(dòng)態(tài)的方式管理所有應(yīng)用程...
    逅弈閱讀 75,870評(píng)論 9 101
  • 要分析Nacos源碼,好歹我們也通過(guò)源碼啟動(dòng)起來(lái)消约,這樣也方便我們debug代碼肠鲫。注:nacos1.1.3 文章篇幅...
    Visonwu閱讀 16,261評(píng)論 0 3
  • 本文已收錄 https://github.com/lkxiaolou/lkxiaolou[https://gith...
    捉蟲大師閱讀 3,510評(píng)論 0 1
  • 一、配置中心介紹 1或粮、Spring Cloud Config Spring Cloud Config為分布式系統(tǒng)的...
    刊ing閱讀 1,106評(píng)論 0 0
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險(xiǎn)厭惡者导饲,不喜歡去冒險(xiǎn),但是人生放棄了冒險(xiǎn)氯材,也就放棄了無(wú)數(shù)的可能渣锦。 ...
    yichen大刀閱讀 6,057評(píng)論 0 4