pika
pika是一款基于rocksdb可持久化兼容redis协议的kv存储。当前最新的特性中还支持codis,可作为codis的后端存储使用,但是运维命令稍微有些不同。pika相对于redis而言主要是适合在容量大的场景下,简化了数据加载和迁移的相关操作,但是整体基于硬盘或者SSD的存储响应性能可能会差些。不过本文只是简单的来了解一下pika的设计的思路,方便以后在使用过程中加快对问题的诊断。
pika设计
pika在设计的时候支持了两种运行模式,即经典模式和分布式模式。
模式 | 原理 |
---|---|
经典模式 | 即一主多从模式,安装pika实例维度,即1个pika实例的数据可以被多个从实例数据同步。 |
分布式模式 | 即用户的数据集合称为table,将table切分成多个分片,每个分片称为slot,对于某个key的数据是由哈希算法计算来决定属于哪个slot,将所有slots及其副本按照一定策略分散到所有的pika实例中,每个pika实例有一部分的主slot和一部分从slot,主从的维度为slot。 |
官网原理图如下
经典模式
分布式模式
从原理图中,也可以清晰的看出经典模式以实例为维度,分布式模式以slot为维度。
pika启动流程
基于pika-3.4.0版本的代码结构,其中pika引用了四个第三方的库,分别如下:
- Blackwidow,由piak自行维护的基于rocksdb的存储管理,所有pika的数据操作都会通过blackwidow的封装最终落入rocksdb。
- Glog,日志库,用于pika项目输入不同等级的日志。
- Pink,由pika自行维护的事件驱动框架,封装了redis协议的解析分发功能,并提供回调函数进行处理。
- Slash,一些处理工具函数,例如同步的或者数据类型的工具函数。
启动流程中最主要的几个函数如下:
int main(int argc, char *argv[]) {
...
LOG(INFO) << "Server at: " << path;
g_pika_cmd_table_manager = new PikaCmdTableManager();
g_pika_server = new PikaServer();
g_pika_rm = new PikaReplicaManager();
g_pika_proxy = new PikaProxy();
if (g_pika_conf->daemonize()) {
close_std();
}
g_pika_proxy->Start();
g_pika_rm->Start();
g_pika_server->Start();
...
}
分为四步,即首先初始化cmd的命令,然后初始化PikaServer,接着初始化PikaReplicaManager,最后初始化PikaProxy,主要的启动函数就是如上几步,接着就继续分析一下。
PikaServer功能
PikaServer::PikaServer() :
exit_(false),
slot_state_(INFREE),
have_scheduled_crontask_(false),
last_check_compact_time_({0, 0}),
master_ip_(""),
master_port_(0),
repl_state_(PIKA_REPL_NO_CONNECT),
role_(PIKA_ROLE_SINGLE),
last_meta_sync_timestamp_(0),
first_meta_sync_(false),
loop_partition_state_machine_(false),
force_full_sync_(false),
slowlog_entry_id_(0) {
//Init server ip host
if (!ServerInit()) { // 初始化监听的端口和IP
LOG(FATAL) << "ServerInit iotcl error";
}
...
InitBlackwidowOptions(); // 初始化Blackwidow的参数项,主要配置rocksdb的相关参数
...
// Create thread 根据配置来查看有多少的工作线程数
worker_num_ = std::min(g_pika_conf->thread_num(),
PIKA_MAX_WORKER_THREAD_NUM);
std::set<std::string> ips;
if (g_pika_conf->n