-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Redo Akka.Persistence serialization #3811
Comments
I should point out: these issues and the bugs I'm fixing in #3744 are one of the reasons why Akka.Cluster.Sharding has been stuck in beta for so long. Coordinator fail-over and recovery is impossible without reliable serialization and deserialization of |
Example of stuff that should be deleted: akka.net/src/contrib/persistence/Akka.Persistence.Sql.Common/Journal/QueryExecutor.cs Lines 690 to 706 in 2ad84ee
Allowing the plugin to OVERRIDE the |
On top of that, having to directly expose both the manifest data AND the serializer ID directly into the schema of the Akka.Persistence plugins has been demonstrably brittle over the years - none of that would have even been necessary had we stuck with the original Akka.Persistence design in the first place, since that information is all neatly encapsulated internally. |
Regarding code snippet you've shown - I think that nowadays we have a method inside IMHO:
|
It's not just that we have a new method inside the 'Serialization' class - it's that we actively bypass the built-in persistence serializers so we never use the MessageSerializer or SnapshotSerializer formats, which (edit: Akka on the JVM) still use.
This wasn't an accident - this was a conscious decision we made around Akka.NET 1.3. As a result, many serializers don't properly support manifest serialization correctly, none that I know of support IActorRef serialization, and we have to actively evolve and migrate our schema for plugins like SQL. None of this would be an issue if we'd just used the envelopes - Protobuf does a much better job tolerating changes in versioning of Akka.Persistence's feature set and standardizing / eliminating errors from the serialization process than our hand rolled process ever could.
…Sent from my iPhone
On May 27, 2019, at 3:05 AM, Bartosz Sypytkowski ***@***.***> wrote:
Regarding code snippet you've shown - I think that nowadays we have a method inside Serialization class itself, that does exactly that.
IMHO:
We shouldn't be too eager to ditch existing mechanisms. Maybe it's possible to simply expose API used to serialize/deserialize akka specific types (like IActorRef)?
I'd take a look at how JVM akka resolves serialization in akka-typed (which AFAIK is a little different from. Also starting from v2.6 its changing default serialization to Jackson (see the issue). Maybe it's something worthwhile to learn from their approach.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
Another good example here: akkadotnet/Akka.Persistence.MongoDB#42 and here akkadotnet/Akka.Persistence.MongoDB#26 - Akka.Persistence.MongoDb couldn't support the built-in Cluster.Sharding serializers by default, since it was doing its own thing with serialization rather than using our Protobuf envelopes. |
To be clear though, @Horusiath is absolutely right about this:
The existing mechanisms are, by any objective standard, bad. But thousands of users have potentially years worth of data stored in them. The only way we could make this situation worse is to strand those users so they can't upgrade onto newer versions of Akka.NET without having to come up with their own hand-rolled ETL tools for Akka.Persistence data. I'd consider that an abdication of responsibility on the part of the Akka.NET project if we allowed that to happen. Therefore, I'm going to learn towards, to the extent that it is both feasible and possible, the following upgrade path:
|
This may be a crazy idea, but: what about making
Of course the problem would be to resolve current ActorSystem, but I think it's doable the same way we deal with current actor cell, using ThreadStatic. |
Related: #2933 |
* Akka.Persistence.SqlServer v1.3.14 upgrade * disabled serialization specs since akkadotnet/akka.net#3811 * fixed target to .NET 4.5
I am currently researching a method to persist the serialization data in a message. The idea is to have a special payload type that is normally serialized Maybe this payload-type would solve the this Akka.Persistence issue too. It would resolve some other issues:
Related: object/Akka.Persistence.Reminders#6 |
It's not a bug - you have to have a standard payload definition to determine what the user-defined message types are. The problem with Akka.Persistence is that we threw the standard Protobuf payload definition in the trash and forced all of that data to get stuck directly into the Akka.Persistence implementations themselves, which makes them very difficult to upgrade and has caused a lot of problems historically. This is a return to Keep it Simple(tm) - we're going to do what the JVM has been doing and let the Protobuf envelope, which can be changed easily without introducing these types of problems, do its job. |
Can this Protobuf envelope then be so generic that it can be used other places? Example: |
We already have it: akka.net/src/protobuf/Persistence.proto Lines 9 to 17 in 36a7267
It's just not being enforced by the underlying Akka.Persistence implementation. In Akka.Remote we do something similar: akka.net/src/protobuf/WireFormats.proto Lines 21 to 26 in 36a7267
akka.net/src/protobuf/ContainerFormats.proto Lines 33 to 50 in 36a7267
|
The envelope formats are only supposed to contain:
In Akka.Remote we also have to include the sender / receiver information; in Akka.Persistence we have to include the sequence number and entity id. |
thx, the protobuf types i didnt see. I made a sample implementation snipset in object/Akka.Persistence.Reminders#6 (comment) My point is that there is currently no pass-through transparent serialization feature The same goes for Akka.Persistence.
Maybe there is just a pass-thru Serializer missing, that takes the manifest, data-bytes and serializerId values directly from a serialized-payload message. ´´´ |
@Aaronontheweb Just to make sure I got it right: the payload (user provided message) inside the |
So yet another thing I've discovered while working on trying to get Akka.Persistence.Azure to do the right thing: #3965 There isn't a single plugin, as far as I'm aware, that actually passes our own serialization TCK that has been in-place since Akka.NET v1.3.0. This includes the SQL plugins and others. This is because our entire serialization approach isn't standardized across plugins and it puts a high burden onto individual plugin owners to implement them correctly, which our own team can't even do correctly, so it seems. Edit: and it doesn't help that our TCK is apparently implemented incorrectly and no one has bothered to notice. |
All user-defined messages will still be serialized using their configured serializers. It's just that the content being saved into Akka.Persistence itself will all be encoded inside a protobuf envelope that is standardized by Akka.Persistence, very similar to how we do it for Akka.Remote. |
For a proof of concept of how this will work, see akkadotnet/Akka.Persistence.MongoDB#71 implementing this in Akka.Persistence.MongoDb since the legacy "object" serialization is totally incompatible with |
how to use Text/Json serialization in debug mode? The main issue is that the journal itself needs currently to serialize/deserialize. I still thing a serialized-message type for serialization would makes more sens. A new layer/component would be required that:
This would help in other issues like:
|
Easiest way to do this would be via an The raison d'etre for doing this is twofold:
Building an entire second system for doing this with text, solely so people can read the messages that are being serialized in plain text through a third party database tool, has been a total disaster from a maintainability, version-tolerance, and implementation success standpoint. A small number of users involved in doing the maintenance work, myself among them, have had to bear significant costs fixing these incompatibilities when we could be doing more useful things like performance fixes. I've personally spent on the order of 200-300 hours working on these problems in 2019. We're done doing that - forever. If having Akka.Persistence data stored in human-readable format is a must-have for you, fork a plugin and bear the costs of maintaining it yourselves. The OSS organization isn't going to do that for free any more. It's an expensive drag on resources and time.
This is what I'm not trying to discourage innovation or creativity here - simply stating an economic truth: our defaults are bad, usually aren't implemented correctly, and this results in both bad experiences for end-users and a ton of maintenance work on both the part of the OSS community and Petabridge. The lesser of two evils is something that actually works reliably and correctly, most of the time, even if you can't easily read the output data in something like SMSS or whatever your chosen database platform is. The answer isn't to do the same thing we did before, but with even more abstractions, and hope it works - it's to follow a pattern that works via standardization of the serialization process. If you want to solve the "data readability" problem, do that on the read side with an independent Akka.Persistence reader tool, or even better - use an EventAdapter or a logger to solve that issue by writing the output into human-readable form elsewhere, instead of trying to do it with the application data itself. |
Thank you for answering my question. Yes, text representation is optional, i am using EventStore For the MongoDb workaround to add a NotSupportedException What about the proposal to extract the serialization logic It is currently not possible to pre-serialize with a poor EventAdapter, I already tried and spend only 10-20h on it,
The HashKey is required for the ConsistentHashRouter To have this message type in akka.dll and as an opt-in feature for An updated journal would then only need to take the SerializedPayload Maybe i am miss taken, but i don't see that this solution |
Do you have an example or some code we could look at? That might help me understand what you're trying to suggest better. |
So, gonna leave my comments here, since I've been neck deep in different implementations on the JVM Side while looking at Tag tables in SQL.
In persistence-jdbc, they're flattening everything down. Now, they absolutely MUST respect the object's defined serializer, but they do not serialize (BTW we probably should do this with tag table changes... yay for more compatibility flags!) |
Meaning PersistentRepresentation is no longer part of the payload? |
That would seem to be the case. Here's the actual serialize in persistence-cassandra. They grab the payload from the persistent repr, and as with persistence-jdbc they are unrolling tagged payloads. |
Truth be told, I think this issue is resolved - over the years we've made a lot of progress on making sure that all Akka.Persistence plugins properly support |
Version: 1.3.13 and later.
Without putting too fine a polish in it, it's clear to me after working on #3744 that the current implementation of Akka.Persistence serialization in Akka.NET is unsustainable and that a serious error in judgement was made when we decided to allow individual Akka.Persistence plugins to choose their own "native-friendly" serialization instead of relying on the Protobuf envelopes that Akka.Persistence provides by default. This is especially true of our Akka.Persistence.Sql plugins.
As the new Akka.Persistence.TCK specifications will make perfectly clear in Akka.NET v1.4.0+, it is very difficult for Akka.Persistence plugin implementations to correctly support things like
IActorRef
serialization since that requires access to some internal fields and properties, such asCurrentTransportInformation
that aren't meant to be exposed outside of Akka.NET for safety reasons.Most journal and snapshot store plugins will fail the new serialization checks, because the current design of many Akka.Persistence plugins requires them to come up with their own techniques for serialization, virtually none of which are consistent with Akka.NET best practices.
Going forward, we should to streamline everything on top of the built-in Akka.Persistence
MessageSerializer
andSnapshotSerializer
implementations so we can correctly support Akka.Persistence features like multi-tenant journals, snapshot stores, and more.This is too big and drastic of a change for v1.4.0, but I'd suggest we put it on the table for 1.5.0.
The text was updated successfully, but these errors were encountered: