问下站内大神们 成千上万的小说-存储方案

353 天前
 wuhao1

1.数据库存储
2.磁盘存储
3.oss 存储
4. ?
结合 速度和成本 最好的会是那种方案呢?
个人倾向于磁盘 速度快成本低

团队倾向于 oss

7142 次点击
所在节点    数据库
87 条回复
wxf666
348 天前
@wuhao1 相比磁盘存储,为嘛不选 SQLite 数据库呢?感觉优点还行呀:


1. 单表 1.3 亿 100 GB 大小时,六七年前轻薄本上,仍能上万随机读/写事务并发。且只占用 16 MB 内存。[源码在隔壁帖]( /t/1075881#reply65 )


2. 官方宣称,相比文件系统,10 KB 文件存数据库里,能快 35%,节省 20% 空间。[文章]( https://sqlite.org/fasterthanfs.html )

你按章节来存的话,假设每章 5000 汉字,UTF-16 存,恰好 10 KB 。


3. 支持全文索引,甚至拼音/首字母/多音字。可无限搜索事务同时进行。

微信宣称,手机端百万百字聊天记录,搜三字词,只需 0.0029 秒。10 秒全文索引完毕。[文章]( https://mp.weixin.qq.com/s/Ph0jykLr5CMF-xFgoJw5UQ )


4. 备份迁移时,没有天量小文件烦恼。

两周后,SQLite 会发布一个,[远程增量同步工具]( https://sqlite.org/draft/rsync.html )。
wxf666
347 天前
@abersheeran #10
@815979670 #17

我用近 14000 章的《带着农场混异界》,试了一下 zstd 的预训练词典,感觉很适合分章节压缩存储,

因为 UTF-8 时,整本压缩率 20%,分章节总压缩率也才 22% ~ 28%,还能快速随机选取章节。

如果独立压缩章节,总压缩率飙到 38%。



1. 压缩后,UTF-16 没有明显优势。所以采取 UTF-8 就好。

UTF-8 时 137.4 MB
- gzip 压缩 43.5 MB ( 31.7%)
- zstd 压缩 28.7 MB ( 20.9%)
- lzma 压缩 26.8 MB ( 19.5%)

UTF-16 时 96.9 MB ,
- gzip 压缩 39.0 MB (少 10.5%,相比 UTF-8 压缩后)
- zstd 压缩 27.6 MB (少 3.9%)
- lzma 压缩 25.2 MB (少 6.2%)


2. 分章节后,所有压缩算法表现都很差。可选择多章节压缩,或分离词典。

- gzip 后共 55.6 MB ( 40.5%)
- zstd 后共 51.8 MB ( 37.7%)
- lzma 后共 52.4 MB ( 38.2 %)


3. 只有 zstd 支持预训练词典,且不同词典大小,分章节总压缩率也不同。

- 32 KB 词典(压缩后 12.6 KB ),压缩后+词典 39.6 MB ( 28.8%)
- 64 KB 词典(压缩后 24.7 KB ),压缩后+词典 37.8 MB ( 27.5%)
- 110 KB 词典(压缩后 41.9 KB ),压缩后+词典 36.6 MB ( 26.7%)← 默认词典大小
- 128 KB 词典(压缩后 48.7 KB ),压缩后+词典 36.3 MB ( 26.4%)
- 256 KB 词典(压缩后 97.8 KB ),压缩后+词典 35.0 MB ( 25.5%)
- 512 KB 词典(压缩后 197.2 KB ),压缩后+词典 34.1 MB ( 24.8%)
- 1024 KB 词典(压缩后 315.3 KB ),压缩后+词典 33.0 MB ( 24%)
- 2048 KB 词典(压缩后 611.2 KB ),压缩后+词典 32.1 MB ( 23.3%)
- 4096 KB 词典(压缩后 1164.8 KB ),压缩后+词典 31.2 MB ( 22.7%)
- 8192 KB 词典(压缩后 2328.5 KB ),压缩后+词典 32.4 MB ( 23.6%)


4. 个人认为,不同场景的选择。

- 如果本地收藏,追求极致压缩,每次查看,接受解压全本,应该选 UTF-16 + lzma ,压缩率 18%

- 如果本地收藏,但要求快速任意跳转章节,选 UTF-8 + zstd + 大词典,压缩率 23%

- 如果对外提供服务,选 UTF-8 + zstd + 小词典,压缩率 27%


第三点考虑如下:

- 若服务器本地解压,再传给用户,每次选取章节后,再取对应词典压力较小,缓存词典所需内存也少

- 若要求客户端先拿词典,再本地解压呈现章节。面对只看几章就弃书的用户,沉没成本较低( 20 ~ 40 KB )
815979670
347 天前
@wxf666 问一下 压缩后的数据存 text 类型还是 blob 类型?
wxf666
346 天前
@815979670 #23

BLOB ,存的是 zstd 压缩后的二进制数据。


噢,如果要全文搜索,存压缩后数据也没关系的。SQLite 的 FTS 支持无内容表,只要你添加/删除时,提供了压缩前的章节内容,就行。

但搜索结果只有 `章节 ID`,还需要回 `章节表` 取数据解压。但搜索服务,一般都会分页呈现结果,所以不会一下子解压几万个章节出来。。

一下子解压几万个章节。。可能也没事?过亿数据,都能四五万随机读并发,命令行里 zstd 用词典,单线程解压那 14000 章节文件,也才 0.9 秒。。还是六七年前的轻薄本了。。
infinet
346 天前
@wxf666 14000 章! 键盘都磨平了吧
815979670
346 天前
@wxf666 谢谢 回复非常有参考价值,我计划用 sqlite 存日志,配合压缩使用 目前未压缩数据一个月有 400G 左右,压缩后体积应该能小压缩到 35% ~30% 左右

第一次了解到外置压缩字典的用法,对于高度重复,量又大的日志文件应该很有用(任务单次日志输出 3MB ),之前我还在担心每行独立压缩,压缩率可能不高的问题
cyoking
346 天前
@rui6ye 你这个不会被被人追究版权吗
wxf666
346 天前
@infinet #25

要是不换键盘,估计都能磨成粉了吧。。

其实网上冲着《字数较多网文》随便搜的,

看了下,这小说连载十来年了,应该换好几套键盘了吧。。



@815979670 #26

我还没试过日志存数据库诶。。

日志可以调整成,边压缩,边流式存到硬盘上吗?

要搜索的话,zstdgrep 就能搜了。。


如果你确实想试试数据库存日志,也推荐你 DuckDB 对比下,

这货是列式数据库,默认就带压缩。同一列相同类型,压缩效果应该也更好些。。

而且功能、计算速度也比 SQLite 丰富/快很多。

就是不知道读写速度,比得上 SQLite 不。。
815979670
345 天前
DuckDB 挺早就注意到了,出于两个考虑没有考虑使用:
1. 项目的开发使用的是 Go 语言,主流的 Go-duckdb 库 ( https://github.com/marcboeker/go-duckdb) 依赖 CGO (无法跨平台编译 这个对我很重要),有一个不依赖 CGO 的 ( https://github.com/scottlepp/go-duck) 但目前只有 8 个 Star 不太敢用在项目中。

2. SQLite 发展时间很长,经过了时间的检验,并且官方也提到了对损坏的数据库文件也尽可能的提供了读取的支持,无论从性能、兼容性 、生态 等多方面考虑,它仍然很能打 并且在我这个场景中够用。而 DuckDB 我自己做一些新技术探索时也尝试过 性能确实可以( 2000w 行 csv ,就纯 csv 没索引那种,汇总数据特别快 只用了 0.2 毫秒),但毕竟是一个新东西,可能 一两年后的项目中会考虑使用吧(让子弹飞一会)。

日志存储倒不是流式存储,项目中会有一个专门写日志的组件,不管哪里的日志都丢给 这个组件,先缓存起来,再按照一定的规则批量写入 SQLite 落盘(我之前测试过 SQLite 批量写入性能 https://www.dbkuaizi.com/archives/154.html 15w 数据耗时 5.13 s ),所以写入不存在问题。
815979670
345 天前
@wxf666 忘了 @了 看 29 楼
815979670
345 天前
29 楼更正一个错误 DuckDB 汇总数据是 200ms 0.2 秒
mayli
345 天前
@wuhao1 oss 压缩存放,外加服务器本地缓存下。
mayli
345 天前
上万的小说 -> 也就 10K
平均每本 10MB
oss = 100 GB
完全没有压力.
tushan
345 天前
建议使用 oss 储存,对于冷门小说还可以走存档的套餐,成本更低,
wxf666
343 天前
@mayli #33
@tushan #34

是整本存 OSS 吗?在线阅读,也要下整本吗。。

对于只看几章,就弃书的用户来说,投入是不是有点高了。。



@815979670 #29

算了,DuckDB 标题也写了,人家自认是 OLAP 类型数据库,应该不适合高并发读写。。

但用来分析你那 400GB 历史日志,应该非常合适。。
mayli
343 天前
@wxf666 你要是有快速跳转需求,可以按照章节切分缓存。
如果懒得切,也可以用 nginx byte-Range Caching
这种缓存分片。

https://blog.nginx.org/blog/smart-efficient-byte-range-caching-nginx
815979670
343 天前
@wxf666 其实也没有分析一说,就是一些普通的运行日志,只有出现故障后根据时间戳检索,在展示的时候解压显示就行
wxf666
343 天前
@815979670 #37

总感觉,要依赖外部程序解压缩,才能查看原文,有点麻烦。。

正常原文存储,每天凌晨归档至 DuckDB ,可行吗?

如果怕 DuckDB 还不够稳定,可能丢数据,那就再 lzma 压缩一份,文件系统上归档?



@mayli #36

切分后,怎么存放、提供访问呢?

1. 直接按范围下载原文,并 gzip 传输,是不可行的。因为如 22 楼所说,独立每章 gzip --best 压缩,整书只能压到 40%。( zstd 配合小字典压缩,都能有 25%)

2. 按章切分 + 字典压缩 + 存 OSS 提供访问的话,好像有个请求费比较贵。。服务器的话,存储和流量又比较贵。。
mayli
343 天前
@wxf666 其实 40% 和 25% 差距并不大,如果你是 OSS 的话,这部分没多少钱。
你这些数据不算多,即是说 1w 本小说
每本 10MB, 10MB * 10K = 100G
每本 100MB, 100MB * 10K = 1000G (我不信有压缩后 100M 的小说…)

假设极限情况 1T 成本用
https://www.hetzner.com/storage/storage-box/ -> € 3.20 max/mo.
https://wasabi.com/pricing -> $6.99 TB/month
https://r2-calculator.cloudflare.com/ -> $38.25 / mo

有这个时间去抠 15%的压缩率,时间成本都已经能一年服务器费用了。

对于一般的电子书站,分章节是合理的,毕竟大部分网页阅读都是分章节的,s3 这种对于单文件多文件也没有太大价钱区别。
wxf666
343 天前
@mayli #39

简单算了下,大部分时候,还是 OSS + zstd 划算?再加上 CDN ,能进一步减少流量部分的花费?

除非只存了 100 ~ 200 GB ,且每月点击数过亿,此时用服务器较为划算?



1. 我查了下啊哩云的价格(不太熟悉,有错的还请指出):

OSS:
- 存储:0.12 元 / GB / 月
- 流量:0.50 元 / GB
- 请求:0.01 元 / 万次(每月 <= 2000W 次时免费)

服务器:
- 存储:0.50 元 / GB / 月
- 流量:0.80 元 / GB


2. 如 22 楼所说,14000 章小说,词典 + 分章节压缩 36.6 MB ,平均每章 2.68 KB 。加上网络传输 TCP/IP 头部、握手、响应头部等杂七杂八开销,算 3KB 好了。

如果是 gzip 压缩传输,平均每章 4.02 KB ,加上乱七八糟两三百字节,算 4.3 KB 好了。


3. 则每月费用为( P 为每章平均网络包大小,C 为每月点击次数(万次),S 为每月存储大小( GB )):

- 服务器:( P x C / 2^20 ) x 0.8 + 0.5 x S

- OSS:( P x C / 2^20 ) x 0.5 + 0.12 x S + max(C - 2000, 0) x 0.01


4. 画图后,是这样:


- X 轴:C 值( 0 - 6.7 亿次)
- Y 轴:S 值( 0 - 1000 GB )
- Z 轴:每月费用( 0 - 3000 元)
- 红色:服务器 + gzip
- 黄色:OSS + gzip
- 蓝色:OSS + zstd
- 绿色:服务器 + zstd

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1076073

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX