sunku-cj:当 Redis 的 API 装进进程内
内容提要
sunku-cj 是仓颉生态中基于 badger-cj 的进程内 KV 数据库,API 与 Redis 高度同构,覆盖五种数据结构约 120 个方法,支持内存与持久化两种模式及 TTL。但它并非 Redis 替代品:仅限单进程使用,无法多进程共享;blpop 为轮询实现,延迟最多 100ms;TTL 仅惰性过期;多线程对同一 key 读改写可能丢更新。适合单进程缓存、CLI 工具和测试替身。
延伸解读
API 同构不等于架构同构
sunku-cj 的方法名、参数顺序和语义都照着 Redis 抄,约 120 个方法覆盖五种数据结构,迁移时业务逻辑几乎不用改。但它的架构位置与 Redis 完全不同:Redis 是网络服务,多进程共享同一份数据;sunku 是进程内库,每个进程各有一份、互不可见。因此不能把它当作 Redis 的替代品,而应视为 L1 本地缓存,Redis 仍适合做 L2 共享层。
三条边界比功能列表更值得先看
文章核对源码后指出三个实际限制:blpop 采用每 100ms 轮询,而非条件变量唤醒,做任务队列时延迟可感知;TTL 只有惰性过期,过期 key 会一直占磁盘直到被读到;多线程对同一 key 做 incr/zadd 这类读-改-写可能丢更新,因为读在事务外、冲突检测看不到。单线程或操作不同 key 则安全。
适用场景由“是否多进程共享”决定
只要程序自身是唯一使用者,sunku 就很合适:单进程本地缓存、CLI 工具状态存储、测试替身、离线数据处理临时工作区。反之,需要多进程共享状态、跨语言服务共享缓存、pub/sub、Lua 原子复合操作或主从集群高可用时,它都不适合。持久化模式复用 badger-cj,支持信号退出落盘,容器场景较实用。
Q&A
sunku-cj 是什么?它和 Redis 有什么关系?
sunku-cj 是仓颉生态中基于 badger-cj 的进程内 KV 数据库,其 API 与 Redis 高度同构,覆盖 String、Hash、List、Set、ZSet 五种数据结构约 120 个方法,方法名和参数顺序都模仿 Redis。但它不是 Redis 的替代品,而是进程内库,只能作为本地缓存使用。
sunku-cj 支持持久化吗?如何保证数据不丢失?
支持。sunku-cj 提供两种模式:纯内存模式(Sunku.memory())和持久化模式(Sunku.open("/data/db"))。持久化模式复用 badger-cj 的 LSM 存储,具备 WAL、SSTable、compaction 和优雅退出落盘能力。调用 registerSignalShutdown() 后,收到 SIGTERM 时会自动 flush 落盘再退出,适合容器环境。
sunku-cj 的 blpop 和 Redis 的 BLPOP 有什么区别?
Redis 的 BLPOP 是阻塞式,通过条件变量唤醒,有元素时立即返回;sunku-cj 的 blpop 采用轮询实现,每 100ms 检查一次,因此延迟最多增加 100ms。做任务队列时能感觉到这个差别,做普通缓存则影响不大。
sunku-cj 的 TTL 过期机制是怎样的?有什么隐患?
sunku-cj 只实现了惰性过期:读取时检查 expiresAt,过期则视作不存在。没有 Redis 的定期删除机制,因此已过期的 key 会一直占用磁盘,直到被访问。长期运行的缓存进程可能出现内存/磁盘只涨不落,需要自行扫描清理。
多线程环境下使用 sunku-cj 的 incr 安全吗?
不安全。sunku-cj 的 incr 等读-改-写操作在事务外读取当前值(db.get),写入在事务内(txn.setEntry),底层 badger-cj 的 SSI 冲突检测依赖事务内读集,事务外读不入账,因此多线程对同一 key 做 incr/zadd 可能丢更新。单线程或不同 key 操作则安全。
sunku-cj 适合哪些使用场景?
适合单进程程序的本地缓存(需要 TTL 和五种数据结构)、CLI 工具/脚本的状态存储、测试替身(用 Sunku.memory() 替代 Redis 免起容器)、离线数据处理临时工作区、单机边缘/嵌入式程序。不适合多进程共享状态、跨语言服务共享缓存、多线程高频更新同一计数器、需要 pub/sub 或 Lua 的场景。