 Okay, let's get started. Welcome everyone, thank you very much for taking time out of your day to join us for today's CNCF webinar, transactional, excuse me, transactional microservices with the test coordination without scale. I'm Jerry Fountain, and I will be moderating today's webinar. We would like to welcome our presenter today, Daniel Kozlowski, Minister of Engineering at PlanetScale. Just a few housekeeping items before we get started. During the webinar, you are not able to talk as an attendee. There is a Q&A box at the bottom of your screen. Please feel free to drop your questions in there and we'll get to as many as we can at the end. This is an official webinar of the CNCF and as such is subject to the CNCF Code of Conduct. Please do not add anything to the chat or questions that would be in violation of the Code of Conduct. Please be respectful of your fellow participants and presenters. Please also note that the recording and slides will be posted later today to the CNCF webinar page at cncf.io slash webinars. And with that, I will hand it over to Daniel for today's webinar. Great, thank you so much. As Jerry said, my name is Dan Kozlowski. I am a maintainer of Vites, which is a CNCF project. I'm also the Minister of Engineering at a company called PlanetScale. PlanetScale was founded by one of the creators of Vites and we work on Vites and we run a database as a service based off of it. And one of the things we get asked a lot is as people are looking at their services, either trying to scale or thinking about scale in the future, a lot of times they're talking about moving to microservices. This has been traditionally one of the ways that you would get additional scale out of your application. If you split it up, then you can get more thorough put. So people come to us and talk to us all the time. There are lots of problems that we see people face and as database scaling experts, we generally have some advice for them about what you can do and how you can use Vites to solve those problems. But as we're developing the product, Vites also brings some extra features to the database realm that are really unique to Vites that allow you to do some things that I don't think any other database lets you do. So I wanted to put together a demo of how we can use those. This is still not a widely used technology for the test. The pieces have been around for a very long time, but we're really exploring what can be done here and we're kind of pushing how you can use the tests with microservices. So some of the things that you're gonna see today are brand new. The code will be made available and please write down as many questions as you have. I'm not used to this one-sided talking thing. I really like interaction. So would love to answer your questions as we move through the presentation, but I have to wait till the end. So let's get started. First, what do I mean when I say monolith and microservice? So a monolith, I generally would define like this. It is a service which may be split into different modules depending on the size of the service, depending on the size of the team. It may be split apart, but generally the defining characteristic is it's built and deployed as a single service, as a single binary, a single process. So this may be in Java, it may be in Go, it could be in Ruby, it could be in any language, but it's going to be one deployable that goes out. And it doesn't mean it's singular, there may be multiple. So you are obviously following best practices. You have implemented the 12 factor methodology. So you don't have any state in this service. You can run as many of these as you want to horizontally scale them. However, state is always pushed outside and traditionally that is to a database, either a relational or a non-relational database. And so your monolithic architecture may look like this. The client comes in, it'll hit the service, all the module, the service would communicate with the database. This is really useful because your application probably has some transaction architecture built into it. Very common for any service that has complex logic to require transactions. And so your transaction architecture may look like this. It may go to one module, which begins a transaction, gets some data, that connection, which contains the transaction information is passed to another module through IPC. And then we can do some more selects, maybe an insert, maybe an update. Finally, we will commit to the transaction and everything's either gonna happen or it's not gonna happen. We're gonna have nice asset properties and our users are always gonna see consistent state. So this might be our traditional transaction architecture in our traditional monolith architecture. Well, what happens when we move to microservices? Generally the best practice when you're moving to microservices is to have an architecture that looks something like this. You may have multiple services. Those services will probably sit behind some sort of coordinator in this diagram here. I have an API gateway, but there's lots of ways to do it. And you're still following that great 12-factor methodology. So you're not storing state in your services. You are pushing the state outside of your service into a database. You'll find a lot of different information about how this should be done because there really isn't a great way to do this. There's trade-offs on either side. I think the general recommendation, if you were to ask 100 people, most of them would say you do database per service. This is what we have seen at PlanetScale as people have come to us. We have seen individuals going database per service. So my modules have turned into services. The defining characteristic here is I can have shared code. I can have not shared code. But what I have is three separate deployable objects. They're versioned independently. They're deployed independently. I can lifecycle them independently. And because of that, they're talking to databases independently. That causes some issues when we're talking about our transaction architecture because in the monolithic architecture, we were passing our connection through IPC so we could actually maintain the same database connection and we could maintain a transaction between the different modules. As soon as we move to microservices, we lose that capability. You can't actually maintain the transaction. There are different databases. So you have to do something else to have transactions or to have any complex business logic with your microservices. But wait, what if I just use the same database? Well, this is not really gonna solve any of your problems. What's going to happen here is your independent services, while they are still microservices, they're still versioned and life-cycled independently. They now have a shared external dependency which needs to be managed in unison with all of them. So you have a single point of failure. You have something that is gonna need to be managed not by one service but three services. So as you're doing management tasks like schema updates or if you're doing any performance related issues, they're all gonna be shared by all of your services. Also, while you may be able to have all of your data in one spot, nothing says that that data is gonna remain consistent across multiple versions of your service. It's very common in this scenario for the user service to make a schema change, but since the campaign service is a different module, it may not know about that schema change and all of a sudden its queries start failing. So there's a lot of hidden problems there and to make matters even worse, you still can't do distributed transactions because the different services can't actually share that connection. Each different process is gonna have a different connection to the database and there's no way for those processes to share that information. So what this actually shows us is we've been lying to ourselves this whole time, right? We've said we followed the 12 factor methodology. We said that our services don't have state. It's all pushed out to the database. That was a lie. That was a horrible lie because we had this implicit state that we don't really think about and that's the connection. Our connection to the database actually carries a good deal of state with it. In the example that I just gave you, that is carrying information about your transaction. That transaction only lives in that connection and we actually rely on that for certain properties of asset transactions, right? If I make an insert in that transaction, depending on my isolation level, nobody else outside of that transaction is gonna see it until I commit it. And also we're gonna have making sure that only one person can update rows. We're going to make sure that either the entire thing happens or nothing happens. All the properties of asset, they exist because we have this implicit state. There's also because of that, another implicit state and that's the TCP connection to the client. So while yes, you may horizontally scale your services, your load balancer probably has a session affinity in it because your clients are going to need to hit the same service or they're not gonna be able to do any sort of complex interaction. Well, so what is the solution? Well, enter the test. So the test wasn't built to solve this problem, but it turns out it does and it does it really well. So for those of you who are not familiar with what the test is, this is the architecture of the test. It is a fairly, it is a distributed database solution. So people will call it a new SQL database. People will call it a sharding system. People will call it many things. But what it does is it takes the traditional database and it splits it up into a couple of different parts that we can then have behave in interesting ways. So every Vittest deployment has a few components that it needs. At the very end of a Vittest deployment, you're gonna have a set of shards. You can have one shard, you can have many shards. A shard is just a portion of your database. The shard is gonna be made up of tablets and each tablet is going to have a MySQL process that actually stores your data. At the end of the day, all data in Vittest is stored on MySQL. In front of that MySQL process, there is a tender process, which we call VTTablet. That is the process that actually connects to MySQL and actually handles the running of queries. Again, we can have as many shards as we like. At any point in time, one of those tablets and one of those MySQL processes is going to be the leader of a shard and then there can be any number of replicas who are receiving updates via binary logs. The test actually manages that relationship there. It knows how to switch between which tablet is the leader and which tablets are the replicas and make sure that everything stays in sync. On top of that, there is a number of stateless gateways. We call these VT gates. You can have as many or a few of them as they like and this is where the magic in this demonstration is gonna happen. VT gate exposes MySQL dialect. So you can connect to it through port 3306 and you can speak the stock MySQL protocol. Most drivers that you'll find for most popular programming languages work directly with this as well as the MySQL command line tools. It behaves generally like you would expect a traditional MySQL database to behave. It takes DDL statements. It takes DML statements and it modifies your database. There are some other parts of a Vitesse cluster that aren't really important for this demonstration so we will just ignore those for now. While I'm still on this page, it's important to note that this is a distributed database, right? These components are all running on different machines that they could be located in different continents and different data centers. And so to communicate between them, we use GRPC. So the VT gates actually talk to the VT tablets over GRPC and the VT gates talk to the topology servers and to the control plane all using this GRPC service layer. Well, it turns out that the VT gate not only talks down to the VT tablets with GRPC but it also exposes its own GRPC endpoint. So the GRPC endpoint that it exposes has a number of different functions. They are all defined in the protocol buffers in the Vitesse code base but the two really important ones are the execute request and execute response. VT gate has a RPC method called execute which is really what we're gonna be abusing to do all of this. And it looks like you would expect this request to look. There is a bound query which is a query with optionally bound parameters. There is a caller ID which is a, it's not the authentication method but it's actually a second level of identification that you can use to sort of further refine who is actually calling a specific query. And then there's that session object. Well, it turns out that because of GRPC what the Vitesse authors did is they took all of the information that is normally implicitly shared in the database connection and they turned it into a session. And so the session object is exchanged like a cookie. And when the Vitesse authors wrote this down they probably didn't mean actually like a cookie but when I read it that's exactly how you can use it. So we have this message, this part of the RPC transaction that actually maintains all of the state. And what originally what this allows you to do is this makes the VT gate actually stateless. If you are using the GRPC endpoint and if you are maintaining the session your VT gates contain absolutely no state. You can actually multiplex between them and you won't notice any difference. So if today you are using the Vitesse drivers that are written in Golang or the JDBC drivers that use the GRPC endpoint either one of those you can use this GRPC endpoint from your programming language and your VT gates will become completely stateless. Well, when you do that what actually happens is this session is stored on the caller and then it's reused to the application just looks like a single database connection. It's just that all of the state has been fully pushed out into the client but there's nothing that says it has to be used that way. So while that is the way the GRPC and Golang drivers work we're, this is a normal GRPC interface we can do anything we'd like with it. So what if we were to just pull that even a little farther out and move it outside of the service and push it down to the client. And so that's what I'm gonna show. I have a theoretical microservice architecture it looks like this, same thing except instead of having a database per service we just have a single Vitesse database. I know what you're saying I just said that this was a bad idea. It turns out that it's not just this GRPC magic that allows Vitesse to operate like this. There's also a number of other features about Vitesse that make this a really good solution. The ones that I wanna just touch on right now is that this allows you to scale because Vitesse has a built in sharding and scaling solution. So you get scale without complexity. It also has built in management features. So we can do things like online schema changes we can do things like transaction killers and query watchers which help eliminate bad actors from bringing down your database. All right, so what does this look like? I'm gonna walk you through an example here using JavaScript that is going to use the GRPC endpoint and it's gonna display some of these properties. So I'm gonna switch to my text editor. And what I've done here is I have written a pretty quick TypeScript library here just to show how you could pull the GRPC endpoint into your programming language and you could use it to run queries like you would on any database but then also how you can use it to explicitly pass state. So walking you through this code here what we see is I have a client class that's got two very important functions. One is just a connection class which gives you a standard database connection but then another one which says I would like you to make a connection but I'm gonna give you this session information. The way I have them wired up is if you just ask for a stock connection then- Then excuse. Did you intend to show an editor? There's a comment that- Yep, absolutely. So yeah, so this is gonna give you a connection that already has the session preloaded. The rest of this is fairly mundane just wiring to wire up the ability to run queries and to wire up the ability to parse queries into result sets. So again, this code will be made available online. It is not necessarily boilerplate but it is a fairly straightforward wiring code to make all this work. It all starts out with a connection to our service. So here is the lines of code that actually create a connection to our service and this just establishes the gRPC connection to our service. At that point sending queries is a matter of creating the correct objects and passing them through. Right, so what does this look like in practice? So in practice, we can have a number of services which look like they're using a standard database. So in this case, I'm running a query because I have a single unified database, I can actually- Can I interrupt? Yes. Everyone is still seeing only the slides and not anything else. I'm sorry about that. Let's try it again. Yeah, that's better. Awesome, all right. Well, this was my lovely, lovely text editor. The connection code is located here. Again, it's split into a standard connection and then a connection with session and again, stock gRPC code. All the code was generated with the gRPC code generator and then we've just wired it up here. Again, code will be online. You will be able to see it. Let me go back to my server. Great thing here is this is a standard MySQL database. So this is a stock SQL and I'm even doing a join here to pull in some information across services. Great thing here is I can do it this way where I'm actually joining in other tables or if I wanna keep strong separation between these services, I can actually, I can do that now because I have explicit state management. So what I'm going to do is in each of my services, whenever our request is made, I'm going to check the headers to see if somebody passed in a test session. If they did, I'm gonna continue on with that session. If they didn't, I'm gonna go ahead and create a new session. And then the other thing that I'm going to do is when I am done, I'm actually going to pass my session out to the next caller. So when a request comes in, I'm actually going to check that it's got a, whether or not it has a session. If it doesn't, I'm going to create a new one. And then when I'm done with it, I'm gonna pass the session back out. All right. Well, what does this look like in practice? I have a sample JavaScript app here that I'm gonna run from the command line. So you can do this one of two ways. You could either do it with complete user control. This could be pushed all the way out to your user's browser and that's kind of how I have it set up. Or you can do it in a microservice. That microservice can just pass the transaction information to other services as it does coordination locally. So for the effect of this demo, I've created a transaction microservice, which will do my begins and commits. So I'm first going to ask for a transaction to begin and then I'm going to insert some data and then I'm going to commit that transaction. And again, this is gonna happen in two separate microservices. So I will just go ahead and copy this script and you should all be seeing my terminal now. Deepv, are you seeing my terminal now? Yes. Beautiful. All right. So I'm gonna paste this script. It's gonna do some stuff, but before that I'm gonna go ahead to my SQL prompt. This is standard my SQL. This is not anything special to the test. Although you can see that when I connected, I connected to a test server. So I can say show tables, hopefully didn't drop my session. Nope. And I can select star from campaign and I don't have anything in there. All right. So what I'm gonna do is I'm actually gonna paste this and all that text that just scrolled past your screens is me actually running the transaction. So I have created a transaction, I have inserted some data and now I'm actually waiting at the commit stage. And what's really cool here is if I do that same select, it's empty because even though I have inserted the data, I haven't committed it yet. So it's not crossing the boundaries of that connection. If I go ahead and commit the data, all right, my commit has happened. I've gotten back a 200 okay. Now, my data has made it in. My transaction has been committed and we can go along. And this would work for, again, I pulled this all the way out to the user, but this would work inside the service as well. So you can have any number of services we can pass around our sessions. State has now become explicit. By passing this all the way to the user, I don't even have to worry about session affinity to my services. I can upgrade my services with out dropping transactions without dropping any user requests. So I have pushed even more of my maintenance burden off into the tests. And then again, the code to use this looks exactly like database code. In fact, it's compatible with a lot of your ORMs and your other tooling that you use for your database today with the extra features that you can pull in things like this GRBC endpoint to be able to do even more things that you can't do with other database systems. Okay, back to slides. I'm gonna stop the stream share and then start again because that seems to give me the best results. Cool. So that is what a Vitesse microservice architecture looks like. But I hear you say, my application is a monolith. We're only moving to microservices. So this is actually really good fit. This is a great fit for Vitesse because Vitesse looks like a traditional database. So if you are running on MySQL today, you can actually deploy Vitesse in front of it and have all the access to your database. And then as you move to microservices, you can implement things like the strangler pattern to actually pull out transactions and pull out complex logic from your monolith into these microservices. So you don't have to worry about doing an all or nothing or doing a database migration with Vitesse. You can actually move your monolith into microservices easier than if you were to adopt a different style database. But if you use the same database, you won't have independent services. Like I had said before, Vitesse actually takes all of the problems that you would have by using the same database and it removes all of them. It has built-in starting to allow you to scale. It has built-in management like online schema change to allow you to do maintenance actions without impacting other services. And then it's got protections built in like query timeouts and query throttling that will allow you to use a single database service but make sure that all of the independent services can't negatively affect each other. And it also, aside from all that, by having the test, you also get additional visibility into your database. So how I said that I had that caller ID, well, now I can actually see which service or which process is running those queries that are slowing down the database or that are causing my response time to balloon. It supports tracing. So your tracing can go from your microservices all the way down through your database and back up. And it actually will give you a better performing solution than if you did move to that database per service model. But you could do the same thing with CQRS or something like the SAGA pattern. This is entirely true. And actually what you're seeing here is the same kind of functionality you would get with CQRS or SAGA, you're getting for free with Vitesse. So you can have a two phase commit, you can have a multi-shard best effort commit, you can have rollbacks, you can have asset transactions, but you don't actually have to take on the complexity of building out something like CQRS or SAGA yourself, you're getting it for free because you're using a database that supports all these things natively. So that's a little bit about running microservices with Vitesse. Again, this is not, this is something that we hear a lot of. It is not necessarily something that a lot of people are doing today, but this is functionality that has been built into Vitesse and has been used for a long time. Like I said, the Golang and JDBC drivers both use this same interface and they use these same mechanisms. It's just we're taking it a step farther here. The code for this will be posted online. There's obviously lots we could do with it. This was a simple demo to sort of just show a little bit of the techniques involved. So with that, I would love to open it up for questions. Thank you very much Daniel for a wonderful presentation. Our first question. This is my first encounter with Vitesse. I'm still a bit unclear what current problem with my SQL Vitesse is trying to solve. If I have a set of microservices talking to my SQL endpoint, are there any concerns there if the SQL client info is stored in the microservice? Are there any problems with data integrity in this case? Yes, so there are. And that's kind of the point of this slide. If you are serving, if you're having a bunch of microservices that are connecting to an external just stock MySQL database, you can't do this, right? You can't actually have transactions that would cross service boundaries. So if you're doing one of the stock examples for a microservice has always been the online store, right? Where a user wants to buy something and so you may have a user service and an inventory service and then you may have something like a credit service that's determining if this transaction can go through. If you had a single database, those three would be modules and that whole interaction would happen in a transaction. So either the user's order is going to go through or going to check that they have credit and we're gonna check that they have inventory and then we're gonna return back that, yes, the order completed and the user's order has happened or something occurred, either the credit was insufficient or we didn't have inventory. So we're actually gonna roll back that transaction and that order isn't going to happen. You can't do that as soon as you moved microservices. Even if you have the same database, you can't do that transaction across connections. As soon as you switch connections, the transaction is gonna be invisible to the other connections. To get around that, that's why people would say, well, you use CQRS or you use something like Saga with an external coordinator to make sure that you can have that transaction happen across those boundaries. What I'm saying is with Vitesse, you actually, you can do that. You can have microservices where your transaction can cross microservice boundaries and you'll get the same kind of asset transaction that you would expect off of a single connection across your microservice mesh that you're using. Awesome. Would you be able to elaborate a bit more on the comparison between the explicit session with Vitesse and the traditional implicit handling? Yes, so the explicit session with Vitesse is a bit of a complex object. What it actually does is, when Vitesse services your query, the query will come in through the VT gate. VT gate has a full SQL parser in it and it knows how to route your queries to either a single or multiple shards. When your client sends that, if you're using the MySQL port, the connection is maintained inside a VT gate that any packets coming across any packets for this connection ID are going to go back to this client. But then as soon as it goes down to the VT tablets, it actually switches to GRPC internally, which multiplexes all client connections across a single GRPC tunnel between the VT gate and the VT tablet. To keep everything in line, the VT tablet actually establishes a connection ID for every single client connection that's inbound, VT tablet establishes a connection ID and it uses that to pass information down to the back in MySQL and then return that back to the VT gate. Because that's all multiplexed, it needs to pass along some information to the VT gate so the VT gate knows which MySQL connection to return the information to. What the GRPC endpoint does is it takes that same bit of information that the VT tablet sends to the VT gate and allows you to just continue sending that out to the client so that when the VT gate gets a query over the GRPC interface, instead of associating that stream with a particular client, it actually just looks at the session and says, okay, I already have a session information so I don't really need to know which MySQL socket to send this out on, I'm just gonna pass this down to my VT tablet and when it comes back, I'm gonna send it back up to the client. I know that's not the world's best explanation. It's a lot better if you have a whiteboard or some code in front of you so you can see how this is all being wired together but that is how it actually works. All right. So plenty of time for questions ladies and gentlemen so please feel free to drop in your questions into the Q&A box and we'll get to as many as we can. Can you tell us how this compares to the database Cockroach DB? Yeah, I mean, so the tests and Cockroach are similar in some ways that they are both distributed in nature so they give you things like high availability and scale. The test is a little bit different. We always say that the test is the world's only cloud-native database because the test is focused more on a transactionality and focused more on being able to get those aspects of a cloud-native system, horizontal scalability, ease of management, treating your resources like they are row crops and not gardens whereas Cockroach is a little bit more of a holistic system. So you'll see that in setting it up, Cockroach is generally a little bit easier to get online but something like the test is generally going to perform a little bit better when you have lots of transactional data and you have a very dynamic runtime environment. Works really well on things like Kubernetes because it's kind of built for the idea that at any point in time, any single part of a test can go away and your queries are still going to be serviced and that's kind of what has led to this kind of functionality because it is built with failure in mind, right? It's built to know that at any point in time, a single component could go down. We have really tried hard to push state out and to reduce single points of failure so that almost any part of your database cluster can go down and your transactions are still going to be serviced or queries are still going to be serviced. So when you think about it, it's built for sort of the five nines uptime of very fast transactions and that's, you know, that lends itself to be a little bit more complex but it also gives you a little bit more flexibility. Okay, now there's another question here. I believe this is in relation to the one you answered before the last one. Is there a performance penalty like a database lock using transactions? No, well, there is locks get established like they would in a standard MySQL database. So if I did an insert on a row and then I tried to delete all of the data in that table, the delete wouldn't happen until the transaction lock cleared either by committing the transaction or allowing the transaction time out to occur but it is not actually imposed by the test. It's imposed at the MySQL layer. So it's the standard locking that you would get in an IODB database. There's many different kinds of locking but there's no additional locking that happens because of the test. There's a bit of a performance penalty in that GRPC is less performant than the MySQL connection. So if you were going, even just the test against the test, if you were benchmarking the the test MySQL server endpoint versus the test GRPC endpoint, the test MySQL server endpoint is going to have higher throughput than the GRPC endpoint because that GRPC interaction does take a little bit more CPU than the stock MySQL server. How does the test manage schema updates when multiple microservices are using different versions of this schema? Yeah, so there's a couple of different ways you can do this. At the end of the day, schema updates are very much up to the user. So if you want to completely decouple your schema of your microservices, this gives you a path to do it. You can have completely decoupled schemas and interactions between those can happen just at the microservice layer. So in my example, I actually used a join to resolve a profile ID to a profile name. If I wanted to keep my schema completely independent, instead of doing that join, when I got the data back for the profile ID, I would just make a call off to the profile service and I would get the profile for that ID via the service API. And then I would merge those in the microservice and then return that to the user fully merged by me. However, the test gives you some additional features that mean you don't have to do that. And you can start to really use the power of joins and use all of the SQL things that you would like because we can do some things to decouple your services a little bit better. We can't make up for a user creating a schema change that isn't updated in code and so your code queries break but what we can do is we can make those schema changes completely transparent. One of the problems that we see with microservices is even if you have robust testing to make sure that schema changes don't break independent services, what'll happen is as every single independent service releases, you will start a schema change. Schema changes are generally lock the world kind of operations. So if I have a very large table on the order of one to two terabytes and I have to add a column or drop a column, that can take hours or days where I cannot update that table. So even if you have really good testing and you know that nobody is going to change a schema to break your other services, the fact that you now have 10 different services trying to make changes to the schema means that you're going to incur outages. What the test gives you is things like online schema change. So we have been working on and releasing online schema change functionality built into the test. Historically we've used external tools to do this but now it is built into the test. So as you make schema changes, they happen online. You can roll forwards and backwards between schema changes I believe. DeepD can correct me if that is not built in yet. I believe you can move forwards and backwards in schema changes. So you can actually make your changes with your services and then be completely transparent to your downstream services. So that frees you up to version and lifecycle all of your services independently. You do have to make sure that your schema is compatible but once you've done that, you now can get past that burden of having multiple maintenance windows and sort of multiplying your maintenance windows for every microservice you bring online. Okay. Can you elaborate a bit more about what happened? Can you elaborate a bit more about the online schema changes? My main doubt is what happens when I try to write the column. Currently the only solution I see with native MySQL is to duplicate it. So the online schema change, historically we've done online schema change with external tools like PTOST or ghost. The same functionality that ghost brought to the cable, the GitHub online schema change tool. I don't know what the T is for. We is now built into the test and what it does is it utilizes Vreplication which is a Vtest technology we've been working on for about two years now which actually allows you to modify your tables and columns live using Vreplication to ensure that the modified columns are in sync with the existing columns or the existing tables and then do a graceful transfer to the updated schema when you're ready. It's in Vitesse. If you have a recent version of Vitesse, I believe you're gonna have to have version 80. It actually is just an annotation on the DDL statement which allows you to trigger an online schema change. And I believe if you join us on the Vitesse Slack channel which is on the screen now, vitesse.io forward slash slack. We can explain to you in detail how that whole process works and how to get started. Again, we've been doing it with outside tools but we recently as a version 80 have pulled this natively into the test. Excellent. Still have plenty of time for questions folks. So please feel free to drop any other questions into the Q&A box. We have about 13 minutes left in the webinar. So please feel free to ask away. Just to add a little bit to what Dan said about the online schema changes. That work is still experimental and we expect to merge it in the next few days and it will be available in the A.doctor release that's coming up in a few weeks. Anyone at all? Does Vitesse just support MySQL or other backends available? It does not support other backends. So it is very MySQL centric. The query parser is the MySQL dialect of the query parser and it is stored in a MySQL database. That being said, depending on your exact needs, we actually do have multiple engines for MySQL that are supported. So we know that there's obviously people out there using Inodb, the default engine, but we also have quite a few users who are using MyRocks. So if you wanted that log structured merge tree style storage engine, MyRocks would allow you to get that. So we don't support other storage systems, but we do support a number of database backends. The plugable storage engine that MySQL supports, a lot of those will still work with Vitesse. We also support many MySQL variants, including MariaDB, Parcona and Oracle's MySQL Enterprise version. And support for Postgres is something that has come up many times and that is in the long-term roadmap. We are looking for contributors who might want to work with us on that. Is the session object in header a big overhead? No, not really. I have Base64 encoded the header. Let me go ahead and stop sharing my screen and then try to share my screen again. I can show you exactly what it looks like Base64 encoded. So again, here was that session that I had ran. At its biggest, here is what the session looks like. So it's not terribly large. It can, if you have a highly, this actually grows with the number of shards. So if you were doing a very complex multi-shard transaction, it can get a little bit bigger than this. But again, this is the serialization of a protobuf object. It is very compact. So I'll have about eight minutes left for questions. So please feel free to ask away. We have anyone else at all? Anyone at all? Are there any projects using Fittest for Saga? It seems a little bit, it seems a little technology to lock in. What are your ideas about this? Well, great thing about the test. It is used by a large number of companies. But you wouldn't need to use it with Saga. You can actually get the same functionality in native Vittest. So most people who adopt it aren't gonna be implementing CQRS or another pattern on top of it. They're just going to use Vittest. In terms of lock-in, Vittest is pretty interesting because it is in fact a standard MySQL database. So you can at any point in time stop using Vittest and go back using MySQL. There does however come a point where realistically you're locked in. So there are people running Vittest who are doing 35 million queries per second across thousands of shards that span tens of thousands of database servers. At that point, you really need, like you can't take your hundreds of terabytes of data and put that into pretty much any other database system and get the same level of performance. So functionally there is no lock-in. You can go back to using stock MySQL at any point in time. But there's gonna be some things that once you start using Vittest, getting into other systems, there's just not too many alternatives out there right now. So really if you're using this simply for the management and some of the extra features and your database, your data could be serviced by a different MySQL server, then there's no lock-in. You can actually just turn Vittest off and you'll have your MySQL server in the background. You connect directly to it. Your queries will stay the same. Your code will generally stay the same. You would just have to remove the Vittest specific functionality like the GRPC connection, the sessions, all those. Is there an interface exposed to implement other backends? Say you were to implement these 20 methods and some guide and surround it, then it should work around other backends on MySQL too. So yes, there is. There are interfaces where if you were to implement that interface for a backend, it would work with that backend. So you would know better than me, but I think if you were to implement the query server, you could pretty much put whatever you wanted behind that query server. And it would, yeah, but... Yeah, but it would be a significant, rewriting a significant portion of the code. So there is the interaction with the backend database for management functions, which is one part of it, but there's also the parsing. And the parser right now is a MySQL compatible parser. So we would need to build a way of plugging in a different parser depending on the backend flavor. So the bottom line is that that work of extracting and formalizing the interfaces required to plug in a different database is still to be done. And the parser planner construct, which actually does most of the work, because we have a MySQL database as the backend, the planner in the test is gonna look a little bit different than the planner in some other databases. We don't translate down to like a block fetch or to a key fetch the way some other distributed databases do where queries are parsed and then they're planned down to a key fetch and then they're sent to the backend just for a key fetch. We actually, because we have a full database in the background, we will actually parse the query and then the result of the planning of the query is actually another query. And that's part of the reason why we can be as fast as we are and as scalable as we are because we can push almost all of the work down to the backing databases. But then it also means that as Deepvi said, not only do you have to implement the query server which actually returns the data, but the parser and planner is very much tuned for the MySQL dialect of SQL. I'm for about one more question, I believe. So if anyone has a last minute question, they'd like to shoot Daniel's way, please. Feel free to drop it in the Q&A box. Would you be able to elaborate a bit more on planner? On the planner? Yes, I am definitely not the expert in the planner. If you want the nitty gritty details, you wanna go to the test.io forward slash slack and join our Slack channel and we can hook you up with the people who spend most of their time working on the planner. But what we do is we actually do a full parse of the SQL query. So we have a custom written SQL parser which creates an AST. And then that AST instead of, again, instead of going down to a block fetch, the planner translates it. The planner uses the V schema along with the shard information that is live updated from the box server, which is one of those components that we sort of breezed over in the architecture diagram to actually create a routing and execution plan. The routing and execution plan is based off of the currently serving live shards. And the actual result of that, like I said, is a SQL query. So much like you have query builders and a lot of ORMs, we have almost the same thing inside of a test. We can take that AST, we can rewrite it and then serialize it back to a query and pass it down to my SQL. The exact steps of that are, I don't know, it's as complex as any of your planners would be, which again, I'm not the expert in the actual details for that hit up the Slack channel and we can get you online with somebody who does know more than me. All right, well, thank you very much, Daniel, for all of your time today and thank you to everybody that took time out of their day for attending today's webinar. As I said before, today's presentation will be available later on on the CNCF webinar page at CNCF.io slash webinars along with the slides that were used today. Thank you everyone for joining us today. Please take care, stay safe, have a wonderful weekend and we'll see you all next time.