Dspace 双写入 RDBMS 和 SOLR 与并发
Dspace dual write to RDBMS and SOLR vs concurrency
我想知道 dspace 如何在支持并发的同时管理数据库和 solr 中的索引。换句话说,如果两个人同时尝试写入同一个项目(例如更改元数据),dspace 如何确保索引不会与数据库不同步。
如果 USER1 与 USER 2 同时写入相同的元数据值,并且首先写入 USER 1 的数据库,然后写入数据库和 USER2 的索引发生,然后写入 USER1 的索引 Happen。
换句话说,USER1 "write" 将在索引中,而 User2 写入将在数据库中 = 不一致!!!
我想知道在dspace中如何避免这种情况,这是一个典型的双写问题。
dspace的事件系统,不知道怎么避免。
有谁知道吗?
在 Solr 中,DSpace 不仅仅索引单个元数据更改(当它发生时)。它实际上重新索引了 Solr 中的整个项目。
这意味着虽然并发是数据库层的问题(并且 writes/updates 在数据库中是同步的),但它不是 Solr 索引过程中的问题。
这是您的示例中 would/should 发生的情况。
- 用户 1 和用户 2 同时编辑同一个项目的标题。
- 编辑将在数据库级别同步,以便第一个发生。假设用户 1 的编辑先发生,然后是用户 2 的编辑。
- 用户 1 的编辑将触发 Solr 中的重建索引。用户 2 的编辑也是如此。这意味着同一个项目将被重新索引两次(一次是
每次编辑)。这些重新索引与特定更新无关(因此第一个重新索引不仅索引标题),而只是告诉 Solr 该项目已更新并且需要重新索引。
- 在第一次重建索引时,用户 1 的编辑已经完成,因此项目将使用该标题编制索引
- 到第二次重建索引时,用户 2 的编辑已经完成(因为重建索引本质上比将编辑保存到 DB 层需要更长的时间),因此项目将使用更新后的(重新)索引标题.
所以,这里的简单答案是 DSpace 不会重新索引单个修改(如果不与数据库编辑同步,最终可能会乱序)。相反,它跟踪哪些 object 已更新并触发整个 object 元数据的重新索引。虽然这看起来像 "overkill",但在 Solr 中对单个 object 的重新索引并不是所有的过程密集型,它确保 object 的 current/latest 元数据被索引在 Solr 中(在同时写入的情况下)。
更新:根据要求(在下面的评论中),这里详细介绍了 DSpace 如何执行重建索引(在 Solr 中)。
- DSpace 有一个定义的事件系统。它遵循本节
dspace.cfg
中的配置:https://github.com/DSpace/DSpace/blob/dspace-5_x/dspace/config/dspace.cfg#L732
- 默认情况下,在 DSpace 5 中,
IndexEventConsumer
是为 Solr 执行索引的。它在此处默认配置:https://github.com/DSpace/DSpace/blob/dspace-5_x/dspace/config/dspace.cfg#L732
- 在 DSpace 5 中,每当有人更改项目的元数据(或关于项目的任何内容)时,都会调用
Item.update()
方法将更改实际保存回数据库层。
- 保存所有更改后(使用
DatabaseManager.update()
),Item.update()
方法生成 new MODIFY event in the Event System.
- 新的 MODIFY 事件附加到 LinkedList of events in the current Context
- 当 Context is committed (which happens when saving a change), it first calls commit on the DB connection (ending the transaction). Then, it sends the list of events to the Dispatcher (
BasicDispatcher
is configured by default in dspace.cfg), which then in turn triggers the index in Solr (via the configured IndexEventConsumer
)
IndexEventConsumer
将更新列表 object 传递给索引服务(默认为 SolrServiceImpl
)。
- 最后,
SolrServiceImpl.indexContent()
从数据库中读取最新的元数据值并在 Solr 中为它们编制索引。
上面的逻辑仍然有点简化(因为它太复杂了,无法遍历代码的每一步)。但是,这里的基本要点是每个 Item.update()
调用都被视为一个数据库事务。它还会触发存储在用户 session(上下文 object)中的修改事件的添加。一旦提交了数据库事务,MODIFY 事件就由 IndexEventConsumer
处理,它重新索引 整个项目 。
因此,在同时编辑的情况下,将生成两个 MODIFY 事件(每次编辑一个)。但是,last MODIFY 事件只有在 last 数据库编辑提交后才会被触发。因此,Solr 索引应始终与数据库中的最新信息同步。
我想知道 dspace 如何在支持并发的同时管理数据库和 solr 中的索引。换句话说,如果两个人同时尝试写入同一个项目(例如更改元数据),dspace 如何确保索引不会与数据库不同步。
如果 USER1 与 USER 2 同时写入相同的元数据值,并且首先写入 USER 1 的数据库,然后写入数据库和 USER2 的索引发生,然后写入 USER1 的索引 Happen。
换句话说,USER1 "write" 将在索引中,而 User2 写入将在数据库中 = 不一致!!!
我想知道在dspace中如何避免这种情况,这是一个典型的双写问题。
dspace的事件系统,不知道怎么避免。
有谁知道吗?
在 Solr 中,DSpace 不仅仅索引单个元数据更改(当它发生时)。它实际上重新索引了 Solr 中的整个项目。
这意味着虽然并发是数据库层的问题(并且 writes/updates 在数据库中是同步的),但它不是 Solr 索引过程中的问题。
这是您的示例中 would/should 发生的情况。
- 用户 1 和用户 2 同时编辑同一个项目的标题。
- 编辑将在数据库级别同步,以便第一个发生。假设用户 1 的编辑先发生,然后是用户 2 的编辑。
- 用户 1 的编辑将触发 Solr 中的重建索引。用户 2 的编辑也是如此。这意味着同一个项目将被重新索引两次(一次是 每次编辑)。这些重新索引与特定更新无关(因此第一个重新索引不仅索引标题),而只是告诉 Solr 该项目已更新并且需要重新索引。
- 在第一次重建索引时,用户 1 的编辑已经完成,因此项目将使用该标题编制索引
- 到第二次重建索引时,用户 2 的编辑已经完成(因为重建索引本质上比将编辑保存到 DB 层需要更长的时间),因此项目将使用更新后的(重新)索引标题.
所以,这里的简单答案是 DSpace 不会重新索引单个修改(如果不与数据库编辑同步,最终可能会乱序)。相反,它跟踪哪些 object 已更新并触发整个 object 元数据的重新索引。虽然这看起来像 "overkill",但在 Solr 中对单个 object 的重新索引并不是所有的过程密集型,它确保 object 的 current/latest 元数据被索引在 Solr 中(在同时写入的情况下)。
更新:根据要求(在下面的评论中),这里详细介绍了 DSpace 如何执行重建索引(在 Solr 中)。
- DSpace 有一个定义的事件系统。它遵循本节
dspace.cfg
中的配置:https://github.com/DSpace/DSpace/blob/dspace-5_x/dspace/config/dspace.cfg#L732 - 默认情况下,在 DSpace 5 中,
IndexEventConsumer
是为 Solr 执行索引的。它在此处默认配置:https://github.com/DSpace/DSpace/blob/dspace-5_x/dspace/config/dspace.cfg#L732 - 在 DSpace 5 中,每当有人更改项目的元数据(或关于项目的任何内容)时,都会调用
Item.update()
方法将更改实际保存回数据库层。 - 保存所有更改后(使用
DatabaseManager.update()
),Item.update()
方法生成 new MODIFY event in the Event System. - 新的 MODIFY 事件附加到 LinkedList of events in the current Context
- 当 Context is committed (which happens when saving a change), it first calls commit on the DB connection (ending the transaction). Then, it sends the list of events to the Dispatcher (
BasicDispatcher
is configured by default in dspace.cfg), which then in turn triggers the index in Solr (via the configuredIndexEventConsumer
) IndexEventConsumer
将更新列表 object 传递给索引服务(默认为SolrServiceImpl
)。- 最后,
SolrServiceImpl.indexContent()
从数据库中读取最新的元数据值并在 Solr 中为它们编制索引。
上面的逻辑仍然有点简化(因为它太复杂了,无法遍历代码的每一步)。但是,这里的基本要点是每个 Item.update()
调用都被视为一个数据库事务。它还会触发存储在用户 session(上下文 object)中的修改事件的添加。一旦提交了数据库事务,MODIFY 事件就由 IndexEventConsumer
处理,它重新索引 整个项目 。
因此,在同时编辑的情况下,将生成两个 MODIFY 事件(每次编辑一个)。但是,last MODIFY 事件只有在 last 数据库编辑提交后才会被触发。因此,Solr 索引应始终与数据库中的最新信息同步。