3 ms·
I can't upvote this enough. The game backend I've been leading uses event sourcing for almost every "object" in our system. It's proven flexible enough to mode
by hesdeadjim 11y ago
I can't upvote this enough.
The game backend I've been leading uses event sourcing for almost every "object" in our system. It's proven flexible enough to model both normal CRUD style access patterns and other activity feed-like features that may or may not have an aggregate state.
Some huge advantages we've identified:
* Modeling our objects as state changes has resulted in less code and improved readability. The effects of a state change are much more obvious than a series of CRUD-style updates. This is anecdotal of course.
* Audit trail, we have every mutation for every object in our system. We can go back in time and identify bugs and fix them by just overlaying new change events. We can also feed this data into any number analytics systems and create materialized views without having to know in advance what kind of data we wish to collect.
* Optimal performance characteristics for our chosen DBs (Redis+DynamoDB). We use Redis for storing incoming events, and DynamoDB to store our periodic snapshots that compress the aggregate state for an object (and keep the event history). This allows us to keep our Redis space usage bounded, as compressions flush the queue for each object. We optimize for DynamoDB pricing/performance by only needing eventually consistent reads for obtaining a snapshot. We keep our write capacity low because the only writes are when we write a new snapshot -- this happens much less frequently and is allowed to fail since a failure only means we continue using the previous snapshot.
* Consistent point in time snapshots. To obtain a backup of the objects, we simply need to snapshot our Redis databases. If we restore, all objects are consistent because the per-object snapshots we store in DynamoDB are immutable and will always exist with any given state of the Redis data. Another consequence of this architecture is that we can take an old snapshot and "go back in time" to the real state of the data.
* Highly concurrent without need for optimistic or pessimistic locking. Redis is obviously super performant and all we use it for is to push event items to the back of lists. For concurrency and conflicts, we can resolve the state of an object by de-duping events that may be invalid or duplicate from the point-in-time view of the aggregate object when the event was pushed. Obviously this won't work for every type of object state, but in our experience it has been extremely resilient.
A few disadvantages:
* Views on the objects must be eventually consistent and must be materialized externally to the storage of the objects.
* More CPU required to create the aggregate state when getting the object. Hasn't been an issue for us and can be mitigated by the frequency of compaction into snapshots.
* Space usage for snapshots. Eventually long lived objects will have a significant cumulative historical size. It's trivial though to traverse the snapshot history and trim the space usage by simply discarding snapshots after a certain point in time. The object will then be constructed from the last snapshot's aggregate state and events that happen after the purge.
- numbsafari 11y agoIs your project a product or OSS? I've been tinkering with a simple game back-end for building up turn-based, multi-player games (an engine for ripping off board games) mostly as a demo/proving ground for ideas and not as a serious project since this is a pretty active space with established projects.
- hesdeadjim 11y agoUnfortunately its proprietary for our studio's games. I've been hoping I could release some parts of the infrastructure as OSS, but I might have to settle for a presentation at some point.
- belenos46 11y agoAre you part of the team building Underworld Ascendant? Because that sounds very much their speed.
- hesdeadjim 11y agoOh man I wish I was. Those games were practically life changing as a child. At one point my parents moved our computer into the bedroom to stop us from playing all hours of the night. They then woke up on a Saturday morning to a friend and I sitting on the edge of their bed playing. That did not go over well -- but they did move it out of their room after that!