TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

What they don’t tell you about event sourcing

234 点作者 jackthebadcat将近 7 年前

19 条评论

lscharen将近 7 年前
The last section on Operational Flexibility and the inability to change the event history raises a very good point.<p>Like most of the issues, the solution requires experience to know when you are at the Goldilocks point (Just Right). This specific issue has a lot in common with managing database migrations in django or any other migration system.<p>The ideal situation is to create migrations that can always be rolled back, but sometimes this is not possible to do operationally. For example, a schema change that restricts a field from NVARCHAR to INTEGER can only be generically rolled back if all of the unconvertable data is persisted. This can be mitigated by structuring the database to avoid these dead-ends, and that really is only gained by hard-won experience.<p>The problem with undoing operations via new events is the same thing -- unless you have foreknowledge of this kind of problem, it is very easy to accidentally create events that perform un-undoable actions. A very simple example of a problematic event would be something that modifies a foreign-key relationship -- let&#x27;s say it&#x27;s a digital asset in a game and you want the ability to transfer ownership of the item from one player to another.<p>The simple solution is a event like SetAssetOwner(asset_pk, player_pk). This would set the item&#x27;s player foreign key field to the player&#x27;s primary key. Easy. However, you have lost knowledge of where the asset came from and cannot undo this operation. A better solution would be to make an event SwapAssetOwner(asset_pk, owner_pk, recipient_pk). Yes, the owner_pk is technically redundant, but it provides a check against someone trying to steal an item with a maliciously crafted SetAssetOwner event that performs no checking. Even better, this operation can be reverted by sending the same event with the owner and recipient arguments reversed. Since these properties are part of the event message, they will be persisted in the event history and all of the information to undo the event is self-contained.
评论 #17820675 未加载
评论 #17821671 未加载
joefreeman将近 7 年前
Good article. I&#x27;ve spent the last year migrating to an event sourced system, so thought I&#x27;d share some thoughts.<p>On the eventual consistency point, I&#x27;ve found you can get quite far with having the read model managing the race condition. This probably doesn&#x27;t work everywhere, but in our system, multiple users can accept an invitation, so we have something like `InvitationAccepted{invitation_id, user_id}`. It&#x27;s possible that multiple users might accept the invitation at roughly the same time, but the command-side doesn&#x27;t really have to be concerned with this - it can happily allow multiple users to accept an invitation. It&#x27;s up to the read model to ask, &#x27;has this invitation already been accepted?&#x27; - if not, the acceptance is successful and will be indicated when queried, otherwise the acceptance is unsuccessful (and as a bonus, we can separately record who unsuccessfully tried to accept it). From the user&#x27;s point of view, when they accept the invitation, they see a spinner until we confirm with the read model one way or the other (this could be done by polling the read model, but in our case we have an event sent back to the client).<p>Coming up with the event schema and versioning&#x2F;granularity are hard. We have version numbers on all our events to make this a bit more manageable&#x2F;explicit (`InvitationAccepted1`, for example). Storing events in a relational database does make it a bit easier to go back and edit&#x2F;upgrade&#x2F;delete them (sort-of cheating, but also relevant for GDPR). Also, I think we&#x27;re going to end up suffering a bit from the &#x27;whole system fallacy&#x27;, but at the moment namespacing all the events (keeping in mind their expected volume) makes it a lot easier to manage.
评论 #17822944 未加载
评论 #17822917 未加载
评论 #17821626 未加载
评论 #17822190 未加载
7sigma将近 7 年前
Regarding eventual consistency, a CQRS\ES system can also be synchronous, or partially. You could have listeners for events that need to supply a strongly consistent model and others events that feed parts of the system that don&#x27;t need strong consistency.<p>&quot;However the events in a event store are immutable and can’t be deleted, to undo an action means sending the command with the opposite action&quot;<p>Well they don&#x27;t have to be immutable. I don&#x27;t see why you can&#x27;t update&#x2F;migrate events.
评论 #17817921 未加载
评论 #17818506 未加载
评论 #17818228 未加载
dmitriid将近 7 年前
Is it just me or the article never presented a solution to the posited problem: ”Since each entity is represented by a stream of events there is no way to reliable query the data. I have yet to meet an application that doesn’t require some sort of querying.”<p>The solution is said to be CQRS, and nothing in the article shows how you solve that.<p>If you unwind the unnecessarily winded florid poetic waxing, it all comes down to “dump it to a database, and query that”.
评论 #17820546 未加载
评论 #17817985 未加载
shady-lady将近 7 年前
Hopefully bi-temporal tables get added to Postgres soon.<p>I think it would cover a few of the use cases that people are turning to event sourcing for(excluding scale).
theptip将近 7 年前
I don&#x27;t see much discussion of event-sourcing simply using a SQL database (i.e. skipping the CQRS part). This would allow you to keep your CP (strongly-consistent) semantics.<p>While this clearly wouldn&#x27;t work in high-volume cases (i.e. where you _actually_ need CQRS), it seems like this would be the simplest option for many systems. I see a lot of articles advocating for immediately jumping into CQRS, which seems like a big increase in architectural complexity.<p>Does anyone have opinions&#x2F;experience on this approach?
评论 #17821514 未加载
评论 #17830526 未加载
评论 #17821050 未加载
评论 #17822113 未加载
dustingetz将近 7 年前
Strong consistency is possible with this model, consider for example git.<p>One real database that works like this is Datomic, which is competitive with SQL for most kinds of read-heavy data modeling loads that SQL and CQRS is used for.
subsubsub将近 7 年前
All the issues the author talks about are valid, however, the idea that no one warns you about them is wrong.<p>If you do even the most basic research into Event Sourcing you will find people warning of these trade offs (foremost amongst them Greg Young, the person who originally set out the idea)
likeclockwork将近 7 年前
I&#x27;ve never quite been able to get my head all the way around &quot;Eventual Consistency&quot;. I don&#x27;t understand how actions that could conflict or resources that could be contended are supposed to work? At some point, something has to say, given two actions A and B that are in conflict, the later action B must fail.<p>So, where does that happen? When getting written into the read model? Then what, it emits an event saying clearly that the previous action failed? All while there&#x27;s a client waiting for results?<p>I&#x27;d love to see a worked example based on discrete resources. Such as two people, a box, and a ball; where the ball can be held by either person or in the box, and a person can take the ball from the box but not from another person.<p>I find the concept intriguing but I don&#x27;t really get it and I haven&#x27;t been able to identify in any of the writing where &quot;the buck stops&quot;.
评论 #17823208 未加载
ninjakeyboard将近 7 年前
I&#x27;ve worked with event sourced systems quite a bit in production and at scale, and have written a book on Akka and another one on related topics. While I have been an advocate of the approach, My experiences are guiding me away from implementing Event Sourcing in many use cases (especially where the entities are long lived). While CQRS is more complex, I&#x27;m more likely to implement CQRS without event sourcing, where an entity is responsible for its own persistence using whatever mechanism we deem suitable, and emits events that can be used for the view (or the data can be viewed as read only.) Ultimately a bounded context is there, and you send it commands and get out events. You have to evaluate the recovery and persistence mechanism based on your needs. Exactly once delivery is a pipedream so it doesn&#x27;t matter how you&#x27;re persisting the event and delivering it, evaluating line by line, crashing somewhere it&#x27;s going to be possible to emit an event twice somewhere (eg if the outbound projection emits the event but doesn&#x27;t persist its offset.) You need to deduplicate somewhere to get exactly once processing semantics. There _are_ simpler approaches to persistence that work just fine with the same delivery guarantees that work fine in the place of Event Sourcing. Nobody talks about any alternatives though - everyone defaults to event sourcing. My intuition guides me to look at other options having been burned one too many times, watching organizations collapse around 100% event sourced applications, etc.<p>I&#x27;m still working on event&#x2F;message driven systems (today with Elixir mostly) but I&#x27;ve started to make architectural compromises to move away from especially event sourcing. Event Sourcing + CQRS may be prescriptive but it&#x27;s very hard for new developers to pick up and understand the layers of abstraction underneath eg Akka + the Persistence Journal. And I&#x27;m not sure I can trust many of the open source libraries outside of Akka to be honest. I&#x27;ve had to dig into the depths of postgres journal implementations and apply windowing to journal queries for example because they weren&#x27;t burned in at the scale I was working with (partially because I inherited an application with a single entity in a context which had many million line long journals - this highlights a design error though but hopefully you can see my point.)<p>You don&#x27;t _need_ to use these patterns but you can still apply DDD and event&#x2F;message based abstractions, and publish events. An entity can write its state to a record and then apply the state in memory as well without using a journal given you handle exactly once processing semantics correctly. This means there are knobs and dials. The problem with event sourcing in the greater picture is that it&#x27;s descriptive of an approach, and there aren&#x27;t many clear alternatives that people are talking about that work in similar system designs. If you have very long lived entities, or only a few of them, it gets especially difficult to keep the system alive over time, but for those use cases it doesn&#x27;t mean you should stop receiving commands and emitting events.<p>You always here about the idea of the approach, never the reality of maintaining these systems, or the inappropriate use. In one implementation, there is one entity that receives thousands of events a day, and lives forever. How do you maintain the journal while changing the code, keep it alive over time? I&#x27;ve watched event sourcing and CQRS sink projects and teams. I&#x27;ve watched well paid contractors unable to figure out how to cluster and scale these systems. The barrier to entry for people to become effective can be high and you should understand the long view in terms of people required and cost over time and validate the approach for your use case very carefully. Again, the fact that everyone talks about event sourcing and no closely related alternatives makes it seem like the gold standard or the only option but there are other (simpler) ways to deal with your persistence in an overall similar architectural approach.
评论 #17818173 未加载
评论 #17820178 未加载
评论 #17822012 未加载
gazarsgo将近 7 年前
It&#x27;s really important to manage versioned schema for events and defining rules around evolution of schemas, hopefully with tooling support like via Avro&#x27;s Schema Registry or Protobuf&#x27;s forward and backwards compatibility guarantees.
sigi45将近 7 年前
Still like the idea but it is more complex to do it right and keep it right.<p>Would only do this with a good team and a real problem where this would be useful.<p>Rdbm goes very far
chrisweekly将近 7 年前
CQRS: &quot;Command Query Responsibility Segregation&quot;<p>Fowler&#x27;s post is predictably excellent: <a href="https:&#x2F;&#x2F;www.martinfowler.com&#x2F;bliki&#x2F;CQRS.html" rel="nofollow">https:&#x2F;&#x2F;www.martinfowler.com&#x2F;bliki&#x2F;CQRS.html</a>
评论 #17818343 未加载
mamcx将近 7 年前
CQRS &amp; Event Sourcing are good ideas, but putting yourself ON PURPOSE with eventual consistency is <i>nuts</i>.<p>Until your are in the facebook-big-data scaling challenging, you don&#x27;t need the madness of lose ACID. You can get terabytes of data easily on a single server, and even partition by company, customer or similar that still allow to keep domain-level consistence.<p>Now, I put the events after my normal CRUD operations (ie: I emit CRUD + Save to event in a single transaction). Is super easy of operate and keep coding familiar and predictable<p>----<p>I think the ideal EE database engine must be like:<p>Have a log Table, and a index&#x2F;subtables for each validation (ie: to check uniques, aggregates, counts, etc.)<p>So, if a have a customer related events, I have:<p>- Index on: code, name<p>- SubTable: code, name, isactive<p>all the other fields are not need for validation so are recovered from the log.<p>In ACID:<p>- POST Command<p>- Validate data with the index,<p>- Save to log<p>- Emit blocking events (events that need to be at the same time after the save)<p>- Commit<p>Eventual:<p>- Emit lazy events (events that not need ACID, like to fill external sources)
marknadal将近 7 年前
I&#x27;m glad somebody else said it. It seems lately a new meme is coming around (by many people independently) all saying:<p>Wait, event sourcing &#x2F; immutable data doesn&#x27;t scale.<p>I was doing event sourcing in 2010, and loved it. It was incredible. But by the time I started hearing people call it &quot;event sourcing&quot; I had already moved on to:<p>State-based, graph CRDTs.<p>They combine the best of event sourcing with the best of distributed state replication, and are super scalable!<p>Now even the Internet Archive[1] is running it (in 2014 I implemented it into a library that they are now using - <a href="https:&#x2F;&#x2F;github.com&#x2F;amark&#x2F;gun" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;amark&#x2F;gun</a> )<p>[1] <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=17685682" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=17685682</a>
ulcica将近 7 年前
They didn&#x27;t even tell me what event sourcing is.
评论 #17817799 未加载
评论 #17817944 未加载
评论 #17817790 未加载
评论 #17817875 未加载
评论 #17817818 未加载
trhway将近 7 年前
Sounds like OLTP transactions and aggregated state only with hip names.
jackthebadcat将近 7 年前
Guys, just need to say that this article is not mine!
ryanmarsh将近 7 年前
<i>If we choose to build a business critical functionality around this eventual consistency can have dire ramifications. There are use cases that availability is the needed property of a system but there are also use cases where consistency also is, where is better to not make a decision rather than making it based on stale information.</i><p>I see this issue raised quiet often. If consistency is paramount you can make commands on certain aggregates be synchronous all the way to updating the read model. There&#x27;s nothing that says you MUST have a queue in-between the event log for an aggregate and the logic that updates the read model. Use common sense.<p><i>Typically shines the most when pinpointing parts of the system that benefit from it, identifying a specific bounded context in DDD terms, but never on a whole system.</i><p>I feel like Greg Young has taken great pains to make this clear. This should be taken for granted when attempting CQRS.<p><i>Also your events will be based on a SomethingCreated or SomethingUpdated which has no business value at all. If the events are being designing like this then it is clear you’re not using DDD at all and you’re better of without event sourcing. Finally, depending on the requirements on how the synchronous the UI and the flow of the task is the eventual consistency can, and most of the times will, have a klinky feel to it and deliver a poor user experience.</i><p>If the read and write model are being updated asynchronously from the UI you&#x27;re gonna have to adopt an optimistic caching scheme on the client. This is why GraphQL subscriptions are pretty much boilerplate for any client I build against a CQRS service. The Apollo client seems to handle this rather well.<p><i>Converting data between two different schemas while continuing the operation of the system is a challenge when that system is expected to be always available. Due to the very nature of software development new requirements are bound to appear that will affect the schema of your events that is inevitable.</i><p>I hereby give you permission to use the Strategy Pattern. Problem solved.<p><i>The events can’t be too small, neither too large they have to be just right. Having the instinct to get it right requires an extensive knowledge of the system, business and consumer applications, it’s very easy to choose the wrong design.</i><p>Greg Young and others have talked quite a bit about how to bound aggregates.<p><i>However the events in a event store are immutable and can’t be deleted, to undo an action means sending the command with the opposite action.</i><p>This is why bookkeeping systems have the idea of &quot;journal entries&quot;. I haven&#x27;t implemented one for an event sourced system but I can see how this might work.<p>Overall great post. Really enjoyed that the author took the time to walk us through all of these issues. Most are non-trivial.