资讯动态

从 hiredis 迁移到 libvalkey:Valkey C 客户端 API 迁移完全指南

发布时间:2026/9/10 14:05:21 来源:尧图企业网站定制
从 hiredis 迁移到 libvalkeyValkey C 客户端 API 迁移完全指南【免费下载链接】placeholderkvA flexible distributed key-value database that is optimized for caching and other realtime workloads.项目地址: https://gitcode.com/GitHub_Trending/pl/placeholderkvLibvalkey 是 Valkey 数据库的官方 C 客户端位于本仓库 deps/libvalkey 目录下可同时替代hiredis与hiredis-cluster两个库。本文以官方 migration-guide.md 为核心系统梳理从这两套旧 API 迁移到 libvalkey 所需的全部改动从命名前缀替换、头文件与构建选项调整到集群 API 的初始化方式重构、回调函数迁移以及多键命令路由行为的变更并补充仓库内 cluster.md、standalone.md、examples 与头文件中的完整示例作为对照。读完本文你将能够把基于 hiredis/hiredis-cluster 的存量 C 代码平滑升级到 libvalkey并理解新 API 背后的设计取舍。一、迁移背景为什么要迁移到 libvalkeyLibvalkey 是 Valkey 生态中的官方 C 客户端其功能定位在 README.md 中有明确描述它面向任何使用 RESP 协议v2 或 v3的服务器同时支持单机standalone与集群cluster两种模式提供同步与异步两套 API并可选支持 MPTCP、TLS 与 RDMA 连接。官方文档明确说明Libvalkey can replace both librarieshiredisandhiredis-cluster.因此迁移工作的总体目标是把原先基于 hiredis单机和 hiredis-cluster集群的代码统一到 libvalkey 的 API 上。整个迁移过程可归纳为四个通用动作替换命名前缀把 API 使用中的前缀redis全部替换为valkey例如redisConnect→valkeyConnect、redisCommand→valkeyCommand。替换安全通信术语将 API 中的SSL全部替换为TLS例如构建选项USE_SSL→USE_TLS。更新 include 路径libvalkey 的所有头文件统一位于include/valkey/目录下即#include valkey/valkey.h、#include valkey/cluster.h适配器位于#include valkey/adapters/xxx.h具体可参见 include/valkey 目录结构。更新构建选项例如USE_TLS取代USE_SSL详见下文构建章节。二、迁移前准备构建与安装 libvalkey迁移前需要先在目标环境构建并安装 libvalkey。根据 README.md库使用 C99 编写同时支持 GNU make 与 CMake 两种构建方式。使用 make 构建# 构建并安装默认库 sudo make install # 开启全部可选功能TLS 与 RDMA sudo USE_TLS1 USE_RDMA1 make install # 当 openssl 位于非默认路径时 sudo USE_TLS1 OPENSSL_PREFIX/path/to/openssl make install使用 CMake 构建mkdir build cd build cmake -DCMAKE_BUILD_TYPERelWithDebInfo .. sudo make install # 启用 TLS 与 RDMA 支持 cmake -DCMAKE_BUILD_TYPERelWithDebInfo -DENABLE_TLS1 -DENABLE_RDMA1 .. sudo make install可见单机make构建使用USE_TLS开关CMake 构建使用ENABLE_TLS开关——这正是迁移指南中USE_TLSreplacesUSE_SSL的实际含义。所有可用的 CMake 选项可参见 deps/libvalkey/CMakeLists.txt。TLS 支持默认不启用必须显式指定构建标志见 cluster.md 的 TLS 一节。三、从 hiredis v1.2.0 迁移单机模式对于单机模式迁移的核心是命名与类型的调整。3.1 sds 类型从公共 API 中移除sds类型已从公共 API 中移除。在旧版 hiredis 中redisFormatSdsCommandArgv等函数会返回sds字符串而迁移后这些接口不复存在sds仅供 libvalkey 内部使用源码中仍在 deps/libvalkey/src/cluster.c 内部大量使用 sds 来管理节点地址字符串但不再暴露给调用方。3.2 重命名的 API 函数旧 APIhiredis v1.2.0新 APIlibvalkey说明redisAsyncSetConnectCallbackNCvalkeyAsyncSetConnectCallback重命名且新函数接受非 const 的回调函数原型3.3 移除的 API 函数旧 API替代方案redisFormatSdsCommandArgvvalkeyFormatCommandArgv声明见 deps/libvalkey/include/valkey/valkey.h返回long long可直接构造 argv 形式的 RESP 命令redisFreeSdsCommand无直接替代sds类型已转为内部使用redisAsyncSetConnectCallbackvalkeyAsyncSetConnectCallback新函数接受非 const 回调原型3.4 重命名与移除的宏版本宏全部改名旧宏新宏HIREDIS_MAJORLIBVALKEY_VERSION_MAJORHIREDIS_MINORLIBVALKEY_VERSION_MINORHIREDIS_PATCHLIBVALKEY_VERSION_PATCH这些新宏在当前仓库中的实际值为0、5、0见 deps/libvalkey/include/valkey/valkey.h。同时HIREDIS_SONAME宏被移除不再提供 soname 相关的编译期定义。3.5 单机 API 迁移后的形态迁移后的单机 API 遵循valkey前缀与printf-like 调用风格。连接示例源自 standalone.mdvalkeyContext *ctx valkeyConnect(localhost, 6379); if (ctx NULL || ctx-err) { fprintf(stderr, Error connecting: %s\n, ctx ? ctx-errstr : OOM); }执行命令与处理回复valkeyReply *reply valkeyCommand(ctx, INCRBY %s %d, counter, 42); if (reply NULL) { fprintf(stderr, Communication error: %s\n, ctx-err ? ctx-errstr : Unknown error); } else if (reply-type VALKEY_REPLY_ERROR) { fprintf(stderr, Error response from server: %s\n, reply-str); } else if (reply-type ! VALKEY_REPLY_INTEGER) { // 非常不可能但应当检查 fprintf(stderr, Error: Non-integer reply to INCRBY?\n); } printf(New value of counter is %lld\n, reply-integer); freeReplyObject(reply);二进制安全内容使用%b格式符需要同时传入长度valkeyReply *reply valkeyCommand(ctx, SET %s %b, some-key, binary, sizeof(binary));完整的单机示例代码位于 deps/libvalkey/examples/blocking.c展示了valkeyConnectWithTimeout、valkeyCommand、valkeyCommandArgv、freeReplyObject、valkeyFree的完整用法。断开连接统一调用valkeyFree(ctx)。3.6 单机模式其它需要注意的行为差异多地址连接尝试当主机名解析出多个地址时libvalkey 会按顺序逐一尝试直到成功或全部失败connect_timeout按每个地址分别生效因此总连接时间可能达到 N × timeout见 standalone.md。回复类型系统回复类型从REDIS_REPLY_*相应变为VALKEY_REPLY_*并在 RESP3 基础上扩展出VALKEY_REPLY_DOUBLE、VALKEY_REPLY_BOOL、VALKEY_REPLY_VERB、VALKEY_REPLY_MAP、VALKEY_REPLY_SET、VALKEY_REPLY_ATTR、VALKEY_REPLY_PUSH等新类型完整列表见 standalone.md。错误码通信错误类型变为VALKEY_ERR_IO、VALKEY_ERR_EOF、VALKEY_ERR_PROTOCOL、VALKEY_ERR_TIMEOUT、VALKEY_ERR_OOM、VALKEY_ERR_OTHER。四、从 hiredis-cluster 0.14.0 迁移集群模式集群模式的迁移是重头戏涉及初始化方式、槽位映射更新机制、结构体布局、回调注册与命令路由等多个层面的变化。4.1 客户端初始化方式彻底改变集群客户端的初始化流程已改变旧式的先初始化 context、再逐步设置选项的流程被统一为通过valkeyClusterOptions结构体一次指定所有选项再创建 context。官方文档要求参考 Synchronous API 与 Asynchronous API 中的配置示例examples 目录下也包含常见客户端初始化示例。新的同步连接方式示例来自 deps/libvalkey/examples/cluster-simple.cstruct timeval timeout {1, 500000}; // 1.5s valkeyClusterOptions options {0}; options.initial_nodes 127.0.0.1:7000; options.connect_timeout timeout; valkeyClusterContext *cc valkeyClusterConnectWithOptions(options); if (!cc) { printf(Error: Allocation failure\n); exit(-1); } else if (cc-err) { printf(Error: %s\n, cc-errstr); exit(-1); } valkeyReply *reply valkeyClusterCommand(cc, SET %s %s, key, value); printf(SET: %s\n, reply-str); freeReplyObject(reply); valkeyReply *reply2 valkeyClusterCommand(cc, GET %s, key); printf(GET: %s\n, reply2-str); freeReplyObject(reply2); valkeyClusterFree(cc);valkeyClusterOptions结构体的完整字段定义在 deps/libvalkey/include/valkey/cluster.h核心字段包括字段说明initial_nodes初始连接的集群节点地址多个地址用逗号分隔如127.0.0.1:6379,127.0.0.1:6380optionsVALKEY_OPT_xxx标志的按位或组合connect_timeout连接超时为NULL时无超时command_timeout命令超时为NULL时无超时username/password使用AUTH命令认证的用户名与密码max_retry允许的重试次数select_db连接成功后选择的逻辑数据库默认 0 表示不发送SELECT命令event_callback/event_privdata集群级事件回调与用户私有数据connect_callback同步 API 的连接/重连钩子async_connect_callback/async_disconnect_callback异步 API 的连接/断开钩子tls/tls_init_fnTLS 上下文与初始化函数attach_fn/attach_data异步事件引擎的挂接函数与数据4.2 默认槽位映射更新命令变为 CLUSTER SLOTS更新内部槽位映射slot map / 集群拓扑的默认命令从CLUSTER NODES改为CLUSTER SLOTS。该行为在源码中有直接体现 deps/libvalkey/src/cluster.c 中定义了VALKEY_COMMAND_CLUSTER_SLOTS CLUSTER SLOTS并围绕其实现槽位更新逻辑。若仍需使用CLUSTER NODES可以通过选项VALKEY_OPT_USE_CLUSTER_NODES重新开启。可用的选项标志见 cluster.md 与 cluster.h标志说明VALKEY_OPT_USE_CLUSTER_NODES使用CLUSTER NODES命令更新槽位映射默认是CLUSTER SLOTSVALKEY_OPT_USE_REPLICAS保留解析得到的副本replica节点信息VALKEY_OPT_BLOCKING_INITIAL_UPDATE异步专用以阻塞方式执行首次槽位映射更新函数返回时 context 立即可用VALKEY_OPT_REUSEADDR设置SO_REUSEADDRsocket 选项VALKEY_OPT_PREFER_IPV4/VALKEY_OPT_PREFER_IPV6/VALKEY_OPT_PREFER_IP_UNSPEC控制getaddrinfo时优先 IPv4 / IPv6 / 同时搜索默认优先 IPv4VALKEY_OPT_MPTCP使用多路径 TCP需服务端与客户端均支持才建立 MPTCP 连接4.3 valkeyClusterAsyncContext 结构体布局变化valkeyClusterAsyncContext现在内嵌一个valkeyClusterContext而不是持有指向它的指针。所有原先的acc-cc用法必须替换为acc-cc。这一点可以从 deps/libvalkey/include/valkey/cluster.h 的结构体定义得到印证valkeyClusterContext cc;作为首个成员直接嵌入且errstr始终指向cc-errstr[]。因此迁移时把所有acc-cc改为acc-cc即可即取地址操作。4.4 重命名的 API 函数旧 API新 API说明ctx_get_by_nodevalkeyClusterGetValkeyContext获取与指定节点通信用的valkeyContext必要时自动连接/重连actx_get_by_nodevalkeyClusterGetValkeyAsyncContext获取与指定节点通信用的valkeyAsyncContext4.5 重命名的 API 宏节点角色旧宏新宏REDIS_ROLE_NULLVALKEY_ROLE_UNKNOWNREDIS_ROLE_MASTERVALKEY_ROLE_PRIMARYREDIS_ROLE_SLAVEVALKEY_ROLE_REPLICA新宏的实际定义可在 deps/libvalkey/include/valkey/cluster.h 中查看VALKEY_ROLE_UNKNOWN 0、VALKEY_ROLE_PRIMARY 1、VALKEY_ROLE_REPLICA 2。这套重命名反映了术语体系从 master/slave 到 primary/replica 的演进。4.6 移除的 API 函数及其替代方案旧 hiredis-cluster 中大量先初始化后设置风格的函数被移除全部收敛到valkeyClusterOptions结构体。完整对照如下源自 migration-guide.md移除的函数替代方案redisClusterConnect2valkeyClusterConnectWithOptionsredisClusterContextInitvalkeyClusterConnectWithOptionsredisClusterSetConnectCallbackvalkeyClusterOptions.connect_callbackredisClusterSetEventCallbackvalkeyClusterOptions.event_callbackredisClusterSetMaxRedirectvalkeyClusterOptions.max_retryredisClusterSetOptionAddNodevalkeyClusterOptions.initial_nodesredisClusterSetOptionAddNodesvalkeyClusterOptions.initial_nodesredisClusterSetOptionConnectBlock已废弃直接移除redisClusterSetOptionConnectNonBlock已废弃直接移除redisClusterSetOptionConnectTimeoutvalkeyClusterOptions.connect_timeoutredisClusterSetOptionMaxRetryvalkeyClusterOptions.max_retryredisClusterSetOptionParseSlavesvalkeyClusterOptions.optionsVALKEY_OPT_USE_REPLICASredisClusterSetOptionPasswordvalkeyClusterOptions.passwordredisClusterSetOptionRouteUseSlots默认即使用CLUSTER SLOTS无需设置redisClusterSetOptionUsernamevalkeyClusterOptions.usernameredisClusterAsyncConnectvalkeyClusterAsyncConnectWithOptionsVALKEY_OPT_BLOCKING_INITIAL_UPDATEredisClusterAsyncConnect2valkeyClusterAsyncConnectWithOptionsredisClusterAsyncContextInitvalkeyClusterAsyncConnectWithOptions会自动初始化 contextredisClusterAsyncSetConnectCallbackvalkeyClusterOptions.async_connect_callback接受非 const 回调原型redisClusterAsyncSetConnectCallbackNCvalkeyClusterOptions.async_connect_callbackredisClusterAsyncSetDisconnectCallbackvalkeyClusterOptions.async_disconnect_callbackparse_cluster_nodes移除仅限内部使用parse_cluster_slots移除仅限内部使用4.7 移除的 API 宏移除的宏替代方案HIRCLUSTER_FLAG_NULL无HIRCLUSTER_FLAG_ADD_SLAVEVALKEY_OPT_USE_REPLICAS选项HIRCLUSTER_FLAG_ROUTE_USE_SLOTS默认启用CLUSTER SLOTS无需设置4.8 异步连接与回调的迁移示例新的异步集群连接方式源自 deps/libvalkey/examples/cluster-async.c#include valkey/cluster.h #include valkey/adapters/libevent.h void getCallback(valkeyClusterAsyncContext *cc, void *r, void *privdata) { valkeyReply *reply (valkeyReply *)r; if (reply NULL) { if (cc-err) printf(errstr: %s\n, cc-errstr); return; } printf(privdata: %s reply: %s\n, (char *)privdata, reply-str); valkeyClusterAsyncDisconnect(cc); } void connectCallback(valkeyAsyncContext *ac, int status) { if (status ! VALKEY_OK) { printf(Error: %s\n, ac-errstr); return; } printf(Connected to %s:%d\n, ac-c.tcp.host, ac-c.tcp.port); } int main(void) { struct event_base *base event_base_new(); valkeyClusterOptions options {0}; options.initial_nodes 127.0.0.1:7000; options.async_connect_callback connectCallback; valkeyClusterOptionsUseLibevent(options, base); valkeyClusterAsyncContext *acc valkeyClusterAsyncConnectWithOptions(options); if (!acc) { /* 处理分配失败 */ } else if (acc-err) { /* 处理连接错误 */ } valkeyClusterAsyncCommand(acc, getCallback, (char *)THE_ID, GET %s, key); event_base_dispatch(base); valkeyClusterAsyncFree(acc); event_base_free(base); return 0; }注意点需要先用valkeyClusterOptionsUseLibevent(options, base)或其他适配器的等价便捷函数把事件循环实例挂到选项上再调用valkeyClusterAsyncConnectWithOptions。可用的事件库适配器见 deps/libvalkey/include/valkey/adapterslibev、libevent、libuv、glib、ivykis、libhv、libsdevent、macosx、poll、qt、valkeymoduleapi。由于首次槽位映射更新是异步进行的紧接着调用valkeyClusterAsyncConnectWithOptions之后发送的命令可能失败此时客户端尚不知道把命令发给哪个节点。解决办法有两种注册event_callback监听VALKEYCLUSTER_EVENT_READY事件或启用VALKEY_OPT_BLOCKING_INITIAL_UPDATE让首次更新以阻塞方式完成。集群级事件回调的event取值包括VALKEYCLUSTER_EVENT_SLOTMAP_UPDATED槽位映射已更新、VALKEYCLUSTER_EVENT_READY首次槽位映射获取完成、客户端就绪、VALKEYCLUSTER_EVENT_FREE_CONTEXTcontext 释放前可用于释放event_privdata。五、移除对多键命令按槽位拆分的支持这是行为层面的重大变化迁移时务必处理。自 hiredis-vip 时代起客户端支持把跨越多个槽位的多键命令DEL、EXISTS、MGET、MSET自动拆分成多条命令分别发送给各自槽位的负责节点。libvalkey 移除了这一能力因为该机制实现复杂且拆分会破坏原子性预期。官方建议的迁移动作发送受影响命令之前使用valkeyClusterGetSlotByKey按 key 计算槽位声明见 deps/libvalkey/include/valkey/cluster.h实现见 deps/libvalkey/src/cluster.c 中基于 CRC16 的槽位计算逻辑与 Valkey 服务端的 16384 个槽位划分保持一致。按槽位对 key 分组必要时构造新命令多次调用valkeyClusterCommand或等价函数分别发送。示意代码/* 将 keys 按槽位分组 */ for (size_t i 0; i nkeys; i) { unsigned int slot valkeyClusterGetSlotByKey(keys[i]); /* 把 keys[i] 加入 slot 对应的桶 */ } /* 对每个桶分别构造并发送 MGET */ for (每个槽位桶) { /* 构造该槽位内的命令 */ valkeyReply *reply valkeyClusterCommand(cc, MGET %s %s ..., k1, k2, ...); /* 合并/处理回复 */ freeReplyObject(reply); }六、迁移后的新特性概览集群模式迁移完成后可以从 libvalkey 的集群 API 中获得以下新能力详见 cluster.md自动重定向与重试valkeyClusterCommand会把命令发送到客户端认为负责该 key 的节点若拓扑已变化节点返回重定向错误客户端自动更新槽位映射并重发命令。若节点不可达命令超时/连接超时函数返回NULL并设置err/errstr同时安排下一次命令发送前更新槽位映射。指定节点执行命令valkeyClusterCommandToNode(cc, node, DBSIZE)只向指定节点发送命令不做重定向与重试但通信错误同样会触发槽位映射更新。管道pipeliningvalkeyClusterAppendCommand追加命令到输出缓冲区首次调用valkeyClusterGetReply时一次性交付整个缓冲区随后依次读取各条回复。节点迭代器valkeyClusterInitNodeIteratorvalkeyClusterNodeNext可遍历所有已知主节点槽位映射更新时迭代器会自动重启可通过比较iter.route_version与cc-route_version检测槽位映射是否更新。TLS 支持先valkeyInitOpenSSL()初始化 OpenSSL再valkeyCreateTLSContext(ca.crt, NULL, client.crt, client.key, NULL, NULL)创建 TLS 上下文最后通过valkeyClusterOptions.tls与tls_init_fn启用。命令表可扩展命令列表及每个命令首个 key 参数的位置定义在 deps/libvalkey/src/cmddef.h由 Valkey 仓库的 JSON 命令描述文件生成如需支持模块自定义命令可用 deps/libvalkey/scripts/gencommands.py 重新生成。七、迁移检查清单完成迁移前请逐项核对头文件所有#include hiredis/hiredis.h、#include hiredis/async.h、#include hiredis-cluster/cluster.h改为#include valkey/valkey.h、#include valkey/async.h、#include valkey/cluster.h异步事件库包含#include valkey/adapters/xxx.h。命名前缀全局搜索redis前缀的 APIredisConnect、redisCommand、redisAsyncCommand、redisReply、REDIS_REPLY_*、REDIS_ERR_*等并替换为valkey前缀。术语SSL→TLSredisSecureConnection类接口与构建选项。版本宏HIREDIS_MAJOR/MINOR/PATCH→LIBVALKEY_VERSION_MAJOR/MINOR/PATCH删除HIREDIS_SONAME的使用。sds 相关删除对redisFormatSdsCommandArgv、redisFreeSdsCommand的调用改用valkeyFormatCommandArgv等标准命令构造接口。集群初始化把所有redisClusterContextInitredisClusterSetOptionXxx序列改写为填充valkeyClusterOptions结构体 valkeyClusterConnectWithOptions/valkeyClusterAsyncConnectWithOptions。结构体布局所有acc-cc改为acc-cc。角色宏REDIS_ROLE_MASTER/SLAVE/NULL→VALKEY_ROLE_PRIMARY/REPLICA/UNKNOWN。多键命令对DEL、EXISTS、MGET、MSET先按valkeyClusterGetSlotByKey分组再发送杜绝依赖旧版自动拆分行为。构建USE_SSL→USE_TLSmake或ENABLE_TLSCMake按需追加USE_RDMA/ENABLE_RDMA与OPENSSL_PREFIX。按照上述清单逐项改造后原有 hiredis / hiredis-cluster 代码即可平滑运行在 libvalkey 之上同时建议对照 migration-guide.md、cluster.md、standalone.md 三份官方文档与 examples 目录中的可运行示例做最终验证。【免费下载链接】placeholderkvA flexible distributed key-value database that is optimized for caching and other realtime workloads.项目地址: https://gitcode.com/GitHub_Trending/pl/placeholderkv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价