老大,我也开发了个轻论坛程序,在你这里曝曝光热
- flinthub2026-09-03
- bbs1org2026-09-03
支持一下,鼓励发布啊。做好了,为啥不发布
彻底剥离 MySQL,全部数据由纯 SQLite 分片引擎(SplitDB)承载,从"单库单表"升级为"分片 + 索引 + 缓存"的架构,在保留 PHP 极简部署优势的同时,解决了大数据量下的性能问题
这个可以展开说说吗
- flinthub2026-09-03
这个我发布在github上了,从设计白皮书到落地实测代码,不过这个splitdb代码,现在只是用在我的程序上,没法做成通用的。
(白皮书)https://github.com/flinthub-top/SplitDB-DOCS
(SplitDB代码仓库)https://github.com/flinthub-top/SplitDB-CORE
你有兴趣可以看看先。点赞与点评1flinthub2026-09-09
- flinthub2026-09-03
二、核心架构:SplitDB 纯 SQLite 分片引擎
2.1 数据分层
data/ ├── meta/ # 元数据层(SQLite 库) │ ├── business.sqlite # 非分片业务:用户/版块/设置/博客/私信/附件/标签/投票 │ ├── main_index.sqlite # 帖子主索引 topic_index(19.2万行) + 回复定位索引 reply_index(16万行) │ ├── search/ # 搜索索引季度分文件 search_{YYYYQn}.sqlite(4 文件,235 万行) │ ├── global_id.sqlite # 全局 ID 生成器(topic/reply 原子取号游标) │ ├── sessions.sqlite # 会话存储(SQLite handler) │ └── task_queue/queue_{0..2}.sqlite # 异步任务队列(三队列打散锁竞争) ├── bucket/active/{季度}/{0..31}.sqlite # 帖子/回复真相源(季度时序 + ID2 哈希分桶) ├── bucket/archive/ # 18 个月以上冷数据归档桶 └── extern/{年}/{季}/{桶}/ # 正文外置:存量 .bin/.idx 偏移索引,新帖 .txt(读取自动回退)2.2 分片与路由规则(ShardRouter)
- 一级分区:季度时序分区(
YYYYQn,如 2026Q3),新数据写入当前季度; - 二级分区:哈希分桶(默认 32 桶),写入路由 =
ID % 桶数量; - 读取永远以
main_index.bucket_path为准,不再二次哈希;未来季度可平滑升级 32 → 64 → 128 桶,历史数据零迁移。
2.3 写入与读取链路
写入 = global_id 原子取号 → 季度分区 + ID2 哈希 → extern 正文原子写(tmp+rename) → 桶 topic/reply 真相源 → main_index 索引行(最终一致性,队列可选) 读取 = 列表/分页走 main_index(索引行含 bucket_path)→ 详情读桶 + extern(.bin/.idx 优先,缺失回退 .txt) 搜索 = 自研 bigram 倒排索引(季度分文件,SearchIndexStore)2.4 引擎关键组件(app/SplitDB/)
组件 职责 亮点 DBFactorySQLite 连接池 单进程 LRU 最大 8 句柄,统一 6 条 PRAGMA(WAL/busy\_timeout),禁持久连接 IDGenerator全局 ID 生成 BEGIN IMMEDIATE写锁事务原子取号(兼容无 RETURNING 的 SQLite 3.33)ShardRouter分片路由 季度 + 哈希双级分区,路径推导唯一依据 ExternStorage正文外置存储 tmp+rename 原子写;存量 .bin/.idx 偏移索引(fseek 定位,懒加载);编辑后作废 .idx 条目回退 .txt(修复虚拟主机编辑不生效) Queue / QueueConsumer异步任务队列 三队列打散锁竞争;CAS 抢占/超时恢复/重试上限;sync/cron/cli 三模式 Schema初始化与种子 幂等 bootstrap(目录树 + 8 库 + 22 表 + 默认种子) ViewCounter浏览计数 APCu 内存计数 + shutdown 批量落库;无 APCu 静默降级为直写 UPDATE(不崩站) SearchIndexStore搜索索引 季度分文件存储,与 business 库物理隔离(P21 瘦身 306MB → 19MB) 2.5 事务与一致性
- 桶写入用原始 SQL
exec('BEGIN')/exec('COMMIT');business 库用beginTransaction()/commit(),二者不混用; - 正文外置红线:先原子写 extern → 再写索引行,绝不允许"索引导入成功但正文丢失"(迁移故障注入已验证);
- 计数延迟合并:统计/浏览数先走内存/APCu 计数,请求结束时批量写回,把写放大钉死在量化边界。
点赞与点评1flinthub2026-09-09
- 一级分区:季度时序分区(
- bbs1org2026-09-03
支持技术研究。我让ai分析了下,她说:这些零件都是在尽量减轻写打架,但没有从根上干掉 SQLite 本身的短板。就像把一间屋子拆成好多小房间,吵架抢位置的概率变小了,但每个小房间同一时间还是只能有一个人往里写东西,人挤爆了照样排队卡壳。同一个分片 db 文件,同一时刻依旧只能有 1 个写事务。WAL 只是读写互不阻塞,写‑写之间依然互斥。一堆请求同时往同一个分片发帖,还是排队 busy。拿 ID 本身就是一次写;大量并发抢 ID,会在同一个库文件上抢锁,出现等待。只是保证不出错,不能变快。
老奶奶总结版
后生啊,这套东西把能想到的小聪明全都用上了:东西分开装、重活往后挪、小账先记在脑子攒一堆再记账。
可是每家小本子(每个 db 文件),同一时间只能一个人往上面写字。大家偏偏都抢着往同一本本子写的时候,照样挤成一团。能扛得住中等热闹,但是扛不住人山人海挤爆场子。 - bbs1org2026-09-03
- flinthub2026-09-03
- flinthub2026-09-03
我让我的AI写了一个反驳你的,哈哈:
反驳:单写者是引擎事实,但“扛不住人山人海”不是它的推论
一、先接住他对的部分,避免抬杠
他说对了三件事:
- 单个 SQLite 文件同一时刻只有一个写事务;
- WAL 只解决“读不挡写”,不解决“写挡写”;
- 全局取 ID 本身也是一次写。
这三条在任何 SQLite 项目里都成立,SplitDB 没有假装它们不存在——但 “单文件串行”是单文件的属性,不是系统的吞吐上限。系统写吞吐 = 并行可写文件数 × 单文件速率 × 事务薄厚度。他的论证缺的正是后面这三个乘数。
二、逐条对质
①“一堆请求同时往同一个分片发帖,还是排队”——“同时往同一个分片发帖”这个前提在设计上就不成立
新帖落盘路径:全局取号 →
id % 桶数路由。ShardRouter::bucket()/bucketForWrite()(app/SplitDB/ShardRouter.php)把帖子按 id 哈希进 32 个(config.phpSPLITDB_BUCKET_SIZE = 32)独立桶文件bucket/active/{季度}/{桶}.sqlite,且只有当前季度可写,历史季度零写入。同时涌入的 N 个发帖,id 不同 → 桶号不同 → 落在不同文件 → 各自持独立写锁并行提交。两人同时写同一本小本子的概率被哈希摊到 1/32,而不是他表述里的 100%。②“拿 ID 本身就是一次写,大量并发抢 ID 会在同一个库文件上抢锁”——是写,但写在哪、写得有多薄,决定它是不是瓶颈
IDGenerator 文件头写得很清楚:基于
global_id.sqlite的id_generator表(app/SplitDB/IDGenerator.php)。抢 ID 的锁发生在一个刻意独立、单行、无业务数据的微型文件上,与分片桶文件是两套互不干扰的串行点:抢 ID 不占桶文件的写锁,写桶文件也不用再碰 ID 锁。每请求代价 = 一次单行BEGIN IMMEDIATE+SELECT/UPDATE,微秒级持锁;竞争失败走busy_timeout = 5000ms+ 最多 3 次 5–20ms 随机退避重试,结果是有界等待,不报错、不丢号。③“WAL 只是读写互不阻塞,写-写依然互斥”——对,所以设计不是消灭单写者,而是压低持锁时长与写请求密度
写-写互斥的伤害 = 密度 × 持锁时长,两条都被拆了:
- 降密度:32 桶扇出(见①)+ 扩容(见⑤);
- 降持锁时长:
DBFactory::PRAGMAS统一强制journal_mode = WAL; synchronous = NORMAL; cache_size = -20000; temp_store = MEMORY(app/SplitDB/DBFactory.php)——WAL 让提交走追加式日志,synchronous = NORMAL免去每事务全量 fsync,单行事务的持锁窗口是微秒级;白皮书红线同时明令“禁止长事务、长快照”。 - 把写挪出锁路径:
- 正文这类大 payload 不进 SQLite,落
extern/{年}/{Q}/{桶}/{id}.txt文件(ShardRouter::externRel()),桶文件只剩元数据小行; - 浏览量这类高频写是 APCu 内存计数 + 30s 节流、单事务批量落库(
ViewCounter::inc()/flush(),落库成功才扣内存、不丢计数),与白皮书红线“禁止 HTTP 线程实时更新浏览量”一致; - 搜索索引等重活走队列异步(
app/SplitDB/Queue.php),不占请求热路径。
④“人挤爆照样排队”——先问“人山人海”是读还是写
论坛流量里读占绝对大头(游客刷首页、列表、热帖)。这套系统里游客列表页连 SQLite 都不进:
PageCache::serve()/render()(app/Helpers/PageCache.php)把首页/论坛列表渲染成静态 HTML 文件缓存直接命中。真正写库的只有发帖/回帖,且被①的扇出摊到 32 个文件上。排队窗口存在,但既不无限(busy_timeout 有界)也不集中(32 路扇出)——要等“单桶写速率顶穿单文件吞吐”才轮到锁成瓶颈,而那是下一个机制处理的:⑤ 扩容机
BucketAutoScaler::updateBucketSize()/emergencyExpand()(app/SplitDB/BucketAutoScaler.php)支持 32 → 64 → 128,且ShardRouter::bucketForWrite()保证扩容后新帖只进新增桶编号段、旧桶不再收新写,读按bucket_path零迁移。人再多,是“多开几本小本子”,不是“排队等同一本”。三、老奶奶版本还给他
小本子一次只能一个人写——对。但现在是 32 本小本子同时能写:账房每次只记一行(薄事务),大件货堆仓库不进账本(正文外置),门口看热闹的挤不进账房(页面缓存),账房最忙的活儿交给后屋伙计夜里做(异步队列)。真把 32 本写满了,就再开 64 本、128 本,旧本子从此不再加新账。
四、诚实的边界(主动把话说到位)
- 单文件单写者是 SQLite 引擎事实,SplitDB 没有也不可能“从根上消灭”它——任何数据库的写路径最终都有一个全局串行点:InnoDB 的 redo log 刷盘、PostgreSQL 的 WAL 同样是单点 fsync。工程问题是串行点是否落在热路径上:正文不走它、浏览数不走它、游客读不走它、同秒写请求被 32 路摊开。
- 全系统唯一“每写必过”的真串行点是
global_id.sqlite的单行取号——这是刻意的取舍(唯一性 + 散列确定性),它单行、独立文件、微秒级,离单机 PHP-FPM 的写速率上限还差两个数量级;真到那天,代码注释里已预留演进空间(ID 段预取 / 雪花取号)。 - 如果“人山人海”指同一瞬间对同一主题/同一行的更新(如千万人同时回同一帖),任何数据库都必须串行——这是语义串行,不是架构缺陷,不能拿来证明分片无用。SplitDB 白皮书自带“不适用场景”与红线(禁止网页同步索引、禁止实时更新浏览量、禁止长事务),说明它对“能扛什么、不扛什么”有明确边界:读多写多、写可散列的社区论坛恰在适用域内。
一句话总结:他描述的是 SQLite 的引擎说明书;SplitDB 反驳的是“所以系统会卡死”这个结论——引擎特性不等于系统瓶颈,中间隔着扇出、薄事务、外置、缓存、异步、扩容这六道设计。
点赞与点评1flinthub2026-09-09
- bbs1org2026-09-03
ai妥协了:SQLite 单文件 “单写者” 是硬件级说明书特性,但不能直接等价为 SplitDB‑CORE 系统瓶颈。中间隔了哈希扇出、极薄事务、外置大文本、内存批处理、异步队列、动态桶扩容六层工程手段。它的短板不在单机写分散论坛场景,而在于无法多机分布式横向扩展。
如此说来,单机部署,你设计的SplitDB是个非常好的数据库技术方案!
- 1234567892026-09-03
大佬,我觉得你可以考虑设计下。支持sql数据库,1千万主题或者1亿主题。应该可以采用分表处理吧。虽然很多人达不上这么多内容,但有利于缓解性能焦虑。另外支持很多人大批量采集。😅
- 1234567892026-09-03
- 1234567892026-09-03
- bbs1org2026-09-03
- 1234567892026-09-03
- bbs1org2026-09-03
- 1234567892026-09-03
- flinthub2026-09-03
不错不错,基础审美很好啊👌 赞
- Maser2026-09-03
这个也很好看
- bbs1org2026-09-03
说明卧虎藏龙
- elm2026-09-03
好棒啊,偏geek风,即有论坛又有博客,还适合小主机,期待😌
有点东西,支持支持
6666666
- flinthub2026-09-03
- zaiwai2026-09-03
不错不错,来支持一下。
相当可以,高手在民间
- dcve2026-09-03
社区大佬越来越多了