【问题标题】:Event Store using nosql performance considerations事件存储使用 nosql 性能注意事项
【发布时间】:2020-10-27 18:24:12
【问题描述】:

这可能更像是一个普通的 NOSQL 基础架构问题。

使用事件溯源系统,我将事件文档保存到 ravendb。

在我的领域模型中有多种类型的事件,下面是一个基本示例:

public abstract class Event
{
    public Guid AggregateId { get; set; }

    public Event(Guid aggregateId)
    {
        AggregateId = aggregateId;
    }
}

public class NewPersonEvent : Event
{
    public string Name { get; set; }

    public NewPersonEvent(Guid id, string name) : Base(id)
    {
        Name = name;
    }
}

public class NewOrderEvent : Event
{
    public DateTime OrderDate { get; set; }
    public double OrderCost { get; set;}


    public NewOrderEvent(Guid id, DateTime date, double cost) : Base(id)
    {
        OrderDate = date;
        OrderCost = cost;
    }
}

无论事件来自什么类型的聚合,事件都会作为事件文档持久化。

这是在 ravendb 中为所有事件使用一种文档类型的最佳方法吗?或者对每个聚合的文档类型进行分组有什么好处

不再只有“Event”文档,而是有“PersonEvent”文档和“OrderEvent”文档。

这两种方法各自的优缺点是什么,具体来说是否存在性能问题?

【问题讨论】:

标签: ravendb event-sourcing


【解决方案1】:

您是否将事件的默认标签名称覆盖为...

docStore.Conventions.FindTypeTagName = type => typeof(Event).IsAssignableFrom(type) ? DocumentConvention.DefaultTypeTagName(typeof(Event)) : DocumentConvention.DefaultTypeTagName(type);

然后,每当您对Event 进行查询时,它就会正常工作并检索所有事件。 session.Query<Event>()

如果是这样,您可以自取其辱,因为如果您只想要事件的一个子集并且执行此操作session.Query<NewPersonEvent>(),它将检索所有事件,因为您在一开始就覆盖了标签约定。 你仍然可以用另一种方式来做,但它不会那么简单(例如,有一个事件类型的枚举并按枚举过滤)。

我会投票不覆盖默认的 RavenDB 行为,将不同的事件类型保留为它们自己的文档集合,并简单地使用多映射索引。

Raven 文档指出静态索引优于动态索引,因此它不应该成为性能问题。 docs:

如果您不混淆标签约定,但您可以为事件的子集创建更多索引,创建 map/reduce 索引以聚合每种事件类型的计数,等等。

索引将是一个多地图索引,您可以选择 2 种风格。

选项 1

    public class Events_All : AbstractMultiMapIndexCreationTask
    {
        public Events_All()
        {
            AddMap<NewPersonEvent>(newPersonEvents =>
                from newPersonEvent in newPersonEvents
                select new
                {
                    Id   = newPersonEvent.AggregateId
                });

            AddMap<NewOrderEvent>(newOrderEvents =>
                from newOrderEvent in newOrderEvents
                select new
                {
                    Id   = newOrderEvent.AggregateId
                });
        }

    }

选项 2(反思)

public class Events_All2 : AbstractMultiMapIndexCreationTask
{
    public Events_All2()
    {
        AddMapForAll<Event>(events =>
            from @event in events
            select new
            {
                Id   = @event.AggregateId
            });
    }
}

这是使用RavenDB.Tests.HelpersShouldly NuGet 包的示例测试。它使用第一个示例索引,但您也可以修改它以使用第二个。

    public class MultimapIndexTest : RavenTestBase
    {
        private readonly Random _random = new Random();

        [Fact]
        public void GetAll_HasBoth_Success()
        {
            //Arrange
            const string personName = "Jimmy";
            double randomCost = _random.Next();

            var event1 = new NewPersonEvent(Guid.NewGuid(), personName);
            var event2 = new NewOrderEvent(Guid.NewGuid(), DateTime.Now, randomCost);

            using (var docStore = NewDocumentStore())
            {
                docStore.ExecuteIndex(new Events_All());

                using (var sesion = docStore.OpenSession())
                {
                    sesion.Store(event1);
                    sesion.Store(event2);
                    sesion.SaveChanges();
                }

                docStore.WaitForStaleIndexesToComplete();

                //Act
                var events = GetAll(docStore).ToList();

                //Assert
                events.ShouldNotBeEmpty();
                events.Count().ShouldBe(2);

                var newPersonEvent = events.FirstOrDefault(x => x is NewPersonEvent) as NewPersonEvent;
                newPersonEvent.ShouldNotBe(null);
                newPersonEvent.Name.ShouldBe(personName);

                var newOrderEvent = events.FirstOrDefault(x => x is NewOrderEvent) as NewOrderEvent;
                newOrderEvent.ShouldNotBe(null);
                newOrderEvent.OrderCost.ShouldBe(randomCost);
            }
        }

        private IEnumerable<Event> GetAll(DocumentStore docStore)
        {
            using (var session = docStore.OpenSession())
            {
                return session.Query<Event, Events_All>();
            }
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-16
    • 2017-01-24
    • 1970-01-01
    • 1970-01-01
    • 2011-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多