找回密码
 -注册-
查看: 9006|回复: 53
打印 上一主题 下一主题

Roon索引数据的内存化实现笔记

[复制链接]
跳转到指定楼层
1
发表于 2022-10-15 21:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式 来自 北京
本帖最后由 中关村东路 于 2022-10-15 23:11 编辑

目录

1. 背景
2. 思路
2.1 Roon的数据
2.2 实现思路和所需内核模块介绍
3. overlay+tmpfs/zram实现
3.1 overlay+tmpfs实现
3.2 overlay+tmpfs实现解释(可选)
3.3 overlay+zram实现思路(可选)
4. 纯tmpfs/zram实现思路(可选)
5. 小结

本帖的想法很简单,直接读写SSD尽管比机械硬盘快,但延迟还是比内存差得多,尤其是很多同学的无扇Roon Core性能还是在一定程度上受限的,用本帖的方法能让你更容易在性能和发热之间找到平衡。说实话,本帖代码只写了不到半小时,但写这个帖子真花了我好长时间,确实不太容易讲清楚,如果对你有所帮助,或者遇到什么问题,可以回帖表示支持。

本文为“中关村东路”原创,在erji.net首发,未经作者允许请勿转载。欢迎各司免费使用。


来自 19楼
 楼主| 发表于 2022-10-15 23:09 | 只看该作者 来自 北京
刚刚重启了一下系统,跑了一整天一切顺利,再次确认数据也都同步进来了。
补一张图吧,内存24G,绿色部分57%是Roon Core占用的,紫色部分是overlay的占用,黄色部分是缓存占用。Linux和windows内存使用机制不同,会尽量缓存用起来,可以看到swap占用是0k,说明内存实际上远没用尽。



回复

使用道具 举报

2
 楼主| 发表于 2022-10-15 21:29 | 只看该作者 来自 北京
1. 背景

本帖主要讨论如何在基于Linux的Roon Core上实现数据库的内存化,可以提升数据库读写速度,并极大优化数据库读写延迟。具体到我个人的特定测试环境下,大规模读写速度可提升三到四倍,小包读写延迟可降低七百到一千倍。在百万音轨数量级的Roon环境中,大多数操作都是小包读取,使用体验会有显著提升。

如果您觉得现在自己的设备体验很好没觉得慢、认为太多音乐没有必要、或者Roon根本没必要用单独的机器用笔记本就很好等等,就不要往下看了,也麻烦不要特地为此来批评我。本帖只是记录和分享昨晚一个突然的想法和具体实现。感兴趣的读者将发现,虽然这思路非常直接,代码非常简单,但实现到你的系统上需要对Linux有初步的了解。我个人并不是IT从业人员,编程水平和精力都有限,本帖的实现并不能直接运行,需要读者看懂,找到几个目录才能用起来。调试过程中如果遇到困难可以留言讨论,但请不要因此攻击我。使用代码之前请先备份数据。

我的Roon系统之前简单分享过【1】,这里再次简要介绍。分为ZFS NAS服务器,Roon Core,Roon Ready/Bridge三部分共五台机器,输出给不同房间三套解码,因为这几台机器都是无扇的,所以另外有一台交叉编译兼HQPlayer服务器。其中ZFS NAS用的是10代标压Intel,32G内存缓存,2T NVME缓存,存储音乐的硬盘做了raidz冗余。Roon Core小主机用的12代低压Intel,24G内存,128G SSD。Roon Bridge小主机是一台老式J3455,16g内存和16G Optane闪存。另外有一台树莓派4b【1】和一台Beaglebone Black Industrial【2】,两台自己山寨的Roon Ready网桥的解码不好其实不常听。上述系统全部使用Gentoo Linux,我也在我的repo【3】里维护了不同版本的xanmod内核和Roon/NAA包,以后我可能会开贴介绍一些内核优化技巧,也欢迎大家使用。为了保证下列思路和代码对你有用,如下硬件条件需要满足:1、Roon Core在一台有root权限的Linux系统运行;2、Roon Core的内存应该尽量保证在16G以上,如果数据较多,最好32G;3、如果你的数据量特别小,这个方案的意义可能并不大。

【1】http://erji.net/forum.php?mod=vi ... =2253401&extra=
【2】http://erji.net/forum.php?mod=vi ... =2276075&extra=
【3】https://github.com/zhjie/zhjie_gentoo_repo

回复

使用道具 举报

3
 楼主| 发表于 2022-10-15 21:31 | 只看该作者 来自 北京
本帖最后由 中关村东路 于 2022-10-15 21:38 编辑

2. 思路

2.1 Roon的数据

在之前的帖子里【1】我曾经讨论过Roon几个线程的功能。这篇帖子要首先讨论一下Roon的数据。Roon的数据主要分为音乐数据、图片数据和索引数据三个部分,其他的都不影响日常使用不用管。其中音乐数据分为本地数据和qobuz等串流数据,本地数据支持本机硬盘和samba等网络存储两种,因为众所周知的原因我目前只能以本地为主qobuz为辅,这就导致了索引数据库臃肿,性能下降;图片在1.8早期和之前的版本中是在索引时就完全下载保存在本地的,当前的实现改为读取的时候才下载,同时缓存起来,这导致了图片依赖Roon服务器的稳定,官网论坛也有人批评,但似乎他们工程师不想改回去;索引数据是最影响Roon操作界面检索、浏览体验的,也是本帖讨论的重点。

在实现中,ROON_DATAROOT这个环境变量决定了你的Roon数据所在,一般要看你的sysv/systemd文件。常见的sysv启动文件八成叫做/etc/init.d/roonserver之类的,可以去那个目录下找。systemd启动文件一般放在/etc/systemd/system/multi-user.target.wants目录下,链接过来的。打开这个启动文件,应该能看得懂ROON_DATAROOT是什么。我的是在/var/roon,以下假定你的也在这个目录下。执行命令
  1. ls /var/roon/RoonServer/Database/Core/
复制代码

在我的Roon Core上可以看到如下几个目录,
  1. 1b1abcdefg230980fd1234567a13  MobileSync  Radiance  account_v3
复制代码

其中第一个是关键,应该是每个人都不一样的,我这个是打码了的,后面都会用这段字符串替代。在这个目录下有这四个文件夹,
  1. du -hcs *
  2. 3.5G        broker_3.db
  3. 24K            classicalness_v1.json
  4. 32K            clientdata.db
  5. 996K        genres_v2.fse
  6. 2.3G        images_1
  7. 6.2M        transport
  8. 5.8G        total
复制代码



其中broker_3.db这么大就是我们要优化的索引数据了。images_1是图片缓存数据,1.8时候这目录可能要好几十G,现在的版本实测删了也能跑起来。看你的数据量,这里的3.5G+2.3G就是日常使用所需的全部数据了,都是碎文件,随机读取延迟是很高的。如果你的内存很大,可以都放进内存试试。我内存只有24G,就只把关键的索引数据broker_3.db目录放在内存了,建议读者也这样操作即可。

2.2 实现思路和所需内核模块介绍

思路其实非常简单,一个目录放在内存里,供Roon读写操作,一个目录放在硬盘上,异步的同步。但这样做有个不大不小的问题,两个目录的全面同步需要一定的时间,虽然并不经常启动Roon Core,我们做孔乙己的毕竟还是希望有更优雅的实现方法。如果可以让内存目录开机即在逻辑上可以使用就好了,Roon该读的数据他没有才问硬盘要,这就是本帖的核心。至于把内存数据同步到磁盘上相对就容易了,我的办法是每天晚上半夜四点让他自己同步,反正是内存同步到ssd也没声音,这时间段执行也不会影响我听音乐。

具体的实现中,有三个内核模块供我们使用。分别是overlay【4,5】,tmpfs【6】和zram【7】,都是顾名思义。overlay分两层,下层实际磁盘目录,上层内存目录。tmpfs是内存中的临时目录,所以性能特别好,之前我的帖子介绍过【1】。zram不但在内存中还做了压缩,性能可能稍微差一点吧。本帖的代码使用了overlay和tmpfs,本来以为需要使用zram的,结果我的内存够了就没用到。如果你需要可以自行参考zram手册,用法应该是完全类似的。

这里多介绍一句overlay,早期版本叫overlayfs,到现在也很多人这么叫。这个模块的核心是四个目录:lowerdir放固化的数据,upperdir放内存里供读写的数据,workdir是临时操作用的目录我们也可以放内存里,最后我们把这几个目录组合起来,用mount命令挂载到逻辑上的broker_3.db索引目录,供Roon读写操作。我也是昨天才查到这个东西,有说的不对的请提出来。不过从实现效果上来看应该没问题。

【4】https://docs.kernel.org/filesystems/overlayfs.html
【5】https://github.com/graysky2/anything-sync-daemon
【6】https://wiki.gentoo.org/wiki/Tmpfs
【7】https://wiki.gentoo.org/wiki/Zram


回复

使用道具 举报

4
 楼主| 发表于 2022-10-15 21:32 | 只看该作者 来自 北京
本帖最后由 中关村东路 于 2022-10-15 21:39 编辑

3. overlay+tmpfs/zram实现

3.1 overlay+tmpfs实现

直接上代码吧。首先是创建内存目录:
  1. mkdir -p /opt/roon/{tmpfs,1b1abcdefg230980fd1234567a13}
  2. mount -t tmpfs -o rw,noatime,nodiratime,size=12g tmpfs /opt/roon/tmpfs
  3. mkdir -p /opt/roon/tmpfs/{upper,work}
复制代码

之后是构造overlay提供给Roon Core,注意后面两行是自动换行了,其实是一行:
  1. mount --bind /var/roon/RoonServer/Database/Core/1b1abcdefg230980fd1234567a13 /opt/roon/1b1abcdefg230980fd1234567a13
  2. mount -t overlay -o rw,lowerdir=/opt/roon/1b1abcdefg230980fd1234567a13/broker_3.db,upperdir=/opt/roon/tmpfs/upper,workdir=/opt/roon/tmpfs/work overlay /var/roon/RoonServer/Database/Core/1b1abcdefg230980fd1234567a13/broker_3.db
复制代码

这一套拳法打完就可以启动roon了。启动速度一如既往的慢。但启动之后的操作就快了。除此之外,上一节说了,需要在每天半夜四点(按你的生物钟定)让cron或者systemd把数据从内存硬同步回硬盘。一定注意这里的几个斜杠别打错了。
  1. rsync -az --delete /var/roon/RoonServer/Database/Core/1b1abcdefg230980fd1234567a13/broker_3.db/ /opt/roon/1b1abcdefg230980fd1234567a13/broker_3.db
复制代码

如果想要在你的系统上跑起来,首先需要确定的是 ROON_DATAROOT=/var/roon ,这个是你的roon数据根目录,是你机器的具体环境决定的,我不知道,上节说的方法你可以试试,也可以去你电脑上找找哪个目录大;其次要查那个诡异的1b1abcdefg230980fd1234567a13,这个数字是我虚构的,你也可以按前面的方法查一下,在 ROON_DATAROOT 下翻翻就能找到。

3.2 overlay+tmpfs实现解释(可选)

下面简单解释一下原理吧,第一段三行建立了tmpfs/upper,tmpfs/work,还有逻辑上的lowerdir,1b1abcdefg230980fd1234567a13目录。为了方便,我们称呼最后这个目录为opt-db,如果你想理解这个方案需要记得,后面还会提到。

第二段,我们先搞了个小trick,没让这个opt-db直接存数据,而是把实际硬盘上的/var/roon/RoonServer/Database/Core/1b1abcdefg230980fd1234567a13 bind过来。为了方便,我们称呼这个目录为var-db吧。这个操作差不多就是windows的快捷方式,以后往opt-db写东西就直接写进var-db了。最后一句代码,再把这个bind过来的opt-db/broker_3.db目录作为lowerdir(实际存储数据的目录),加载回var-db/broker_3.db,这正是Roon Core所需的那个目录,供其读写。这样我们就用这段简短的代码实现了想要的逻辑——当Roon尝试从var-db/broker_3.db读写时候,实际上他操作的是tmpfs/upper,如果这里没有想要的东西,overlay模块会从lowerdir也就是opt-db/broker_3.db同步过来,然而回忆一下,这个opt-db并不是真的存了数据,而是我们从硬盘上的var-db bind过来的,所以读到的是硬盘上的var-db/broker_3.db目录。换句话说,Roon看起来是从逻辑上的var-db/broker_3.db读取东西,但这个目录是我们把好些东西组合起来的,但最终他读到的居然还是var-db/broker_3.db这个硬盘目录。我的天,这个逻辑是不是很酷。

第三段,每天半夜同步的这一步,会从逻辑上的var-db,读取数据同步到opt-db。有意思的是,这个opt-db实际上是从var-db bind过来的,看起来是不是好像从var-db同步到var-db?其实不是,因为这个opt-db是在第二段第一行从硬盘bind过来的,而现在逻辑上的var-db却不再是真正的存储在硬盘上var-db,而是overlay之后的,也就是说,先从内存中读取,内存找不到就去lowerdir找,而lowerdir是opt-db自己,是不是很呵呵,这样同步过来的就只有内存中的数据了。

怎么样,是不是绕糊涂了?下面你有两个选择,糊涂着用,看懂了之后再用,以及不用。是不是这回真糊涂了?开了个冷笑话,希望看懂的同学在弹幕上扣1。

3.3 overlay+zram实现思路(可选)

和3.1的overlay+tmpfs的实现完全类似,只要改第一段第二句为zram就可以了,具体代码可参考【7】。


回复

使用道具 举报

5
 楼主| 发表于 2022-10-15 21:33 | 只看该作者 来自 北京
本帖最后由 中关村东路 于 2022-10-15 23:11 编辑

4. 纯tmpfs/zram实现思路(可选)

这套思路就简单多了,不过考虑到不够酷,性能也没优势,我就没采用。

首先你要用第3节中第一段的方法用tmpfs/zram创建一个逻辑上的目录给roon,我想,应该就是ROON_DATAROOT。之后用rsync从硬盘上的实际数据中(你需要把原来的Roon真是数据挪到这来)把数据库整体同步到内存里来。接下来就可以打开Roon Core使用了。最后,还是要在每天半夜把数据从内存用3节中第三段代码写回磁盘。


回复

使用道具 举报

6
 楼主| 发表于 2022-10-15 21:33 | 只看该作者 来自 北京
5. 小结

本帖的想法很简单,直接读写SSD尽管比机械硬盘快,但延迟还是比内存差得多,尤其是很多同学的无扇Roon Core性能还是在一定程度上受限的,用本帖的方法能让你更容易在性能和发热之间找到平衡。说实话,本帖代码只写了不到半小时,但写这个帖子真花了我好长时间,确实不太容易讲清楚,如果对你有所帮助,或者遇到什么问题,可以回帖表示支持。


回复

使用道具 举报

7
 楼主| 发表于 2022-10-15 21:33 | 只看该作者 来自 北京
打完收工。
回复

使用道具 举报

8
 楼主| 发表于 2022-10-15 21:36 | 只看该作者 来自 北京
本帖方法很容易推广到其他带数据库的软件系统。
回复

使用道具 举报

9
发表于 2022-10-15 21:38 | 只看该作者 来自 北京
能不能给介绍 一下ROON的实用性  我总听说这个东西  但是一直没研究过

有了它是否可以在广域网访问家里局域网上的音乐?
回复

使用道具 举报

10
 楼主| 发表于 2022-10-15 21:40 | 只看该作者 来自 北京
本帖最后由 中关村东路 于 2022-10-15 21:54 编辑
jackylzf 发表于 2022-10-15 21:38
能不能给介绍 一下ROON的实用性  我总听说这个东西  但是一直没研究过

有了它是否可以在广域网访问家里 ...

可以自己查看Roon的官方介绍或者问卖软件的人。我用着不错。主要用来听NAS的音乐和qobuz,再外面也能听。
回复

使用道具 举报

11
发表于 2022-10-15 22:23 | 只看该作者 来自 中国
给大佬送膝盖来了
回复

使用道具 举报

12
发表于 2022-10-15 22:25 来自手机 | 只看该作者 来自 上海
中关村东路 发表于 2022-10-15 21:36
本帖方法很容易推广到其他带数据库的软件系统。

LMS低头弯腰du了下自己表示东西太小了用不上啊……
话说你这个是不是可以直接写在fstab里啊?
回复

使用道具 举报

13
 楼主| 发表于 2022-10-15 22:26 来自手机 | 只看该作者 来自 北京
姚鹏 发表于 2022-10-15 22:23
给大佬送膝盖来了

我跟着大佬您玩儿了hek玩儿黑胶^_^
回复

使用道具 举报

14
 楼主| 发表于 2022-10-15 22:28 来自手机 | 只看该作者 来自 北京
leonbernieni 发表于 2022-10-15 22:25
LMS低头弯腰du了下自己表示东西太小了用不上啊……
话说你这个是不是可以直接写在fstab里啊?

内存的两个操作不太方便。我有个启动文件专门写各种优化代码,放那了。放在roon启动脚本前面也可以
回复

使用道具 举报

15
发表于 2022-10-15 22:31 来自手机 | 只看该作者 来自 上海
中关村东路 发表于 2022-10-15 22:28
内存的两个操作不太方便。我有个启动文件专门写各种优化代码,放那了。放在roon启动脚本前面也可以

是不是还要考虑sleep下下的?不然老觉得它们会抢道
回复

使用道具 举报

16
 楼主| 发表于 2022-10-15 22:33 来自手机 | 只看该作者 来自 北京
leonbernieni 发表于 2022-10-15 22:31
是不是还要考虑sleep下下的?不然老觉得它们会抢道

这段代码发出来就是觉得很优雅,秒执行。
回复

使用道具 举报

17
发表于 2022-10-15 22:35 来自手机 | 只看该作者 来自 安徽界首

大佬牛批!多发点实用型技术贴。
回复

使用道具 举报

18
 楼主| 发表于 2022-10-15 22:37 来自手机 | 只看该作者 来自 北京
haosong51 发表于 2022-10-15 22:35
大佬牛批!多发点实用型技术贴。

我发的除了请教购买建议的都是实用技术贴啊……
回复

使用道具 举报

20
发表于 2022-10-16 00:51 来自手机 | 只看该作者 来自 中国
大佬太猛了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | -注册-

本版积分规则

Archiver|手机版|粤icp备09046054号|耳机网-耳机大家坛

粤公网安备 44030602000598号 耳机大家坛、www.erji.net、网站LOGO图形均为注册商标

GMT+8, 2025-4-28 20:54

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表