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. 用户 1 和用户 2 同时编辑同一个项目的标题。
  2. 编辑将在数据库级别同步,以便第一个发生。假设用户 1 的编辑先发生,然后是用户 2 的编辑。
  3. 用户 1 的编辑将触发 Solr 中的重建索引。用户 2 的编辑也是如此。这意味着同一个项目将被重新索引两次(一次是 每次编辑)。这些重新索引与特定更新无关(因此第一个重新索引不仅索引标题),而只是告诉 Solr 该项目已更新并且需要重新索引。
  4. 在第一次重建索引时,用户 1 的编辑已经完成,因此项目将使用该标题编制索引
  5. 到第二次重建索引时,用户 2 的编辑已经完成(因为重建索引本质上比将编辑保存到 DB 层需要更长的时间),因此项目将使用更新后的(重新)索引标题.

所以,这里的简单答案是 DSpace 不会重新索引单个修改(如果不与数据库编辑同步,最终可能会乱序)。相反,它跟踪哪些 object 已更新并触发整个 object 元数据的重新索引。虽然这看起来像 "overkill",但在 Solr 中对单个 object 的重新索引并不是所有的过程密集型,它确保 object 的 current/latest 元数据被索引在 Solr 中(在同时写入的情况下)。

更新:根据要求(在下面的评论中),这里详细介绍了 DSpace 如何执行重建索引(在 Solr 中)。

  1. DSpace 有一个定义的事件系统。它遵循本节 dspace.cfg 中的配置:https://github.com/DSpace/DSpace/blob/dspace-5_x/dspace/config/dspace.cfg#L732
  2. 默认情况下,在 DSpace 5 中,IndexEventConsumer 是为 Solr 执行索引的。它在此处默认配置:https://github.com/DSpace/DSpace/blob/dspace-5_x/dspace/config/dspace.cfg#L732
  3. 在 DSpace 5 中,每当有人更改项目的元数据(或关于项目的任何内容)时,都会调用 Item.update() 方法将更改实际保存回数据库层。
  4. 保存所有更改后(使用 DatabaseManager.update()),Item.update() 方法生成 new MODIFY event in the Event System.
  5. 新的 MODIFY 事件附加到 LinkedList of events in the current Context
  6. 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)
  7. IndexEventConsumer 将更新列表 object 传递给索引服务(默认为 SolrServiceImpl)。
  8. 最后,SolrServiceImpl.indexContent() 从数据库中读取最新的元数据值并在 Solr 中为它们编制索引。

上面的逻辑仍然有点简化(因为它太复杂了,无法遍历代码的每一步)。但是,这里的基本要点是每个 Item.update() 调用都被视为一个数据库事务。它还会触发存储在用户 session(上下文 object)中的修改事件的添加。一旦提交了数据库事务,MODIFY 事件就由 IndexEventConsumer 处理,它重新索引 整个项目

因此,在同时编辑的情况下,将生成两个 MODIFY 事件(每次编辑一个)。但是,last MODIFY 事件只有在 last 数据库编辑提交后才会被触发。因此,Solr 索引应始终与数据库中的最新信息同步。