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

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

相关推荐
Deryck_德瑞克1 小时前
redis和分布式锁
分布式
徐徐同学1 小时前
cpolar为IT-Tools 解锁公网访问,远程开发再也不卡壳
java·开发语言·分布式
视界先声1 小时前
国产分布式存储替代VMware vSphere?:20+功能对比,一文了解SmartX
分布式
露天赏雪7 小时前
Java 高并发编程实战:从线程池到分布式锁,解决生产环境并发问题
java·开发语言·spring boot·分布式·后端·mysql
没有bug.的程序员9 小时前
Spring Boot 事务管理:@Transactional 失效场景、底层内幕与分布式补偿实战终极指南
java·spring boot·分布式·后端·transactional·失效场景·底层内幕
LuminescenceJ10 小时前
GoEdge 开源CDN 架构设计与工作原理分析
分布式·后端·网络协议·网络安全·rpc·开源·信息与通信
组合缺一13 小时前
论 AI Skills 分布式发展的必然性:从单体智能到“云端大脑”的跃迁
java·人工智能·分布式·llm·mcp·skills
shepherd12614 小时前
深度剖析SkyWalking:从内核原理到生产级全链路监控实战
分布式·后端·skywalking
h7ml16 小时前
基于 RabbitMQ 构建异步化淘客订单处理流水线:解耦、削峰与失败重试
分布式·rabbitmq·ruby
夜月蓝汐16 小时前
分布式监控SkyWalking链路追踪
分布式·skywalking