在上一篇博客中我们详细描述了MetaServer处理客户端请求流程。承接上篇,今天主要来描述MetaServer如何处理ChunkServer请求。
因为MetaServer处理ChunkServer和处理客户端请求流程极其相似,所以可以先浏览前一篇文章,帮组应该会很大。两者主要区别在于在处理ChunkServer请求时,MetaServer并未采取类似处理客户端请求的Master + worker线程的模式,所有ChunkServer请求都在Master进程中处理,之所以这样做我想是因为ChunkServer的请求处理逻辑相对比较简单,不会阻塞。
数据结构
ChunkServerFactory
其角色可简单类比ClientManager。负责监听来自ChunkServer的新连接请求,并在收到连接时触发预先设置的回调函数,话不多说,先上代码:
class ChunkServerFactory : public IAcceptorOwner
{
...
private:
Acceptor* mAcceptor;
};根据我们之前的分析,由于继承了IAcceptorOwner,因此,当新连接到来时便会触发回调函数CreateKfsCallbackObj。
ChunkServer
class ChunkServer :
public KfsCallbackObj,
public CSMapServerInfo,
private SslFilterVerifyPeer,
public boost::enable_shared_from_this<ChunkServer>
{
...
int HandleMsg(IOBuffer *iobuf, int msgLen);
/// Handlers for the 3 types of messages we could get:
/// 1. Hello message from a chunkserver
/// 2. An RPC from a chunkserver
/// 3. A reply to an RPC that we have sent previously.
int HandleHelloMsg(IOBuffer *iobuf, int msgLen);
int HandleCmd(IOBuffer *iobuf, int msgLen);
int HandleReply(IOBuffer *iobuf, int msgLen);
/// Send a response message to the MetaRequest we got.
bool SendResponse(MetaRequest *op);
...
}ChunkServer可类比前文提到的ClientSM。MetaServer每收到一个来自新ChunkServer的连接便会创建一个该对象。由于MetaServer处理ChunkServer没有采用Master + worker线程的机制,因此,每个新连接上的Request都是由主进程来处理。而chunkServer则主要是维护该连接对应的ChunkServer状态。
核心流程
接收ChunkServer新连接
Master进程负责接收客户端上的新的连接。ChunkServerFactory内负责监听网络端口以及接收新连接的是成员Acceptor。关键的API如下:
bool ChunkServerFactory::Bind()
bool ChunkServerFactory::StartAcceptor()当Acceptor接收到一个新的连接时,会触发Acceptor的回调函数:Acceptor::RecvConnection。在这里会调用其拥有者(也即ChunkServerFactory对象)的回调:mAcceptorOwner->CreateKfsCallbackObj(conn)。
Acceptor::Acceptor(
NetManager& netManager,
const ServerLocation& location,
bool ipV6OnlyFlag,
IAcceptorOwner* owner,
bool bindOnlyFlag)
: mLocation(location),
mIpV6OnlyFlag(ipV6OnlyFlag),
mAcceptorOwner(owner),
mConn(),
mNetManager(netManager)
{
SET_HANDLER(this, &Acceptor::RecvConnection);
Acceptor::Bind();
if (! bindOnlyFlag) {
Acceptor::StartListening();
}
}
int
Acceptor::RecvConnection(int code, void* data)
{
switch (code) {
case EVENT_NEW_CONNECTION:
break;
......
}
NetConnectionPtr& conn = *reinterpret_cast<NetConnectionPtr*>(data);
KfsCallbackObj* const obj = mAcceptorOwner->CreateKfsCallbackObj(conn);
if (conn) {
if (obj) {
conn->SetOwningKfsCallbackObj(obj);
mNetManager.AddConnection(conn);
} else {
conn->Close();
}
}
return 0;
}接收到一个新的Connection的关键在于mAcceptorOwner->CreateKfsCallbackObj(conn)。对于MetaServer来说,其管理ChunkServer连接的类是ChunkServerFactory,因此,mAcceptorOwner->CreateKfsCallbackObj实现是:
KfsCallbackObj *ChunkServerFactory::CreateKfsCallbackObj(NetConnectionPtr &conn)
{ return ChunkServer::Create(conn); }可以看到,对于一个新连接,会直接创建一个chunkServer对象来管理。
/* static */ KfsCallbackObj*
ChunkServer::Create(const NetConnectionPtr& conn)
{
...
return CreateSelf(conn, ServerLocation());
}
/* static */ ChunkServer*
ChunkServer::CreateSelf(const NetConnectionPtr& conn, const ServerLocation& loc)
{
...
ChunkServer& srv = *(new ChunkServer(
conn,
conn->IsGood() ? conn->GetPeerName() : string("replay"),
! conn->IsGood()
));
...
}
ChunkServer::ChunkServer(
const NetConnectionPtr& conn,
const string& peerName,
bool replayFlag)
: KfsCallbackObj(),
...
{
...
// 设置了该ChunkServer连接上请求到来时的回调函数
SET_HANDLER(this, &ChunkServer::HandleRequest);
// 加入至全局的chunkserver队列中
ChunkServersList::PushBack(sChunkServersPtr, *this);
...
}ChunkServer对象和Connection一一对应。且在创建该对象的时候,设置了连接的事件触发回调函数chunkServer::HandleRequest。
接收ChunkServer请求
每个ChunkServer连接上一旦有新的请求到来时便触发预先设置的回调函数ChunkServer::HandleRequest。在这里会从连接上读取并解析命令。一旦完整命令解析完毕,最终会将命令通过ChunkServer::HandleMsg提交。
int
ChunkServer::HandleRequest(int code, void *data)
{
switch (code) {
case EVENT_NET_READ: {
...
while ((gotMsgHdr = mHelloOp || IsMsgAvail(&iobuf, &msgLen))) {
const int retval = HandleMsg(&iobuf, msgLen);
}
...
}
...
}处理请求
int
ChunkServer::HandleMsg(IOBuffer *iobuf, int msgLen)
{
...
return HandleCmd(iobuf, msgLen);
}
int
ChunkServer::HandleCmd(IOBuffer* iobuf, int msgLen)
{
...
op->clnt = this;
if (sMaxPendingOpsCount <= mPendingOpsCount) {
...
} else {
...
Submit(*op);
}
return 0;
}
inline void
ChunkServer::Submit(MetaRequest& op)
{
submit_request(&op);
}submit_request()流程已经在前面分析得比较透彻。与客户端请求在工作线程处理不同的是,来自ChunkServer的请求则是直接在Master进程中被处理,了解这点就可以了。
请求处理完成,返回响应
而请求一旦处理完成后,会调用MetaRequest::SubmitEnd来收尾工作。这里的收尾工作主要是要将处理结果调度返回给ChunkServer,其主要的调用流程是:
MetaRequest::SubmitEnd()
--->NetDispatch::Dispatch()
--->ChunkServer::HandleRequest(EVENT_CMD_DONE, r)
int
ChunkServer::HandleRequest(int code, void *data)
{
...
switch (code) {
...
case EVENT_CMD_DONE: {
MetaRequest* const op = reinterpret_cast<MetaRequest*>(data);
...
if (SendResponse(op) && deleteOpFlag) {
MetaRequest::Release(op);
}
break;
}
}最终直接在这里面给ChunkServer返回了响应。这样,MetaServer处理来自ChunkServer请求、发送响应等流程已经非常清晰。