valkey之网络管理架构深度解析

一、连接类型实现体系

valkey通过ConnectionType结构体构建了灵活的网络连接抽象,支持多种连接类型的统一管理。每种连接类型都通过填充该结构体的函数指针来实现特定功能,形成了面向接口的设计模式。

1.1 socket连接

Socket连接提供了最基础的TCP/IP通信能力,实现了全部连接与IO操作接口,是valkey网络通信的基础实现。

src/socket.c

c 复制代码
static ConnectionType CT_Socket = {
    /* connection type */
    .get_type = connSocketGetType,

    /* connection type initialize & finalize & configure */
    .init = NULL,
    .cleanup = NULL,
    .configure = NULL,

    /* ae & accept & listen & error & address handler */
    .ae_handler = connSocketEventHandler,
    .accept_handler = connSocketAcceptHandler,
    .addr = connSocketAddr,
    .is_local = connSocketIsLocal,
    .listen = connSocketListen,
    .closeListener = connSocketCloseListener,

    /* create/shutdown/close connection */
    .conn_create = connCreateSocket,
    .conn_create_accepted = connCreateAcceptedSocket,
    .shutdown = connSocketShutdown,
    .close = connSocketClose,

    /* connect & accept */
    .connect = connSocketConnect,
    .blocking_connect = connSocketBlockingConnect,
    .accept = connSocketAccept,

    /* IO */
    .write = connSocketWrite,
    .writev = connSocketWritev,
    .read = connSocketRead,
    .set_write_handler = connSocketSetWriteHandler,
    .set_read_handler = connSocketSetReadHandler,
    .get_last_error = connSocketGetLastError,
    .sync_write = connSocketSyncWrite,
    .sync_read = connSocketSyncRead,
    .sync_readline = connSocketSyncReadLine,

    /* pending data */
    .has_pending_data = NULL,
    .process_pending_data = NULL,
    .postpone_update_state = NULL,
    .update_state = NULL,

    /* Miscellaneous */
    .connIntegrityChecked = NULL,
};

int RedisRegisterConnectionTypeSocket(void) {
    return connTypeRegister(&CT_Socket);
}

1.2 unix域套接字

Unix域套接字专注于本地进程间通信,省略了网络连接相关的接口,优化了本地通信的性能。

src/unix.c

c 复制代码
static ConnectionType CT_Unix = {
    /* connection type */
    .get_type = connUnixGetType,

    /* connection type initialize & finalize & configure */
    .init = NULL,
    .cleanup = NULL,
    .configure = NULL,

    /* ae & accept & listen & error & address handler */
    .ae_handler = connUnixEventHandler,
    .accept_handler = connUnixAcceptHandler,
    .addr = connUnixAddr,
    .is_local = connUnixIsLocal,
    .listen = connUnixListen,
    .closeListener = connUnixCloseListener,

    /* create/shutdown/close connection */
    .conn_create = connCreateUnix,
    .conn_create_accepted = connCreateAcceptedUnix,
    .shutdown = connUnixShutdown,
    .close = connUnixClose,

    /* connect & accept */
    .connect = NULL,
    .blocking_connect = NULL,
    .accept = connUnixAccept,

    /* IO */
    .write = connUnixWrite,
    .writev = connUnixWritev,
    .read = connUnixRead,
    .set_write_handler = connUnixSetWriteHandler,
    .set_read_handler = connUnixSetReadHandler,
    .get_last_error = connUnixGetLastError,
    .sync_write = connUnixSyncWrite,
    .sync_read = connUnixSyncRead,
    .sync_readline = connUnixSyncReadLine,

    /* pending data */
    .has_pending_data = NULL,
    .process_pending_data = NULL,
    .postpone_update_state = NULL,
    .update_state = NULL,

    /* Miscellaneous */
    .connIntegrityChecked = NULL,
};

int RedisRegisterConnectionTypeUnix(void) {
    return connTypeRegister(&CT_Unix);
}

1.3 tls加密连接

TLS连接增加了加密相关的初始化、清理和配置接口,提供了证书处理和加密数据传输能力,是安全通信的实现。

src/tls.c

c 复制代码
static ConnectionType CT_TLS = {
    /* connection type */
    .get_type = connTLSGetType,

    /* connection type initialize & finalize & configure */
    .init = tlsInit,
    .cleanup = tlsCleanup,
    .configure = tlsConfigure,

    /* ae & accept & listen & error & address handler */
    .ae_handler = tlsEventHandler,
    .accept_handler = tlsAcceptHandler,
    .addr = connTLSAddr,
    .is_local = connTLSIsLocal,
    .listen = connTLSListen,
    .closeListener = connTLSCloseListener,

    /* create/shutdown/close connection */
    .conn_create = connCreateTLS,
    .conn_create_accepted = connCreateAcceptedTLS,
    .shutdown = connTLSShutdown,
    .close = connTLSClose,

    /* connect & accept */
    .connect = connTLSConnect,
    .blocking_connect = connTLSBlockingConnect,
    .accept = connTLSAccept,

    /* IO */
    .read = connTLSRead,
    .write = connTLSWrite,
    .writev = connTLSWritev,
    .set_write_handler = connTLSSetWriteHandler,
    .set_read_handler = connTLSSetReadHandler,
    .get_last_error = connTLSGetLastError,
    .sync_write = connTLSSyncWrite,
    .sync_read = connTLSSyncRead,
    .sync_readline = connTLSSyncReadLine,

    /* pending data */
    .has_pending_data = tlsHasPendingData,
    .process_pending_data = tlsProcessPendingData,
    .postpone_update_state = postPoneUpdateSSLState,
    .update_state = updateSSLState,

    /* TLS specified methods */
    .get_peer_cert = connTLSGetPeerCert,

    /* Miscellaneous */
    .connIntegrityChecked = connTLSIsIntegrityChecked,
};

int RedisRegisterConnectionTypeTLS(void) {
    return connTypeRegister(&CT_TLS);
}

1.4 rdma高性能连接

RDMA连接针对高性能计算场景设计,提供了低延迟的数据传输能力,包含了特殊的状态管理接口。

src/rdma.c

c 复制代码
static ConnectionType CT_RDMA = {
    /* connection type */
    .get_type = connRdmaGetType,

    /* connection type initialize & finalize & configure */
    .init = rdmaInit,
    .cleanup = NULL,

    /* ae & accept & listen & error & address handler */
    .ae_handler = connRdmaEventHandler,
    .accept_handler = connRdmaAcceptHandler,
    //.cluster_accept_handler = NULL,
    .is_local = connRdmaIsLocal,
    .listen = connRdmaListen,
    .closeListener = connRdmaCloseListener,
    .addr = connRdmaAddr,

    /* create/close connection */
    .conn_create = connCreateRdma,
    .conn_create_accepted = connCreateAcceptedRdma,
    .shutdown = connRdmaShutdown,
    .close = connRdmaClose,

    /* connect & accept */
    .connect = connRdmaConnect,
    .blocking_connect = connRdmaBlockingConnect,
    .accept = connRdmaAccept,

    /* IO */
    .write = connRdmaWrite,
    .writev = connRdmaWritev,
    .read = connRdmaRead,
    .set_write_handler = connRdmaSetWriteHandler,
    .set_read_handler = connRdmaSetReadHandler,
    .get_last_error = connRdmaGetLastError,
    .sync_write = connRdmaSyncWrite,
    .sync_read = connRdmaSyncRead,
    .sync_readline = connRdmaSyncReadLine,

    /* pending data */
    .has_pending_data = rdmaHasPendingData,
    .process_pending_data = rdmaProcessPendingData,
    .postpone_update_state = postPoneUpdateRdmaState,
    .update_state = updateRdmaState,

    /* Miscellaneous */
    .connIntegrityChecked = NULL,
};

int RegisterConnectionTypeRdma(void) {
    return connTypeRegister(&CT_RDMA);
}

二、连接类型注册流程

2.1 注册调用链

c 复制代码
src/server.c
main
  |   src/connection.c
  |--> connTypeInitialize

2.2 注册实现

src/connection.c

c 复制代码
int connTypeInitialize(void) {
    /* currently socket connection type is necessary  */
    serverAssert(RedisRegisterConnectionTypeSocket() == C_OK);

    /* currently unix socket connection type is necessary  */
    serverAssert(RedisRegisterConnectionTypeUnix() == C_OK);

    /* may fail if without BUILD_TLS=yes */
    RedisRegisterConnectionTypeTLS();

    /* may fail if without BUILD_RDMA=yes */
    RegisterConnectionTypeRdma();

    return C_OK;
}

这种注册机制实现了:​

  • 核心连接类型的强制注册(Socket和Unix)
  • 可选连接类型的条件注册(TLS和RDMA)
  • 编译时决定是否支持特定连接类型的灵活性

三、监听器初始化流程

监听器初始化是valkey网络服务启动的关键步骤,负责根据配置创建并激活各类连接的监听机制。

3.1 初始化调用链

c 复制代码
src/server.c
main
  |   src/config.c
  |--> loadServerConfig
  |
  |    src/server.c
  |--> initListeners

3.2 初始化实现

根据不同的配置,初始化不同的监听器。

c 复制代码
void initListeners(void) {
    /* Setup listeners from server config for TCP/TLS/Unix */
    int conn_index;
    connListener *listener;
    if (server.port != 0) {
        conn_index = connectionIndexByType(CONN_TYPE_SOCKET);
        if (conn_index < 0) serverPanic("Failed finding connection listener of %s", CONN_TYPE_SOCKET);
        listener = &server.listeners[conn_index];
        listener->bindaddr = server.bindaddr;
        listener->bindaddr_count = server.bindaddr_count;
        listener->port = server.port;
        listener->ct = connectionByType(CONN_TYPE_SOCKET);
    }

    if (server.tls_port || server.tls_replication || server.tls_cluster) {
        ConnectionType *ct_tls = connectionTypeTls();
        if (!ct_tls) {
            serverLog(LL_WARNING, "Failed finding TLS support.");
            exit(1);
        }
        if (connTypeConfigure(ct_tls, &server.tls_ctx_config, 1) == C_ERR) {
            serverLog(LL_WARNING, "Failed to configure TLS. Check logs for more info.");
            exit(1);
        }
    }

    if (server.tls_port != 0) {
        conn_index = connectionIndexByType(CONN_TYPE_TLS);
        if (conn_index < 0) serverPanic("Failed finding connection listener of %s", CONN_TYPE_TLS);
        listener = &server.listeners[conn_index];
        listener->bindaddr = server.bindaddr;
        listener->bindaddr_count = server.bindaddr_count;
        listener->port = server.tls_port;
        listener->ct = connectionByType(CONN_TYPE_TLS);
    }
    if (server.unixsocket != NULL) {
        conn_index = connectionIndexByType(CONN_TYPE_UNIX);
        if (conn_index < 0) serverPanic("Failed finding connection listener of %s", CONN_TYPE_UNIX);
        listener = &server.listeners[conn_index];
        listener->bindaddr = &server.unixsocket;
        listener->bindaddr_count = 1;
        listener->ct = connectionByType(CONN_TYPE_UNIX);
        listener->priv = &server.unix_ctx_config; /* Unix socket specified */
    }

    if (server.rdma_ctx_config.port != 0) {
        conn_index = connectionIndexByType(CONN_TYPE_RDMA);
        if (conn_index < 0) serverPanic("Failed finding connection listener of %s", CONN_TYPE_RDMA);
        listener = &server.listeners[conn_index];
        listener->bindaddr = server.rdma_ctx_config.bindaddr;
        listener->bindaddr_count = server.rdma_ctx_config.bindaddr_count;
        listener->port = server.rdma_ctx_config.port;
        listener->ct = connectionByType(CONN_TYPE_RDMA);
        listener->priv = &server.rdma_ctx_config;
    }

    /* create all the configured listener, and add handler to start to accept */
    int listen_fds = 0;
    for (int j = 0; j < CONN_TYPE_MAX; j++) {
        listener = &server.listeners[j];
        if (listener->ct == NULL) continue;

        if (connListen(listener) == C_ERR) {
            serverLog(LL_WARNING, "Failed listening on port %u (%s), aborting.", listener->port,
                      listener->ct->get_type(NULL));
            exit(1);
        }

        if (createSocketAcceptHandler(listener, connAcceptHandler(listener->ct)) != C_OK)
            serverPanic("Unrecoverable error creating %s listener accept handler.", listener->ct->get_type(NULL));

        listen_fds += listener->count;
    }

    if (listen_fds == 0) {
        serverLog(LL_WARNING, "Configured to not listen anywhere, exiting.");
        exit(1);
    }
}

四、抽象连接层设计

valkey通过connection.h头文件定义了抽象连接层的接口,实现了对各类连接的统一操作,体现了面向对象的多态特性。

4.1 统一接口设计

src/connection.h

c 复制代码
...

static inline int connWritev(connection *conn, const struct iovec *iov, int iovcnt) {
    return conn->type->writev(conn, iov, iovcnt);
}

static inline int connRead(connection *conn, void *buf, size_t buf_len) {
    int ret = conn->type->read(conn, buf, buf_len);
    return ret;
}

...

4.2 多态实现机制

抽象连接层通过函数指针实现了多态:​

  • 上层代码使用统一的connReadconnWritev等接口
  • 实际执行时根据conn->type指向的具体连接类型,调用对应的实现函数
  • 新增连接类型时,只需实现ConnectionType结构体的函数,无需修改上层逻辑

这种设计带来的优势:​

  • 接口与实现分离,降低模块间耦合
  • 便于扩展新的连接类型
  • 保持上层代码的稳定性
  • 统一的错误处理和状态管理

五、架构设计亮点​

模块化设计: 每种连接类型作为独立模块实现,便于维护和扩展​
条件编译支持: 通过编译选项控制TLS、RDMA等可选模块的编译和注册​
统一抽象层: 通过函数指针实现多态,简化上层使用​
渐进式初始化: 从连接注册到监听器启动,形成完整的初始化流程​
灵活的配置体系: 支持多种连接类型的并行配置和启动​

valkey的网络管理架构通过这种分层抽象和接口统一,既保证了底层实现的灵活性,又为上层提供了简单一致的使用方式,是高性能网络服务的典型设计模式。

相关推荐
亚林瓜子2 个月前
AWS EC2源代码安装valkey命令行客户端
redis·云计算·aws·cli·valkey