一、連接類型實現體系
valkey通過ConnectionType
結構體構建了靈活的網絡連接抽象,支持多種連接類型的統一管理。每種連接類型都通過填充該結構體的函數指針來實現特定功能,形成了面向接口的設計模式。
1.1 socket連接
Socket連接提供了最基礎的TCP/IP通信能力,實現了全部連接與IO操作接口,是valkey網絡通信的基礎實現。
src/socket.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
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
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
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 注冊調用鏈
src/server.c
main| src/connection.c|--> connTypeInitialize
2.2 注冊實現
src/connection.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 初始化調用鏈
src/server.c
main| src/config.c|--> loadServerConfig|| src/server.c|--> initListeners
3.2 初始化實現
根據不同的配置,初始化不同的監聽器。
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
...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 多態實現機制
抽象連接層通過函數指針實現了多態:?
- 上層代碼使用統一的
connRead
、connWritev
等接口? - 實際執行時根據
conn->type
指向的具體連接類型,調用對應的實現函數? - 新增連接類型時,只需實現
ConnectionType
結構體的函數,無需修改上層邏輯?
這種設計帶來的優勢:?
- 接口與實現分離,降低模塊間耦合?
- 便于擴展新的連接類型?
- 保持上層代碼的穩定性?
- 統一的錯誤處理和狀態管理
五、架構設計亮點?
模塊化設計: 每種連接類型作為獨立模塊實現,便于維護和擴展?
條件編譯支持: 通過編譯選項控制TLS、RDMA等可選模塊的編譯和注冊?
統一抽象層: 通過函數指針實現多態,簡化上層使用?
漸進式初始化: 從連接注冊到監聽器啟動,形成完整的初始化流程?
靈活的配置體系: 支持多種連接類型的并行配置和啟動?
valkey的網絡管理架構通過這種分層抽象和接口統一,既保證了底層實現的靈活性,又為上層提供了簡單一致的使用方式,是高性能網絡服務的典型設計模式。