layout: post title: predixy代码走读 categories: [database] tags: [proxy,redis,predixy]


我发现很多公司用redis proxy,开源选型都用了predixy,所以来读一读

入口是handler->run函数

    Request::init();
    Response::init();
    auto conf = mProxy->conf();
    refreshServerPool();
    while (!mStop) {
        mEventLoop->wait(100000, this);
        postEvent();
        long timeout = conf->clientTimeout();
        if (timeout > 0) {
            int num = checkClientTimeout(timeout);
            if (num > 0) {
                postEvent();
            }
        }
        refreshServerPool();
        checkConnectionPool();
        timeout = mProxy->serverPool()->serverTimeout();
        if (timeout > 0) {
            int num = checkServerTimeout(timeout);
            if (num > 0) {
                postEvent();
            }
        }
    }

其中 eventloop的wait是epoll_wait的封装

template<class T>
int EpollMultiplexor::wait(long usec, T* handler)
{
    int timeout = usec < 0 ? usec : usec / 1000;
    logVerb("epoll wait with timeout %ld usec", usec);
    int num = epoll_wait(mFd, mEvents, MaxEvents, timeout);
    logVerb("epoll wait return with event count:%d", num);
    if (num == -1) {
        if (errno == EINTR) {
            return 0;
        }
        Throw(EpollWaitFail, "handler %d epoll wait fail %s", handler->id(), StrError());
    }
    for (int i = 0; i < num; ++i) {
        Socket* s = static_cast<Socket*>(mEvents[i].data.ptr);
        int evts = 0;
        evts |= (mEvents[i].events & EPOLLIN) ? ReadEvent : 0;
        evts |= (mEvents[i].events & EPOLLOUT) ? WriteEvent : 0;
        evts |= (mEvents[i].events & (EPOLLERR|EPOLLHUP)) ? ErrorEvent : 0;
        handler->handleEvent(s, evts);
    }
    return num;
}

hanldeEvent根据来的连接类型,处理不同的connect,listen,accept和connect(主要是后面这俩)

如果是读事件,就直接读了,一口气读完?readEvent

主要是把epoll拿到的fd和事件进行处理,标记,主要是addPostEvent来做,标记之后,真正的epoll_ctl动作封装在postEvent中,内部有postConnectConnectionEvent和postAcceptConnectionEvent来处理

在这样框架下,主要的工作就在于维护内部的数据

转发,有接收前端消息有发送后端消息

  • PostConnectConn的列表,PostAcceptConnect的列表,主要是addPostEvent和PostEvent来维护改动
  • epoll_wait拿到的事件属性也保存了,根据这个属性,在post函数中处理,如果是写事件,一次写不完,重新加数据,下次写。总之不要出现互相影响(一个重要的优化点)
    • 在处理期间会检测这个connect是不是正常的,不正常直接修改成err
  • PostConnectConn针对不同的命令区分成共用的和私有的
ref
  1. https://github.com/joyieldInc/predixy