Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于SyncMap"缓存"层的个人想法 #1191

Open
2 tasks done
PaienNate opened this issue Jan 11, 2025 · 4 comments
Open
2 tasks done

关于SyncMap"缓存"层的个人想法 #1191

PaienNate opened this issue Jan 11, 2025 · 4 comments
Labels
enhancement New feature or request

Comments

@PaienNate
Copy link
Contributor

PaienNate commented Jan 11, 2025

在提问之前...

  • 我填写了简短且清晰明确的标题,以便开发者在翻阅 issue 列表时能快速确定大致问题。而不是“一个建议”、“卡住了”等
  • 我基本确定这是一个新功能/建议,而不是遇到了 bug(不确定的话请附上日志)

说说你遇到的问题?

当前SyncMap与其说是作为缓存层,事实上是作为“内存数据库”使用的。

如果在数据库无法存储时,存放在SyncMap的数据会一直累积,并在程序崩溃时数据全部丢失。

这显然也会有较高的内存占用。而大部分数据实际上是不必要被进行读取的。

同时,并不能保证程序关闭时,最后一次写入是一定成功的,有数据丢失的风险。

有什么好的想法?

既然SyncMap缓存层目前基本是作为内存数据库使用,不如将其重构为内存数据库版本。或者至少将存储数据库的上层部分重构为内存数据库版本。

采用某个可持久化的内存数据库来实现SyncMap,并针对指针类型做特化,将其序列化后再存储/读取;如果程序崩溃或者遇到其他情况,可以保证数据可控的不丢失。

同时,在部分情况下,甚至可直接升级它至Redis等内存数据库,从而针对服务器集群部署提供基础。

其他内容

X

@PaienNate PaienNate added the enhancement New feature or request label Jan 11, 2025
@Xiangze-Li
Copy link
Member

提请注意:按此思路,内存数据库的持久化事实上成为了「数据库主份」,SQL 变成了「数据库的热备份」,进一步又有「备份的备份」。

既然是热备份,当内存持久化的数据和 SQL 的数据不一致时,准备如何处理;或说,当程序启动时,内存数据库是以持久化的数据来装载,还是以 SQL 的数据来装载?
如果以内存持久化为准,是否只要有最后一步备份即可,可以直接将 SQL 弃用?如果以 SQL 为准,是否可以直接将内存数据库简化成真正的缓存层?

@PaienNate
Copy link
Contributor Author

提请注意:按此思路,内存数据库的持久化事实上成为了「数据库主份」,SQL 变成了「数据库的热备份」,进一步又有「备份的备份」。

既然是热备份,当内存持久化的数据和 SQL 的数据不一致时,准备如何处理;或说,当程序启动时,内存数据库是以持久化的数据来装载,还是以 SQL 的数据来装载? 如果以内存持久化为准,是否只要有最后一步备份即可,可以直接将 SQL 弃用?如果以 SQL 为准,是否可以直接将内存数据库简化成真正的缓存层?

@fy0 (先拽一个木落来这里),如果将内存数据库简化为真正的缓存层,也就是说它仅优化读不参与写,此时直接去除该层确实可行。

木落之前对这个想法的说明是:
image

我对数据库能否承受这个量级的操作不太清楚。事实上说,如果能承受住较大量级,这个方案是最好的。但测试起来不太方便,回头看看能不能搓一个测试。

针对“内存数据库的持久化事实上成为了「数据库主份」”的情况,考虑到内存数据库有落盘到SQL的逻辑,所以实际上正常情况是这样的:

数据 -> 内存数据库 -> 落盘(每n秒)

重启海豹时,则:

海豹启动 -> 内存数据库读取数据 -> 立即落盘当前内存数据库数据 -> 恢复原本状态

当出现意外时,将会变成:

数据 -> 内存数据库(持久化) -> 因数据库损坏,落盘失败,提示用户数据库要维修

重启海豹时,则

海豹启动 -> 内存数据库读取数据 -> 立即落盘当前内存数据库数据 - 若数据库修复,啧落盘到数据库内(或如果确认内存数据库不宜落盘,则删除持久化文件),否则落盘失败,提示需要维修。

个人认为直接将SQL层移除是不明智的,长期运行下,内存占用量无法估量;同时如果数据库出现问题,难以进行修复和数据恢复。同时由于大部分内存数据库基本设置是kv的,性能上讲也难说会占优。

欢迎进一步讨论。

@Xiangze-Li
Copy link
Member

木落之前对这个想法的说明是:

如果考虑数据一致性,这才是正确的做法;否则就要回答以哪份数据为准的一致性问题。

针对“内存数据库的持久化事实上成为了「数据库主份」”的情况,考虑到内存数据库有落盘到SQL的逻辑,所以实际上正常情况是这样的:

数据 -> 内存数据库 -> 落盘(每n秒)

重启海豹时,则:

海豹启动 -> 内存数据库读取数据 -> 立即落盘当前内存数据库数据 -> 恢复原本状态

当出现意外时,将会变成:

数据 -> 内存数据库(持久化) -> 因数据库损坏,落盘失败,提示用户数据库要维修

重启海豹时,则

海豹启动 -> 内存数据库读取数据 -> 立即落盘当前内存数据库数据 - 若数据库修复,啧落盘到数据库内(或如果确认内存数据库不宜落盘,则删除持久化文件),否则落盘失败,提示需要维修。

在这个设计中,重启之后的数据源几乎总是内存持久化,那么内存持久化就是主份。同时,它还提出了另一个并未良好说明的概念,即「确认内存数据库不宜落盘」:这要求程序有能力对数据的「内容语义」进行检查,以排除「合法的数据库保存了非法数据」状态。

个人认为直接将SQL层移除是不明智的,长期运行下,内存占用量无法估量;同时如果数据库出现问题,难以进行修复和数据恢复。

在内存数据库事实上是主份的情况下,如果还希望要释放冷数据占用的内存,实际上是要求开发一个支持读和写的缓存层,其中写可以累积批量化而不使缓存立即过期;而缓存过期的操作是写入 SQL。否则,在业务逻辑直接从内存数据库取数据的情况下,就不得不将所有数据都加载到内存里。

同时由于大部分内存数据库基本设置是kv的,性能上讲也难说会占优。

同样地,只要业务逻辑把这个内存数据库作为主份,就不可能享受 SQL 的性能。

@PaienNate
Copy link
Contributor Author

”实际上是要求开发一个支持读和写的缓存层,其中写可以累积批量化而不使缓存立即过期;而缓存过期的操作是写入 SQL。“

我认为这个说法非常合适,我比较关心的问题是我们是否要做该层的持久化,它可以不参与下一次的运行,但至少应该保留在数据库无法正确落盘时,可以恢复数据的渠道。

至少目前来看,这种情况是存在的(落盘 database is locked),而目前解决的方案是”啊反正下一次落盘没准落的进去呢“(木落原话),如果炸豹时的落盘失败,那么数据就会丢失。

*或者,如果无法落盘次数达到一定限制,直接炸豹以保证数据安全?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants