目前的整体架构思路

一条修改操作如何被处理

一条日志, OpLog,我们不应该包含复杂的 POI 对象,是一个极简的声明式的 JSON 结构。仅需描述三件事:谁、在哪、做了什么修改

{
  "excelId": "excel_1024",
  "logId": 15023,
  "version": 12,
  "userId": "user_abc",
  "timestamp": 1718027127000,
  "opType": "UPDATE_CELL", 
  "payload": {
    "sheetName": "Sheet1",
    "row": 4,
    "col": 2,
    "cellType": "STRING",
    "oldValue": "Hello",
    "newValue": "Hello World"
  }
}

对前端而言,收到 WebSocket 的广播的这条 JSON 之后,直接找到对应的单元格,把内容刷新成对应的内容。前端并不需要知道后端时用 POI 还是别的东西存文件;

对于后端而言,当异步刷新快照的线程拿到该条日志 JSON 时,只需要与 POI 的操作对象作 API 的一系列处理。

冷热日志与快照闭环

热日志支持高并发和实时广播的数据路径流动。在实现上,我们用 RabbitMQ -> Redis -> WebSocket 实现一个流程。它是易失的。

冷日志则负责持久化和批量落盘,也就是真正的存储。 RabbitMQ -> MySQL。

异步快照存储:最终的快照是要将当前版本的 POI 刷盘存入 MinIO 中。

如何在不同的数据源中同步刷盘操作呢?在 Redis 与 MySQL 之间,我们用延时队列。也就是说,一旦有修改操作(不是自动保存操作,而是用户自动触发的),那么前端传递过来,这条数据就通过交换机入了 Redis 的队列成为消息;该消息的消费者会负责对 Redis 进行日志写入;如果写入成功则 ACK 进入串行的延时队列 MySQL,也就是与 MySQL 进行同步,我们设定一个延时范围,在一个不会过多降低性能也能够保证用户体验的程度上保证可靠性;2s 的消息丢失是可以忍受的;

在 MySQL 与 MinIO 中的刷盘同步也是如此;由于一旦日志进入 MySQL 持久化之后,那么这些内容可以被认为是一个完全可追溯的文档了。那么在任意时候,我们进行将该快照版本更新和重刷日志都是可以接受的;但是很明显,如果每次读取一个文件都要重刷大量日志的话,肯定是不必要的;也因此可以在一定条件出发后重刷新的快照版本,策略上可以是保证保留近期的3个历史快照;这个刷盘是异步的,可以通过延时队列或者计数器实现,也是一个非常简单的兜底策略。

这也会涉及到一个问题。如果刷盘更新快照开始了,那么意味着快照版本将要 +1, 那么原本没有更新的日志此时就会显示为老版本的快照。在我们当前的逻辑,一个文件是由当前快照内容+(日志快照号>=该快照)的内容组成的。那么

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇