目录
with InfiniBand RDMA architecture
原文:http://blog.wjin.org/posts/ceph-async-messenger.html
作于December 28, 2015,比较老,有一定的参考意义,但应该与现在的有一定差异。
一、前置知识
1、ceph Async 模型
ceph Async的IO 多路复用多线程模型
说明:
每个worker 有一个eventCenter,一条workerThread线程。workerpool管理着多个worker,AsyncConnection在创建时根据负载均衡绑定到对应的Worker中。
在Ceph Async模型里,一个Worker类对应一个工作线程和一个事件中心EventCenter。 每个socket对应的AsyncConnection在创建时根据负载均衡绑定到对应的Worker中,以后都由该Worker处理该AsyncConnection上的所有的读写事件。
2、Async Messenger机制图
图:
建立连接后的sd与worker的绑定
一个进程里只有一个workerpool,即使多个messager也是共享一个,里面包含有多个worker,一个worker一个thread,worker内一个eventcenter,eventcenter管理epoll
通信流图:
如图所示,在Ceph Async模型里,没有单独的main_loop线程,每个工作线程都是独立的,其循环处理如下:
- epoll_wait 等待事件
- 处理获取到的所有IO事件
- 处理所有时间相关的事件
- 处理外部事件
在这个模型中,消除了Half-sync/half-async的 队列互斥访问和 线程切换的问题。 本模型的优点本质上是利用了操作系统的事件队列,而没有自己去处理事件队列。
3、Async Messenger分层架构
二、代码跟踪
研究对象:源码在文件src/ceph_osd.cc。
1、Server
服务端需要监听端口,等待连接请求到来,然后接受请求,建立连接,进行通信。
先来看核心代码
int main(int argc, const char **argv)
{
……
messenger = Messenger::create(g_ceph_context, g_conf->ms_type,
entity_name_t::MON(-1),
"simple_server",
0 /* nonce */,
0 /* flags */);
……
r = messenger->bind(bind_addr); //posix中= (bind+listen)
……
messenger->start();
messenger->wait(); // can't be called until ready()
……
}
Simple、async“外观上”都是创建messenger –> bind->start-> wait--->外观模式--->和socket相似 socket-->bind-->listen-->Epoll.wait
1)Initialization (create )
以osd进程为例,在进程启动的过程中,会创建Messenger对象,用于管理网络连接,监听端口,接收请求,源码在文件src/ceph_osd.cc:
int main(int argc, const char **argv)
{
......
// public用于客户端通信
Messenger *ms_public = Messenger::create(g_ceph_context, g_conf->ms_type,
entity_name_t::OSD(whoami), "client",
getpid());
// cluster用于集群内部通信
Messenger *ms_cluster = Messenger::create(g_ceph_context, g_conf->ms_type,
entity_name_t::OSD(whoami), "cluster",
getpid());
/*
Messenger *ms_hb_back_client = Messenger::create();
Messenger *ms_hb_front_client = Messenger::create();
Messenger *ms_hb_back_server = Messenger::create();
Messenger *ms_hb_front_server = Messenger::create();
Messenger *ms_objecter = Messenger::create();
*/
......
}
生成messenger用了工厂模式:
//src/msg/Messenger.cc
Messenger *Messenger::create(CephContext *cct, const string &type,
entity_name_t name, string lname,
uint64_t nonce)
{
......
// 在src/common/config_opts.h文件中,目前需要配置async相关选项才会生效
// OPTION(enable_experimental_unrecoverable_data_corrupting_features, OPT_STR, "ms-type-async")
// OPTION(ms_type, OPT_STR, "async")
else if ((r == 1 || type == "async") &&
cct->check_experimental_feature_enabled("ms-type-async"))
return new AsyncMessenger(cct, name, lname, nonce);
......
return NULL;
}
类AsyncMessenger的构造函数需要注意,虽然在osd进程的启动过程中,会创建6个messenger,但是他们全部共享一个StackSingleton(内含NetworkStack指针), 函数lookup_or_create_singleton_object保证只会创建一个StackSingleton,因为传入的名称"AsyncMessenger::NetworkStack::"+transport_type是一样的:
AsyncMessenger::AsyncMessenger(CephContext *cct, entity_name_t name, // 创建单例的StackSingleton,(内含NetworkStack指针) cct->lookup_or_create_singleton_object<StackSingleton>(single, "AsyncMessenger::NetworkStack::"+transport_type); |
下面的代码生成StackSingleton, if (!_associated_objs.count(name))下面的代码保证了同名的 StackSingleton只new一个
template<typename T>
void lookup_or_create_singleton_object(T*& p, const std::string &name) {
ceph_spin_lock(&_associated_objs_lock);
if (!_associated_objs.count(name)) {
p = new T(this);
_associated_objs[name] = new TypedSingletonWrapper<T>(p);
} else {
TypedSingletonWrapper<T> *wrapper =
dynamic_cast<TypedSingletonWrapper<T> *>(_associated_objs[name]);
assert(wrapper != NULL);
p = wrapper->singleton;
}
ceph_spin_unlock(&_associated_objs_lock);
}
另外需要注意,这个进程唯一的StackSingleton是在messenger(这里是AsyncMessenger)的构造函数分配的,messenger的析构函数并不负责释放内存,因为多个messenger共享&