kudu是一种分布式的存储引擎,服务端分为kudumaster以及kudutserver。master负责管理tablet server以及接受客户端请求,保存table的scheme等metadata,然后对数据分片具体的读写落在tablet server上。因此本文探究master如何对tablet server(简称TS)进行管理。
首先master以及ts进程往往分布在不同的主机上面,无法采用单机的IPC(inter process communication进程间通信方式),因此master以及ts互相之间的通信采用RPC(remote process call)的方式。kudu 采用protobuf的方式进行数据结构的序列化以及反序列化。
首先在master这边,ts被抽象为一种ts_descriptor的数据结构,保存着ts的实例信息以及注册信息。
#ifndef KUDU_MASTER_TS_DESCRIPTOR_H
#define KUDU_MASTER_TS_DESCRIPTOR_H
#include <memory>
#include <mutex>
#include <string>
#include "kudu/gutil/gscoped_ptr.h"
#include "kudu/util/locks.h"
#include "kudu/util/make_shared.h"
#include "kudu/util/monotime.h"
#include "kudu/util/status.h"
namespace kudu {
class NodeInstancePB;
class Sockaddr;
class ServerRegistrationPB;
// TS实例信息的protobuf类
// sockaddr用于socket传递参数类以及返回值类
// 服务器注册信息的protobuf类
// PB类通过sockaddr进行传输
namespace consensus {
class ConsensusServiceProxy;
}
//一致性服务代理
namespace rpc {
class Messenger;
}
//messenger
namespace tserver {
class TabletServerAdminServiceProxy;
}
//TS管理服务代理
namespace master {
// master这边保存的tablet server的信息
// 这个类用于追踪ts上一次的心跳 状态 实例id等 该类为线程安全(因为使用了自旋锁等同步方式访问私有数据)
class TSDescriptor {
public:
static Status RegisterNew(const NodeInstancePB& instance,
const ServerRegistrationPB& registration,
std::shared_ptr<TSDescriptor>* desc);
//static函数 注册一个新ts 需要ts的节点实例 服务器注册类 以及ts描述类的一个指针
virtual ~TSDescriptor();
//析构函数为虚
void UpdateHeartbeatTime();
//更新ts heartbeat时间为当前
MonoDelta TimeSinceHeartbeat() const;
//返回上次心跳到现在为止的时间区间
bool PresumedDead() const;
//根据心跳判定ts是否已经挂掉
Status Register(const NodeInstancePB& instance,
const ServerRegistrationPB& registration);
//注册ts 与static register相比有何不同?参数少了一个指向自己的指针
const std::string &permanent_uuid() const { return permanent_uuid_; }
int64_t latest_seqno() const;
//uuid 以及 最新的序列号 序列号干嘛用的?
void GetRegistration(ServerRegistrationPB* reg) const;
//获取ts注册信息
void GetNodeInstancePB(NodeInstancePB* instance_pb) const;
//获取TS节点实例信息
Status GetTSAdminProxy(const std::shared_ptr<rpc::Messenger>& messenger,
std::shared_ptr<tserver::TabletServerAdminServiceProxy>* proxy);
//返回ts管理服务的代理
Status GetConsensusProxy(const std::shared_ptr<rpc::Messenger>& messenger,
std::shared_ptr<consensus::ConsensusServiceProxy>* proxy);
//返回一致性服务的代理
void IncrementRecentReplicaCreations();
//增加最近创建的副本数 该数值需要随时间自动衰退
double RecentReplicaCreations();
//ts最新创建的副本数
void set_num_live_replicas(int n) {
DCHECK_GE(n, 0);
std::lock_guard<simple_spinlock> l(lock_);
num_live_replicas_ = n;
}//设置存活副本数
int num_live_replicas() const {
std::lock_guard<simple_spinlock> l(lock_);
return num_live_replicas_;
}
//存活的副本数
std::string ToString() const;
private:
FRIEND_TEST(TestTSDescriptor, TestReplicaCreationsDecay);//友元 用于测试
explicit TSDescriptor(std::string perm_id);
//私有显式转换构造 通过uuid转换
Status ResolveSockaddr(Sockaddr* addr) const;
//使用dns 将注册的ts主机 解析为sockaddr
void DecayRecentReplicaCreationsUnlocked();
mutable simple_spinlock lock_;
//自旋锁
const std::string permanent_uuid_;
int64_t latest_seqno_;
//uuid以及序列号
MonoTime last_heartbeat_;
//上次heartbeat时间
double recent_replica_creations_;
//ts最近被master选择用于创建新副本的次数
//如果master要选择一个ts创建副本 应该选择最近比较空闲的 也就该值比较低
MonoTime last_replica_creations_decay_;
int num_live_replicas_;
//ts上存活的副本数
gscoped_ptr<ServerRegistrationPB> registration_;
//智能指针 注册信息 master上会有多少线程同时使用ts的注册信息呢
std::shared_ptr<tserver::TabletServerAdminServiceProxy> ts_admin_proxy_;
std::shared_ptr<consensus::ConsensusServiceProxy> consensus_proxy_;
//ts两个代理的地址
ALLOW_MAKE_SHARED(TSDescriptor);
DISALLOW_COPY_AND_ASSIGN(TSDescriptor);
//两个宏 一个是禁止拷贝与赋值 因为每个ts都是独一无二的
//一个是允许使用make shared函数 提高shared_ptr之间拷贝的速度
};
} /