MPRPC项目(第11天,zookeeper)

一、安装以及相关配置

bash 复制代码
//安装
sudo apt update
sudo apt install wget curl -y
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.5/apache-zookeeper-3.8.5-bin.tar.gz

//然后要配置java环境
# 1. 安装JDK8(ZooKeeper 3.8.5推荐)
sudo apt update && sudo apt install openjdk-8-jdk -y

# 2. 配置全局JAVA_HOME(确保ZooKeeper后台进程能读取)
echo "export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64" | sudo tee -a /etc/profile
echo "export PATH=\$JAVA_HOME/bin:\$PATH" | sudo tee -a /etc/profile
source /etc/profile

# 3. 验证Java环境
java -version  # 输出jdk1.8.x即成功

解压完后,

1、进入conf目录

2、将zoo_sample.cfg改为zoo.cfg

3、进入zoo.cfg

4、将dataDir修改一个路径,因为/tmp是临时文件

5、再进入bin目录,执行./zkServer.sh start

就成功了

二、znode节点和ZK客户端常用命令

1、znode节点存储格式

2、心跳消息

若客户端/服务端未在超时前发送心跳,ZooKeeper 会销毁其临时节点

3、客户端常用命令

执行./zkCli.sh

常用的命令有ls,get,create,set,delete

三、zk的watcher机制

允许客户端向服务器注册监听特定节点(znode)的变化。当被监听的节点发生改变时(如数据更新、节点删除、创建等),ZooKeeper 服务器会主动向客户端发送通知。

四、应用实践

1、zookeeper.h

cpp 复制代码
#pragma once
#include<semaphore.h>
#include<zookeeper/zookeeper.h>
#include<string>

class ZkClient
{ 
public:
    ZkClient();
    ~ZkClient();
    //启动连接zkserver
    void Start();
    //在zkserver上根据path创建znode节点
    void Create(const char* path, const char* data, int datalen, int state=0);//默认0永久性
    //根据参数指定的path,获取数据,并把数据保存在data中
    std::string GetData(const char* path);    
private:
    // zk客户端句柄
    zhandle_t* m_zhandle;
};

2、zookeeperutil.cc

cpp 复制代码
#include"zookeeperutil.h"
#include"mprpcapplication.h"
#include<semaphore.h>
#include<iostream>

//全局的watcher观察器  zkserver给zkclient的通知
void global_watcher(zhandle_t *zh,int type,int state,const char *path,void *watcherCtx)
{
    if(type==ZOO_SESSION_EVENT)//回调的消息类型是和会话相关的消息类型
    {
        if(state==ZOO_CONNECTED_STATE)//zkclient和zkserver链接成功
        {
            sem_t *sem=(sem_t*)zoo_get_context(zh);
            sem_post(sem);//信号量资源加一
        }
    }
}

ZkClient::ZkClient():m_zhandle(nullptr)
{}

ZkClient::~ZkClient()
{
    if(m_zhandle!=nullptr)
    {
        zookeeper_close(m_zhandle);//关闭句柄释放资源
    }
}

//zkclinet启动链接zkserver
void ZkClient::Start()
{
    //加载zk的IP和端口号,默认为2181
    std::string host=MprpcApplication::GetInstance().GetConfig().Load("zookeeperip");
    std::string port=MprpcApplication::GetInstance().GetConfig().Load("zookeeperport");
    std::string connstr=host+":"+port;

    //调用原生API,端口与IP,回调函数,会话超时时间
    /*
    zookeeper_mt:多线程版本
    zookeeper的API客户端程序提供了三个线程
    API调用线程
    网络I/O线程:专门在一个线程里处理网络I/O
    watcher回调线程
    */
    m_zhandle=zookeeper_init(connstr.c_str(),global_watcher,30000,nullptr,nullptr,0);
    if(nullptr==m_zhandle)
    {
        std::cout<<"zookeeper_init error!"<<std::endl;
        exit(EXIT_FAILURE);
    }

    sem_t sem;
    sem_init(&sem,0,0);//初始化资源为0
    zoo_set_context(m_zhandle,&sem);//设置上下文,添加额外信息

    sem_wait(&sem);
    std::cout<<"zookeeper_init success!"<<std::endl;

}
//在zkserver上根据指定的path创建znode节点
void ZkClient::Create(const char *path,const char *data,int datalen,int state)
{
    char path_buffer[128];
    int bufferlen=sizeof(path_buffer);
    int flag;

    //检查该节点是否存在
    flag=zoo_exists(m_zhandle,path,0,nullptr);
    if(ZNONODE==flag)//该节点并不存在
    {
        //创建指定path的znode节点
        flag=zoo_create(m_zhandle,path,data,datalen,&ZOO_OPEN_ACL_UNSAFE,state,path_buffer,bufferlen);
        if(flag==ZOK)
        {
            std::cout<<"znode create success... path:"<<path<<std::endl;
        }
        else
        {
            std::cout<<"flag:"<<flag<<std::endl;
            std::cout<<"znode create error... path:"<<path<<std::endl;
            exit(EXIT_FAILURE);
        }
    }
}
//传入参数指定的znode节点路径,获取znode节点的值
std::string ZkClient::GetData(const char *path)
{
    char buffer[64];
    int bufferlen=sizeof(buffer);
    int flag=zoo_get(m_zhandle,path,0,buffer,&bufferlen,nullptr);//获取信息与返回值
    if(flag!=ZOK)//如果获取失败
    {
        std::cout<<"get znode error... path:"<<path<<std::endl;
        return "";
    }
    else
    {
        //获取成功
        return buffer;
    }
    
}

3、rpcprovider.cc修改

添加

cpp 复制代码
//把当前rpc节点上要发布的服务全部注册到zk上,让客户端可以从zk上找到这个rpc节点
    //session timeout   1/3的timeout时间,会向zk发送ping
    ZkClient zkclient;
    zkclient.Start();

    for(auto &sp : m_serviceMap){
        std::string service_path = "/"+sp.first;
        zkclient.Create(service_path.c_str(),nullptr,0);
        for(auto &mp : sp.second.m_methodMap){
            std::string method_path = service_path+"/"+mp.first;
            char method_path_data[128] = {0};
            sprintf(method_path_data,"%s:%d",ip.c_str(),port);
            zkclient.Create(method_path.c_str(),method_path_data,strlen(method_path_data),ZOO_EPHEMERAL);
        }
    }

4、mprpcchannel.cc修改

将原来直接从配置文件读的ip和port优化,从zk获取

cpp 复制代码
//设置服务端的ip和port
    // std::string ip = MprpcApplication::GetInstance().GetConfig().Load("rpcserverip");
    // uint16_t port = atoi(MprpcApplication::GetInstance().GetConfig().Load("rpcserverport").c_str());

    ZkClient zkClient;
    zkClient.Start();

    std::string method_path = "/"+service_name + "/" + method_name;
    std::string host_data = zkClient.GetData(method_path.c_str());
    if(host_data.empty()){
        controller->SetFailed("zkClient get data failed!");
        return;
    }
    int idx = host_data.find(":");
    if(idx == -1){
        controller->SetFailed("zkClient get data failed!");
        return;
    }
    std::string ip = host_data.substr(0,idx);
    uint16_t port = atoi(host_data.substr(idx+1,host_data.size()-idx).c_str());

五、编译脚本

autobuild.sh

bash 复制代码
#!/bin/bash

set -e

rm -rf `pwd`/build/*
cd `pwd`/build &&
    cmake .. &&
    make
cd ..
cp -r `pwd`/src/include `pwd`/lib

该项目就结束了,还有很多细节没有补充,后面复习再补充了,让脑子自己先理解去。

相关推荐
Light601 天前
构建数据要素新纪元:领码SPARK平台驱动的可验证、可交易、可监管数据要素工程体系
分布式·数据治理·数据要素·数据质量·dcmm·领码spark·数据产品化
长路 ㅤ   1 天前
Curator源码解析:LeaderLatch实现
zookeeper·curator源码·leaderlatch·分布式选主·临时顺序节点
齐 飞1 天前
Spring Cloud Alibaba快速入门-分布式事务Seata(下)
分布式·spring cloud·微服务
机器觉醒时代1 天前
定义下一代机器人训练?智元 SOP:VLA 模型真实世界分布式在线后训练的关键突破
分布式·机器人·ai大模型·人形机器人
Honmaple1 天前
SpringBoot + Seata + Nacos:分布式事务落地实战,订单-库存一致性全解析
spring boot·分布式·后端
阳宗德1 天前
分布式解决方案:从痛点拆解到思路落地
分布式
2501_941805931 天前
面向高可用微服务体系的状态管理演进与多语言实现经验融合实践分享文章
java·大数据·分布式
rchmin1 天前
分布式ID生成方法详解
分布式
笃行客从不躺平1 天前
分布式事务核心原理与主流模型学习
分布式