scale.bythebay.io: Ryan Knight, Return of the Transaction King
Recording: scale.bythebay.io: Ryan Knight, Return of the Transaction King
you yeah cool all right thank you everyone for coming out I'm Ryan Knight I do I run a company called grand cloud I do consulting I spend a lot of time on like the application development side doing like Scala Java development I just have spent some time in data stacks during Cassandra because she had her sales engineer actually before that even worked at Oracle spent some time to Oracle with the Oracle database in Oracle RAC way back when so why don't you talk about today's return of the transaction King does anyone have a clicker I forgot my clicker but well I just had my son all right so free Fisher data right in the very beginning of databases we had relational databases with the asset transactions right atomic consistent isolated durable and this is how databases work for 20 plus years and right asset transactions were really nice and made it really simple to write your applications you know if we went back to the lab sack days you know it's actually pretty simple to write a lamp application with it because you had the trans actually consistency made a lot of things really nice and simple what happened is the internet right traditional asset transactions just didn't scale at the Internet I mean people try to all sorts of workarounds with like leaders with read replicas distribute it locks and you know two-phase commit succour distributed systems just fundamentally breaks right you and leader with the read replicas you were left with a single point of failure things fall apart when you your leader goes down and the Rieger applicants you're always having problems with the rege replicas you know inconsistency in the Weig replicas so traditional asset transactions really just didn't work in the Internet era they really fell apart and this led to the cap theorem probably everyone here has heard of the cap theorem this trade-off between consistency availability and partition tolerance and what this really means is that for a long time people talked about you know which we're in the captain and dry line you know you know to get true consistency I had to trade off availability or vice versa so what companies were really left with was this trade-off between driver wanting global scale are going to want strong consistency and which one do I choose to build my like applications on and a lot of companies chose global scale and this led to the rise of eventual consistency so eventually consists is really become the predominant model today in most applications in application and eventually consistency is done at the sacrifice of strong consistency so there's been this trade-off for a long time so if we look at eventual consistency eventually consistency is really just a necessary evil right eventually consistency is not something any of us really want to deal with and so you know we've invented all sorts of workarounds and deal with this eventual consistency you know like last right wins we have you know invent sourcing models you know it's all these different models that basically rewrite the data now and we'll figure out later on how it sorted out later I know that's what mentor students a lot about is you know I write my series of events and I do roll up in snapshots and so I figure out how that due date you know is what the you know the value you like your funding your bank transactions you know I figure out whether the value of my bank account is up after the fact you know I thought you know add all those transactions together the bank account transactions together so this is really the eventual consistency model and you know it really works really well alright events sourcing works really well it's a very predominant model in the industry today and it's it's used across the internet very successfully right so DNS uses it quite extensively IOT like any time series use case monitoring web metrics followers right if I'm taking a you know account of you know metrics of how many people hit my web page that can be eventually consistent right I can you know if I add you know you know what I do in the additive of all the metrics of you know web page hits that can be you know associative and I can add that in different orders and you always get to the same answer there's also been a lot of use cases where you know people figure out how to modify the business to allow for inconsistency it's very common for you know online store to oversell right they figure that they have about a thousand items and they'll sell a thousand items and then they'll you know when it you know they might sell a thousand and two and only have a thousand items and just say sorry we don't have your items stock reorder or write the bank has an overdraft charge right so there's a lot of ways of modeling your business to fit in with this eventually consistency and event sourcing kind of models that work really well but where it falls apart and I was talking to James worried about this the thing is is we live in a staple and finite world so there's oftentimes these cases because we're in a very stable finite world we don't have the ability to just say well maybe we have 100 maybe have 100 - it doesn't matter there's a lot of use cases where we have the finite number of things we need to sell and so what that leads to is there's places where event sourcing breaks down right there's a lot of use cases where the order of events matters where I have to have an exact you know linear order or serializable you know order of events and when I have in this exact order of events matters what happens is if I have two hosts we're like two servers we're writing my events in parallel to my to my database or might you know in each kind of data store these events can get out of order when I can't guarantee that these events that are being you know written in parallel are being placed in the exact same order I'm going to end up with a divergent history of events and so then I end up with a problem of how do i reconcile this divergent history of events and I also end up with this problem of the possibility of losing some of my history of events so there is a slight problem that you know if I'm writing from multiple servers the same events that there's cases where I can actually lose some of my history right so in these fuse cases where there's really the ordering really matters this is the places where event sourcing starts to break down a common example that I can talk about is a like a reward system if I have to process a batch of rewards as that rewards comes in you imagine the bachelor rewards then I'm processing from work say like a single user does like it a crew you know crew points accrues points and then redeems them well what if that's the history I saw the first time through it so I'm redeeming those points well what if the actual history was a crew a crew void and then redeemed and I missed that void right and because I processing these as a batch of transactions I might not receive that void until after the redeem and so there's a very specific use cases where that ordering of events for something like that you know redeeming points matters you know another problem is like dealing with a void you know what if the order those transaction comes in as a you know a void gonna redeem so they're coming in out of order not God deal with the void but I don't have the redeem so these kinds of situations really matter you know another example is you know like an auction you know if I'm auctioning a particular item off I want to know the exact order those the bids on that item were received and I need to know the exact ordering of those events so there's these times where events were seen really starts to break down so let's so a lot of people talk about strong consistency there's a lot of different definitions of strong consistency today when I talk about strong consistency this is actually from the Google Docs about one of their databases they talk about what they how they see strong consistency and what they define as strong consistency is I have surveys writing value acts to note a right well when I read from node B it's gonna block for the reading of X right so it cannot read it X while it's being written to right and at the same time note C is also going to block for reading of X so what's happening is the readers are blocked until the replication is complete so I talked about strong consistency there's a lot of different definitions what I'm talking about I'm talking about the ability to you know have it rich in to the note a and then know B and C are not going to be able to read that value back out until it's completed so this is a much stronger sense of consistency than other definitions right so in the industry we see a lot of different views of strong consistency and how people dis find consistency oftentimes people are called strong consistency if I write and then I read from the local forum that they call that strong consistency so there's differing opinions of house consistencies to find what I'm really talking about when I talk about storing consistency is the ability to do a read before right so I want to read a value out of the database update and then write it back down right so things like comparing swaps also getting like snapshot isolation so this is a much higher level than just a strong consistency of a write and then reading to get the same value back out so this is a much stronger guarantee that I'm going to actually see an updated value that I read back out of the database so so when we talk about strong consistency one of the things we're talking about dealing with is the ability to avoid what's called right skew so right skew is right I have two concurrent transactions each to determine what they are writing based on reading a data set which overlaps with it the other what the other one is writing so you basically have two people trying to read the same so data and update it but then they're overriding each other and so they write the wrong values so you get the skew and your write values so this is one example of where you can get like a skew of data basically your day gets out of alignment so can we really ignore consistency you know can we just say you know all use cases are eventually consistent and we'll sort it all out later I think when we do that we're really pushing the consistencies problem into the application where the problems are much harder to solve so by by saying that you know everything is going to be eventually consistent we're really saying that we're really not avoiding the problem we're just saying that we're gonna be eventually consistent at the data tier and what we really need to think about is well are we really modeling things eventually consistence throughout the entire layer or are we really just pushing consistency up into the applications you are dealing with there and when we do that and we start trying to model the consistency in the application tier we get into a lot of complexity so there's a lot of ways to deal with this complexity of the application tier but it puts a lot of burden on the application to offers to have to deal with this so some of the common patterns of consistency in the application tier that I've seen is event sourcing with command serialization right so when I write the command for my event I do all the you know like I serialize on the particular command so like I might have a user ID and all the the commands for that user ID I'll go through a single like actor so you know some kind of a serialization point so I can guarantee that when I'm writing all the events for that particular user all the events are being written from a single server or you can do a serialization point like a Kafka consumer so I can say you know this Kafka consumer is dealing with this specific topic and dividing my data out such that I can guarantee that right the ordering of events that I'm processing are going to be an exact linear order well this works ok until things starts to fail so what happens if I have a single you know command writer for a single user and I can you write it I can scale that across like an after cluster and have you know okay actors dealing with those commands and guaranteeing that I'm getting those orders right but then if a actor or noted my cluster goes down I didn't have to deal with right time zones so how long do i wait for that database right to time out before I know that I'm going to have to failover to another node so and then at that point in time I'm starting to have to deal with a lot of failure cases of what has happens when things are going to break so this gets even worse with the rise of cloud native Micra services so with the Micra service architecture you know I should say you know monolithic it's pretty easy to deal with event sourcing and guaranteeing the ordering of events when I get into a cloud native like microservices type of architectures things really increase in complexity so one of the things is the partitioning of the application domain and the related data so how do I figure out like which services are dealing with which data who's dealing with the events who's writing these events and I'm having to deal with a lot of increased coordination between these data's you know so if I have different services who are having to coordinate on a particular event or having to you know one reads and one writes how do I could do the coordination between these so all these kinds of things as things scale up with microservices you get a stay loving an increasing exponential growth in complexity which makes things a lot harder to deal with so I really think that when you look at a you know a cloud native architecture and you add you know no sequel databases and uses it's completely take out an asset transaction you end up with almost this Rube Goldberg machine of data right so you're trying to figure out between how these hundreds of servers how do I coordinate all the data between all these services so I think this leads to a lot of complexity when you're not having this very strong sense of consistency between my application in my applications here so let's just talk a bit about what we're going to say asset transactions and why why do they ask the transaction to be important so atomic is it's guaranteeing that I have a my operation is actually an atomic operation like so if I do a multiple like read writes or writes reads those all happen it like in a very atomic level like it's an atomic lock that I'm guaranteeing that that's a single unit of work that's being done consistency not only a strong consistency but also that it's correct so am i affecting other pieces of data that I shouldn't be isolated is that transaction being isolated from the other effects are being happening in the database is it durable is it you know is that transaction actually committed before someone else tries to read it so it's a much stronger sense of dealing with my data than just a strong consistency so that it's really taking this to a much stronger level of guaranteeing what's happening to my data so what I really think is that we're nice to talk about return of the transaction King what I really think is I think we're seeing a return in this industry of asset transactions combined with event sourcing is where this industry is headed so I still think that sourcing model is a great model I think there's you know probably 89% of the use cases in businesses today really work well for a good sourcing you know and I think a lot of you know any kind of you know no sequel database that does event sourcing this is a phenomenal database for those exact reasons so I think they're still really strong use case for event sourcing and I think you know and I think there's just this is more kind of I see this as you know figuring out which use case to use which database and where you know where these different models of architectures fit in so I think the problem that we've run into is in industries we were thinking trying to think of make everything fit into an event sourcing eventual consistency where it can't it just fundamentally can't where I think there's their use cases where we actually need asset transactions so when I talk about the rise of transactions there's a couple of databases out there that are really adding in this this strong consistency back into the core of the database so these are the databases that have both global scale and strong consistency the three primary ones that I know about today are fana google spanner and cockroach DB and these are really kind of next-generation databases I think are going to fundamentally change the way we can program our applications because we get a return of transactions one second how many people here have heard of these databases anyone heard of fauna couple people heard of fauna spanner anyone heard of spanner cool how about cockroach you guys have heard so you guys heard a lot of these cool does anyone use any of these databases currently no one yet okay so what is the value of transactions why would we want to add transactions back into our application layer I think by adding in transactions for these use cases where I need true strong consistency at the highest level where I truly need you know an asset transaction I think it really decreases the complexity in your application tier it reduces the cognitive overhead of complexity of trying to figure out you know how do I serialize these you know right how do I figure out you know how do I figure out you know who's reading who's writing the data at what time at what point if I can serialize that I'll bite you having a transaction it really makes the applications are easier you know I've seen people go as crazy as you know writing their own patches algorithm to deal with eventually consistence in your application to your that's a really hard thing to maintain a business layer an application tier for your business logic I think probably returning to transactions and using them in the right use case you really can increase your developer productivity and you also can focus more on your business value why oftentimes I'll see developers who are starting to focus on they spend so much time dealing with eventual consistency and you know events are seen in applications here and trying to work around all the problems that causes they're not really delivering business value they're more trying to build their own you know like paxos consensus algorithm you know or some kind of you know complex you know data management layer at the application tier and I don't think that's where it really fits in so I think this is a huge boost both for developer productivity and for businesses so there's always this interesting discussion around do we have to sacrifice availability and partition tolerance to get consistency there's a lot abated about this I'm not gonna wait into this fully I'll just the if you if you're really interested in there's papers you they need read Eric Brewer and the spanner paper where he introduced his spanner he talks about he says there's two important caveats to his you know Eric Brewers inventor of the cap theorem you know he says there's cognate caveats of my theorem this is first you only need four-foot something during an actual partition and even then there are many mitigations second the actual theory was only about 100 percent availability while the interesting discussion is about the trade-offs involved for a realistic high availability so what he's really saying is do we really have to sacrifice everything do we have to sacrifice consistency because of ATP there's another really interesting paper about this by I'm not quite sure I was tasting and Daniel Abadi he talked about the process with the cap theorem and yeah Yahoo's little note knowing no Seco system everybody talks about is under normal condition so we wanted really to that what we really should be thinking about is the trade-off between latency and consistency and he taught he goes into this and a lot in depth about why he thinks that the cap theorem is overrated and that we really should start thinking about under normal conditions we should be thinking about the consistency and how you know this trade-off between consistency latency you know so if you look at Google and that spanner paper Google actually talks about their modern chubbie cells that's their compute units they have over five nines of availability their availability at this point in time is so high that they're saying you know what we have so little outage that you know let's start look focusing more on consistency that's exactly what they built with spanner so just a really brief introduction of the spanner I think spanner is an absolutely fascinating database the way they've actually built spanner is Google has its own private network around the globe so they actually have laid and all of their data centers are interconnected by their own private network across the globe which guarantees very high bandwidth they also have in each data center GPS receivers with atomic clocks so they have this guarantee of of being able to know the exact time at every single data center around the world a moment this is something that's really unique to Google no one else has and by having this exact time they can provide serialize ability guarantees that no other database can provide and so that this is the way they built spanners built on top of this concept of these serializability guarantees and so you know it's interesting I talked to some friends that work for Google and we talked a lot about databases and today you know the trade-offs between different database approaches one interesting thing I found from Google is their core business is ads and their core business of AdWords has never moved off of a relational or off of a transactional database so they originally built on top of my sequel they started my sequel they were actually running off of my sequel for a very long time and they kept the AdWords on a transactional database until they could invent their own and they built span and actually AdWords has been running on a internal version of spanner for over five years so for them you know the AdWords platform is such a key part of their business where they're dealing with people's you know they talked about dealing with people's money and financial transactions what they say is when we're dealing with people's money and we're dealing with financial transactions we don't want eventual consistency we don't want the question of whether or not I've been able to sell that ad I don't want to have a question of you know am I going to be able to you know earn the revenue I need to and for this reason they've kept spanner on a write as strongly consistent asset transaction database for their entire history and what they've done is they basically taken spanner they're not making this a commercial product on the Google cloud what one other use case us banner is the Google cloud platform actually runs the whole control plane is backed by spanner by a strongly consistent you know asset transaction database one other interesting thing they do is they actually separate out compute and indeed it layers so you can actually they can actually take their data and just plug into another compute instance and so that allows them to have no scheduled downtime so if they need to upgrade a compute instance or a server for any kind of reason they can actually just plug your data into another compute instance and that allows them to do maintenance by just move your data between nodes cockroach GB it has hybrid logical clocks similar to a vector clock for ordering your transactions they deal with a lot of challenges with the clock skew they can weight up to 250 milliseconds on reads I'm still in my mind I have a lot of questions about whether or not they're really gonna be able to pull this off I mean they're basically trying to do their own version of spanner without the atomic clocks which is a really a challenging problem so the one database that I've been spending a lot of time on evaluating is fondant and I think fun is really interesting database because it doesn't it has the global transactions it has sorry the global scale plus the store inconsistency you have you know global transactions around the world without depending on atomic clocks so they have an entirely new approach to how they deal with transactions and databases this all comes out of the spelling error in my slides they're saying so the people who found if I know where it came from Twitter they they build a lot of similar systems internally to Twitter they dealt with massive scale at Twitter and you know in solving all the reliability and you know the fail whale problems a Twitter for a number of years and based on that experience in building massively distributed systems they took that experience there's also a very groundbreaking paper called the Callen paper there's written the talks about a new approach to writing databases and they took these two things and they build a new generation of database the other unique thing I think with fana is that funny is a it's a functional type safe right the query language is a functional query languages so it doesn't use a normal approach so what they've done is you know most databases like spanner they tried to you know be sequel compatible Faunus said well what's more important is let's build if we're going to build a modern database let's prevailed a modern language to use with our database it also has indexes so I can do multiple indexes you know any kind of indexes across my data I can do constraints I can do views all these kinds of things so how does the transaction resolution work what it really does is it resolves these transactions before committing into the database so what it has is it has this RAF replicated log of transactions this is the drys is the toll already two transactions and so when I write a transaction to the database what it does is it puts it into this like epoch badge and it does a global resolution of that that transaction a log so that this is that's a very high level skimming over it so they do a lot of things to avoid like you know across regional replication you know if that batch of functions only has a read then I can do optimistic locking all these kinds of things to optimize this entire process but the novelty is the fact that instead of trying to do a lock on my database right so an acid traditional ask the transaction is you know like begin lock you know you know do a slack - you know insert an update and then then unlock instead what they're doing is they they allow you to take a function I censor that function down to the database that function is a function right is the the unit of transaction and it takes all the functions for that via epoch and it resolves them together and then it applies those to the database so this is really a novel approach of how you build your database from the ground up I talked about most of this yeah there's a lot of other unique features to stefana has native security access control built into it so every query that you make actually has to have an access key and based on that access key I can determine the row level whether or not allowed to access that data this provides complete data isolation across data sets the other interesting thing is that key that I'm accessing the data with is that key or that token is also used for scheduling my the priorities of that query that I'm running and so what they do internally is they actually have more of like an operating system like design and what this relies review is a single cluster for different and competing workloads so that I can have in a single cluster I could have an analytics cluster along with my traditional all at CPE cluster and I can give different priorities to different queries and I can also assign different priorities to different users so I'm combining these these very tight security controls with the quality of service controls which - you know we use that database for a lot of different purposes without affecting other people another interesting thing is temporarily for encrypt all instances of its data right it does never override them but it just creates new records every time it writes the data representation and fauna so this is the other unique thing about fauna is you have your database your database has what they call classes and they create an instance of that class and that instance has array or scalar types but I can also do nested data so I can do within a single database I can have multiple databases and then with inside of a database I can have multiple classes so I can have nested objects you know and this allows me to have relationships in my data instances records are stored in the database as an instance right all objects as are instances of a specific class so the core the core row like concept in it and like a partition if on as a class so I created an instance of a class I saw that that class gets stored in a database and I did a ref back from that class and so that reference refers to that unique instance of that class so the transaction scope is a functional transactional scope so the entire function is or query block is the scope of my transaction this is a paradigm that it's going to feel very natural to functional programmers because the way you work with fauna is in a very functional kind of a manner so I think for you know anyone with the Scala background who's used to doing functional programming is going to find this a much more intuitive model to work with fauna and then it has indexes similar to a traditional database the unique thing is the the indexes you index on a particular term I say I want to give an index of this term and these are the values I want to return so you specify in your index what values did we return from that the reading of that index and that index is also what's used to enforce the uniqueness constraints on the database and then the the query optimizer does not make the index it doesn't choose for you which index is being used you have to specifically reference which index is being used all right I'm going to show a little bit of code so let's see here so this is I was working on a little sample that is kind of like a contract between two users so the idea is that right I have a that's you scroll up here so I have a creditor and debtor so I have I want to make a credit a contract or you know one person that's another person the amount of money and I want to know the state of that contract whether it's you know proposed have I proposed lending you money have I accepted redeemed or rejected that contract so to look us a little bit of the phonic coverage of how I write this so in with Scala and the the they have a new driver out that has a codex automatically see your license and deserialize is from case classes so this will allow me to automatically write that user class let me break this down for you a little bit so I talked about how the fundamental unit in font is a class so when I set up my schema the first thing I do is I create a class so here I'm saying your create class the name of that class is user and then I'm going to do a query to check to see if that user already exists and then I want to create an index on that user so I want to do an index by user name so this is the name of my index the source of the index so I'm saying the source comes from this particular class and then the terms of this index so this is what I'm going to actually index on these are the values I'm indexing on so I'm just going to index on the user name so when we talk about a functional scope when I actually run this query so here's where I run the query is I do this if so I'm doing a father if query I'm saying if this class does not exist then create it otherwise just get it so here I'm passing in a functional scope stud and then similarly we have a contract a lot of the same concept here right so let's scroll down so here I create a class called contract my contract is going to be between two parties right and then I'm going to create an index on that contract where I have a contact by ID and the terms like an index on our on that contract ID so now that I've create the class let's I'll show you a little bit about how we can actually use that so everything is done with this client is defined a backup to salute I basically have a finite client which is my connection into my database with that client I'm saying let's create a user so what I'm saying is and I'm creating a user in the class user so I'm saying what user and then I'm specifying the data for that user all right so the date of this instance is a user ID and a user name so that's going to create a user and then going to how it's it's a functional language so as an example say like I have a list of five users so this entire block is a single phonic query or function that gets submitted to the database and I've so many of this query to the database I'm basically passing to the database five users and I'm going to iterate over each of those five users I'm going to say for each of these users do this function and I'm going to do a lambda I'm going to map over those users and I'm going to create an instance of those what's unique about this is I'm not set but this is not five right separate queries they're being issued to the database this entire block of code is being issued to the database and that function is being run inside of the database the Magno of those users so in the similar way I can get the data back out so here's an example of using that index I index by user by the user table by user name so if I want to read a user out of the database for example if I want to find the user Hydro so what I'm saying here is I want to get out I want to get something out of the database and I want to match on the index so the index I want to use is the user by user name and the value on a match is Hydro so I'm basically getting the ref back out of that data so here I'm saying basically select by default what I'm getting back is just a reference to that object so I don't get back the actual data I just getting back a ref and so now that I have that ref so I basically have a pointer to that class now that I have that pointer I want to get the actual data out of there and so what I do is I'd say get a ref so that's actually pulling that ref out of the database and giving me the actual values out so the first step is just to select the ref and find it and then I take that ref I pull it back out but again this is all done inside the database so this isn't a two-step process you know back and forth the database this is all done in a single step so a little bit more of a complex example is say like I want to let see you just I want to go to I want to create a contract right the contract is between two users so to create the contract between two users I first need to look up those users so right if I get something from the if I if I get a you know request from the clients saying you know I want to you know imagine you know user Hydro and user you know Bob and create a contract between them so instead of having to go to the databases looking up user Bob then looking at me a user admin and then you know getting those values back and then you know creating a contract and sorting that back in the database I can do this all in one functional check chunk so this query does is right I'm creating a query inside that query I'm going to create a class of type contract and the value so like the value creditor is going to be based on a select the value debtor is going to be based on select so I'm basically inside that single functional block I'm looking up the creditor I'm looking up the debtor and I'm saying those values inside the contract those are returning the ref so then in terms of redeeming the contract again this is going back so this is really your where we get into this transactional type of approach to our database so here I'm saying I mean I like this so this is if we look at this this section of code right here what I'm saying is I want to look up a contract ID so this let me back up this is saying I want to redeem a contract so like the contract between two users I now want to redeem that contract says this value right as this contract already been redeemed can or can I redeem it so I wanted to have the strong sense of guarantee of whether or not this contract has already been redeemed all right so if I deal with money and I say well you know Bob owes me you know five dollars I wouldn't know for sure whether or not that he's already paid me or not so the way I can do this in fauna is a functional transaction as I can say go and look at the contract right so I'm matching on that index contact ID and getting back to contract reference and then I get the state of the contract so is that the say that contract is it just in a proposed State have I you know is it have we just started the contract or have I already redeemed it so I look at the state of the contract and I say right if equals state we deed so if I've argued game that contract that could have functional air out you know it's going to return an error I already redeemed otherwise I'm going to update the contract and I'm going to set the state to be redeemed so this gives me a functional scope for doing my transaction inside this functional scope I'm able to do it you know basically an asset transaction of reading the values out of my database verifying what they are and then deciding whether or not doing it something based on that value as a more complete example so obviously you could there's a lot of ways to break this down so this is a like a bank account or transfer between two customers so here what I'm doing is I look up the source balance between the like a source customer and destination customer right and then I'm comparing and I'm basically doing the calculation of their what I'm doing is I say right I want to look at your source balance and once I take out your source pounds behind your value are you going to still have enough money you know to make this transfer so I'm saying are you is the value going to drop below zero so I can't approve this transfer is this going to be allowed right so I basically get the the source balance the destination balance and I do some math to see if this is going to be you know the math that works out and what I can do inside of this this functional scope of the database is I'm actually doing the subtract I'm doing the add and then I'm saying if statement right so if my source balance is greater than zero then do this this query and inside of this for the Curie stroke I want to do a number of things I want to create a transaction right so I want to keep a transaction log I'm still doing the event sourcing I'm still keeping a record of all the events that have happened so I know exactly what transfers happen isn't you know what money went from her to who but I've also at the same time of keeping the deeds event log I'm keeping an exact account balance right so I'm updating the data for that customer for the source custom a destination customer and giving them an exact balance so they know that their account when they look at the amount of money that I make account they know that it's exact so cool I am out of time no cool all right I'll be around after the talk if you have any questions if you have you talk to you guys so cool thank you everyone [Applause]