BRPC 基于zookeeper的命名服務(wù)實(shí)現(xiàn)

命名服務(wù)

命名服務(wù)是用將易記的名稱(chēng)(通常是由人類(lèi)可讀的名稱(chēng))映射到特定的網(wǎng)絡(luò)資源或服務(wù)叫搁。它為用戶提供了一種方便的方式來(lái)訪問(wèn)網(wǎng)絡(luò)資源枉氮,而無(wú)需記住資源的物理地址或復(fù)雜的網(wǎng)絡(luò)標(biāo)識(shí)符雷滚。

BRPC NamingService

在brpc中西剥,使用NamingService框架來(lái)管理命名服務(wù)初斑,同時(shí)集成負(fù)載均衡策略宪肖。
在當(dāng)前BRPC版本(1.7.0)中已經(jīng)內(nèi)置了多種命名服務(wù)實(shí)現(xiàn)其中包括:BNS疯搅、DNS濒生、File、consul等方式幔欧。
而zookeeper也是一種比較常見(jiàn)罪治、常用的命名服務(wù)工具丽声,以下是通過(guò)zookeeper搭建命名服務(wù)并集成到BRPC的NamingService框架中。

zookeeper命名服務(wù)的實(shí)現(xiàn)

第一步:初始化連接ZK服務(wù)觉义,設(shè)置命名服務(wù)名稱(chēng)節(jié)點(diǎn)

int Connect() {
        int ret = 0;
        // 設(shè)置 ZK 日志級(jí)別
        zoo_set_debug_level(ZOO_LOG_LEVEL_WARN);
        // 完成zk初始化雁社,獲取zk句柄,連接ZK服務(wù)
        zk_handle_ = zookeeper_init(zk_config_.GetServers().c_str(), zk_watcher_g,
                                    zk_config_.GetTimeout(), 0, this, 0);

        if (NULL == zk_handle_) {
            LOG(ERROR) << "Error when connecting to zookeeper servers...";
            return -1;
        }
        // 完成zk驗(yàn)證
        if (!zk_config_.GetUserAuth().empty()) {
            ret = zoo_add_auth(zk_handle_, "digest", zk_config_.GetUserAuth().c_str(),
                               zk_config_.GetUserAuth().length(), NULL, NULL);
            if (ret) {
                LOG(ERROR) << "error" << ret << " for verification.";
                return -2;
            }
        }
        // 設(shè)置命名服務(wù)ZK節(jié)點(diǎn)路徑 /naming_service_example/naming_service1
        // 用于watch服務(wù)信息變化
        data_dir_ = zk_config_.GetDataDir();
        return 0;
    };

第二步:添加Watcher 持續(xù)監(jiān)控命名服務(wù)下的節(jié)點(diǎn)變化

/**
     * AddWatcher 添加 命名服務(wù) 節(jié)點(diǎn)監(jiān)控
     * **/
void AddWatcher() {
    int ret = zoo_get_children(zk_handle_, data_dir_.c_str(), 1, &children_names_);
    if (ret != ZOK || children_names_.count <= 0) {
        LOG(INFO) << "default zookeeper data parser data is empty." << children_names_.count;
    }
    // 處理命名服務(wù)節(jié)點(diǎn)下的內(nèi)容信息
    parser_children_names();
    runing_ = true;
    watcher_thread_ = std::thread(&ZookeeperClient::do_parser_loop, this);
};

第三步:持續(xù)添加節(jié)點(diǎn)變化watcher
由于zookeeper的注冊(cè)event是一次性的晒骇,因此霉撵,watcher在接收到上次注冊(cè)的event以后就會(huì)失效,為了持續(xù)監(jiān)聽(tīng)zookeeper服務(wù)節(jié)點(diǎn)變化洪囤,每次watcher失效以后需要重新注冊(cè)watcher事件徒坡,因?yàn)槊?wù)一直監(jiān)聽(tīng)命名服務(wù)節(jié)點(diǎn)下的變化,因此可以通過(guò)zoo_get_children方法進(jìn)行watcher的重新注冊(cè)的功能

// 可通過(guò) 設(shè)置zoo_get_children的第三個(gè)參數(shù) watch 為非0 達(dá)到重新注冊(cè)的目的瘤缩,注冊(cè)的回調(diào)函數(shù)為zookeeper_init 傳入的 zk_watcher_g 方法
ZOOAPI int zoo_get_children(zhandle_t *zh, const char *path, int watch,
                            struct String_vector *strings)
static void zk_watcher_g(zhandle_t* zh, int type, int state, const char* path,
                             void* watcherCtx) {
        ZookeeperClient *self = (ZookeeperClient *)watcherCtx;
        if (type == ZOO_CHILD_EVENT) {
            std::lock_guard<std::mutex> lock(self->mutex_);
            zoo_get_children(zh, path, 1, &self->children_names_);
            self->is_changed_ = true;
        } else if (ZOO_SESSION_EVENT == type) {
            if (ZOO_CONNECTED_STATE == state) {
                LOG(INFO) << "Connected to ZooKeeper.";
            } else if (ZOO_EXPIRED_SESSION_STATE == state) {
                LOG(INFO) << "ZooKeeper session expired.";
                // TODO: Handle session expiration
                // do reconect
                for (int i = 0; i < 10; i++) {
                    if (0 == self->Connect()) {
                        break;
                    }
                    LOG(WARNING) << "Do zookeeper reconnect, times:" << i;
                    sleep(5);
                }
            }
        }
    };

zookeeper命名服務(wù)集成到BRPC

命名服務(wù)集成到BRPC 的NamingService框架只需要集成NamingService然后重寫(xiě)父類(lèi)方法即可喇完,最好通過(guò)注冊(cè)的方式,集成到框架中
第一步:繼承brpc::NamingService 類(lèi)

class ZooKeeperNamingService : public brpc::PeriodicNamingService {}

第二步:重寫(xiě)父類(lèi)方法實(shí)現(xiàn)自定義處理邏輯

// 持續(xù)獲取命名服務(wù)節(jié)點(diǎn)下的服務(wù)器列表剥啤,根據(jù)各自的業(yè)務(wù)需求實(shí)現(xiàn)列表獲取邏輯
// 列表通過(guò) zk watcher 持續(xù)監(jiān)聽(tīng)變化更新
int GetServers(const char *service_name, std::vector<brpc::ServerNode> *servers) override;
// 服務(wù)列表更新時(shí)間間隔锦溪,也就是框架調(diào)用GetServers方法的時(shí)間間隔
int GetNamingServiceAccessIntervalMs() const override;
void Describe(std::ostream &os, const brpc::DescribeOptions &) const override;
// 生成 命名服務(wù)對(duì)象
NamingService *New() const override;
void Destroy() override;

第三步:集成到BRPC的NamingService框架

// 設(shè)置ZK連接信息
ZKNamingService::ZKConfig zk_config("127.0.0.1:2181", "",
                              "test", "ns_test", 1000);
// 初始化內(nèi)部ZK連接信息
ZKNamingService::ZooKeeperNamingService zkns(zk_config, 2000);
// 將命名服務(wù)注冊(cè)到 NamingService框架,該步驟只是將命名服務(wù)類(lèi)注冊(cè)到框架中府怯,并沒(méi)有實(shí)際執(zhí)行刻诊,
// 在channel.Init()時(shí)通過(guò)brpc::NamingService* ZooKeeperNamingService::New();方法重新生成對(duì)象并執(zhí)行相關(guān)邏輯
brpc::NamingServiceExtension()->RegisterOrDie("zk", &zkns);
brpc::Channel channel;

// Initialize the channel, NULL means using default options.
brpc::ChannelOptions options;
options.timeout_ms = 1000 /*milliseconds*/;
options.max_retry = 1;
// 使用命名服務(wù)
if (channel.Init("zk://ns_test", "rr", &options) != 0) {
    LOG(ERROR) << "Fail to initialize channel";
    return -1;
}

參考文檔

brpc客戶端命名服務(wù)
brpc負(fù)載均衡
BNS命名服務(wù)
consul命名服務(wù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市牺丙,隨后出現(xiàn)的幾起案子则涯,更是在濱河造成了極大的恐慌,老刑警劉巖赘被,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件是整,死亡現(xiàn)場(chǎng)離奇詭異肖揣,居然都是意外死亡民假,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)龙优,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)羊异,“玉大人,你說(shuō)我怎么就攤上這事彤断∫安埃” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵宰衙,是天一觀的道長(zhǎng)平道。 經(jīng)常有香客問(wèn)我,道長(zhǎng)供炼,這世上最難降的妖魔是什么一屋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任窘疮,我火速辦了婚禮,結(jié)果婚禮上冀墨,老公的妹妹穿的比我還像新娘闸衫。我一直安慰自己,他們只是感情好诽嘉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布蔚出。 她就那樣靜靜地躺著,像睡著了一般虫腋。 火紅的嫁衣襯著肌膚如雪骄酗。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天岔乔,我揣著相機(jī)與錄音酥筝,去河邊找鬼。 笑死雏门,一個(gè)胖子當(dāng)著我的面吹牛嘿歌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茁影,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼宙帝,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了募闲?” 一聲冷哼從身側(cè)響起步脓,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浩螺,沒(méi)想到半個(gè)月后靴患,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡要出,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年鸳君,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片患蹂。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡或颊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出传于,到底是詐尸還是另有隱情囱挑,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布沼溜,位于F島的核電站平挑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏系草。R本人自食惡果不足惜通熄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一否淤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧棠隐,春花似錦石抡、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至嗡贺,卻和暖如春隐解,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诫睬。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工煞茫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摄凡。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓续徽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親亲澡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钦扭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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