有关设置的简短说明:
我正在尝试使用RDBMS(以我的情况为Postgres)实现“基本”事件存储/事件源应用程序。这些事件是通用事件,仅具有一些基本字段,例如eventtime
,location
,action
,格式为XML。由于这种总体结构,现在有一种以有用的方式对它们进行分区的方法。这些事件是通过Java应用程序捕获的,该Java应用程序验证事件,然后将其存储在事件表中。每个事件在捕获后都会分别得到uuid
和recordtime
。
此外,可以有外部应用程序的订阅,这些订阅应获取与自定义条件匹配的所有事件。当捕获到一个新的匹配事件时,应将该事件推送给订户。为了确保订阅者不会错过任何事件,我目前正在强制将捕获过程设为单线程。当新事件进入时,将设置一个锁定,该事件将获得一个分配给当前时间的recordtime
,并且该事件最终将插入到DB表中(明确等待提交)。然后释放锁。对于计划每5秒运行一次的订阅,我跟踪上次发送的事件的recordtime
,并执行对where recordtime > subscription_recordtime
之类的新事件的查询。当匹配事件成功推送到订户时,subscription_recordtime
被设置为最大事件recordtime
。
实际上一切正常,但是您可以想象,单线程捕获过程的伸缩性不是很好。因此,主要问题是:如何优化此功能,并允许多个捕获进程并行运行?
我已经考虑过在插入时在数据库本身中设置recordtime
,但是由于不能保证提交的顺序(JVM暂停),所以我认为当两个捕获事务几乎在运行时会丢失事件。同时。当我正确理解数据库生成的时间戳时,它将在实际提交之前设置。因此,具有recordtime
t2 的事务对于预订查询已经是可见的,尽管具有recordtime
t1 ( t1 < t2 ),仍在进行中,因此尚未提交。订阅的recordtime
将设置为 t2 ,因此事务1中的事件将丢失...
是否有一种方法可以保证在数据库级别上的顺序,以便按捕获/提交事件的顺序显示事件?每个新可见的事件必须具有比之前的事件晚的时间戳(严格单调增加)。我知道全表锁,但是我认为,与以前一样,我将受到同样的性能损失。
是否可以将 DB 设置为使用单线程编写器?然后,每个捕获过程也将等待另一个写TX完成,但是在数据库级别,这比单个实例/线程捕获应用程序要好得多。还是可以使用其他字段/ ID来跟踪当前状态?普通序列ID也会遭受相同的原因。
答案 0 :(得分:0)
是否可以在数据库级别上保证顺序,以便事件以捕获/提交的顺序可见?
您不必担心事件的全局排序。您的事件应包含Version属性。在编写事件时,应该始终为给定的聚合/流ID 单调增加版本号。这实际上是插入时唯一重要的顺序。对于具有事件1、2、3和4的客户ABC,您只应编写事件5。
使用上述规则,数据库事务可以确保流中的正确顺序。
对于预定每5秒运行一次的订阅,我跟踪上次发送事件的记录时间,并对新事件执行查询,例如recordtime> subscription_recordtime。
阅读事件是一个略有不同的故事。首先,您可能会有一个串行列来唯一标识事件。这将为您排序,并让您确定是否已阅读所有事件。当您从商店读取事件时,如果您检测到序列中的间隔。如果您在阅读最新事件时正在插页,则会发生这种情况。在这种情况下,只需重新读取数据,看看差距是否消失。这需要您的订阅来维持它在索引中的位置。替代地或附加地,您可以读取至少N毫秒的事件,其中N是足以补偿事务延迟(例如500或1000)的阈值。
此外,请记住,您可以在流程中使用或利用开源RDBMS事件存储。
马丁:http://jasperfx.github.io/marten/documentation/events/
SqlStreamStore :https://github.com/SQLStreamStore/SQLStreamStore