What is inside the database layer?

The product looks very interesting, there are some questions I didn’t understand really well after looking at the documentation.
What is inside the database layer? How do I do some complex aggregations? How does all of that work?

1 Like

When thinking about Kalix, it’s best not to think about there being a “database layer”. Kalix is not an n-tier architecture. It is not correct to think of it in terms of layers or tiers. There is your code, and your code is supplied with the state it needs when and where it needs it. Kalix manages the mechanics of that, in a very intentionally opaque way. The best way for you to think about it is that your state is stored in memory with your code. Kalix is responsible for passivating entities to durable persistence when they aren’t needed (to reclaim memory), and rehydrating them from durable persistence when they are needed, as well as sharding them across nodes (so each entity only exists in one place and can be strongly consistent), and replicating across nodes for replicated entities. In future, we will also handle replicating between regions, and between the cloud and the edge. But all that is intentionally opaque. We do have a distributed database that we persist state to, but that’s not a concern developers using Kalix should ever need to concern themselves with.

For aggregations, the functionality we currently offer is quite limited, we currently only support aggregating a single entity type, essentially allowing the provision of indexes on fields other than the entity id for a given entity type. Underneath this is backed by a database, but again, it’s opaque. We do hope in future to add joins between entity types, potentially both materialized and non-materialized, and possibly aggregations of rows together (count, sum etc).

4 Likes

Thanks! That’s a brilliant explanation.
This approach seems new to me.
One of the things that I often see in the projects is that the data science team gets access to the DB layer to do SQL queries or some other analytics including some ml algorithms on the data.

Is there going to be a way to access all that data, or it’s just not a good case for this pattern?

Our recommended approach in that instance would be to publish the events to a Kafka or Google PubSub topic. Event sourced entities have an event stream out that can be published to a message broker, and value entities have a change stream out that likewise can be published to a message broker. Once in the message broker, the data science team can consume the events/changes, and process those streams in whatever way makes sense to them, that might be saving the events to an SQL database for ad-hoc queries, or it might be some streaming data processing.

Makes sense. What about transactions? Do they exist, what transaction isolation levels?

Kalix entities are strongly consistent without transactions, Kalix guarantees this. The way it does this is by dynamically sharding entities across the nodes that the entities run on, routing all commands to a given entity (by id) to the right node for that entity, and then on that node, running each command that arrives for that entity one at a time. Since Kalix can guarantee only one command will be run for any given entity at a time, transactions aren’t needed, we have actual linearized reads and writes, we don’t need transactions to simulate that.

That’s within an entity. Outside of an entity, all bets are off, there are no transactions, if you try to update two entities in sequence, and the second fails, the first won’t be rolled back. This is a natural consequence of Kalix’s state model, and while this lack of transactions may be limiting in some ways, in other ways it’s freeing - it allows Kalix services to scale truly horizontally, there are no nasty hidden hotspots or bottlenecks that you’ll encounter as you scale up due to transactions. It also allows the large variety of state models, including replicating between regions and to the edge, that we hope to provide in future.

The way to work around this is to use the saga pattern, when you have a workflow of operations that track the state of an operation and drive the progression of the saga from event streams. Currently this must be implemented manually in Kalix, though we do hope to some day provide first class support for sagas/workflows.

Views are eventually consistent, as is publishing an event stream from an entity to a message broker.

6 Likes

Hi James,

Thanks a lot for all those detailed clarifications.

I understand the power of Kalix comes from all the Akka components that underpin it.

My question however is : for a lot of companies their data is really essential and is looked at as something really precious. You never want to lose it right.

With the Kalix approach the lifecycle of the data seems to be getting tightly coupled with the lifecycle of the service.

However, aren’t you in a lot of cases trying to regularly refresh your service layer on top of a more long lived data layer that has a different lifecycle than the service ?

It would help if Lightbend could clarify better how they intend to deal with those challenges.

Perhaps I could try to answer it myself, but correct me if I got it wrong.

Let’s look at Kalix as a way of building stateful services, but not necessarily systems of reference.

Kalix helps you in building services that are stateful from a processing perspective, allow you to solve most of the challenges in this space but typically the data stored as part of the state is more to be looked at as fairly short-lived processing state, rather than establishing an architecture to use permanent data stores that you would consider as the backbone of your enterprise.

So, I guess it may get its inputs from calling other services or message queues as input and if there is something to keep beyond the concrete process the Kalix service is intended to support, you would also push information out to a more permanent data store (a system of reference) ?

Perhaps Kalix is the better version of Cloud Foundry in the end : enabling you to build stateful services without worrying about the data persistence at all.

I think in a Kalix app, the data has just as much importance than in any traditional app. I’m not sure why that wouldn’t be the case? In fact, I would argue that Kalix allows data to have an even higher level of importance than traditional apps, especially when using event sourced entities, because in that case, inherent in the data is an audit trail of exactly what happened when, which means you can reproduce the state of the system at any time in the past. You can’t do that in traditional architectures.

I assume what you’re talking about is that you might have a service that implements a certain business process, and as part of that process, updates table X, but then in 5 years time, that business process changes fundamentally, and that service is decommissioned, meanwhile, a new service is written to implement a new business process, which updates table X? Is that the sort of thing you’re talking about? I would describe that as an anti-pattern, because the problem then is that it leads to spaghetti architectures where no one has clear ownership of data, and no one really knows what services depend on what data. This leads to a system where the smallest of changes take much longer to implement than they should because the system is so fragile.

A service should completely own its data, nothing else should have access to it, except through public interfaces that that service defines. This is the principal of encapsulation, it’s the same reason why in object oriented programming, a classes fields are made private and can only be modified through its public interface.

But encapsulation doesn’t mean that the data for that service is less important or can’t outlive the service. What it does mean is that a new service that replaces it and depends on the same data must use a public interface defined by the old service to migrate that data into itself. And again, this is where Kalix shines, because Kalix gives you event streams that allow a service to offer a public interface to consume its entire dataset. More than that, these event streams are online, you can effectively use them to keep the old service and new services data in sync while they are still running, there’s no need for an outage, and in fact you can progressively phase in a new service over months or years as the owner of the data, you don’t need big cutovers.

1 Like

The micro-service architectures are indeed a paradigm shift : a service or application is no longer tapping into something that exists in its own right while the application may just be one of the potential producers / consumers of the data in the store, instead the application owns the data, but isn’t that exactly confirming what I was saying ? The data’s life-cycle is tightly coupled with that of the service : if you press the delete button on the service entry, your data will be gone too. Perhaps that is something some people might still have to get used to.

I agree that there are certainly ways of meeting those challenges also in the new context of micro-services in the ways you have described.

No doubt however, people shoud be made aware that deleting a service going forward is a much more impactful operation than it might have tradionally been : you are not just removing a port or adapter into a stable data layer, you are annihilating all the information too. That was my point.

Building a new service for the same business domain will also mean, that the project should include a data migration project from the old service to the new service if you want to keep a continuous historical data record.

Not every application though requires CQRS, so it is a nice evolution in the Akka architecture that with Akka persistence you now have this flexible choice between ES (and CQRS if you need to) and classic persistence or even just replicated data for certain scenarios with CRDTs. That’s what I see as a really nice feature in this architecture. No persistence headaches but still various approaches you can choose to implement.

1 Like

How do we use existing database for the services we want to port to kalix? Also if we need to spin up a local dev environment and want to have a test database, how can we do this through docker? This is a common usecase for a team working on a single service.

@sameerargade I think you’ve misunderstood how Kalix uses databases. Kalix does not grant you access to perform queries directly on a database. It stores data using its own schemas, which are private and considered an implementation detail. It would not make sense to grant Kalix access to an existing database with existing data as the data in that database would not be stored using Kalix’s schema.

Kalix provides a development environment that uses in-memory storage. No database is needed, the Kalix proxy stores the data itself. The documentation for this can be found here:

makes sense, however what if we have default list of values to chose from, where are we expected to store them, or do we create a LOVService outside of kalix, and access it from kalix?