In pursuit of the best value US cloud provider
servicestack.net
servicestack.net
Possible negatives depending on your needs:
- no AMAZON AMI: I don't think you can boot your custom O/S. While they have a large choice of OS, it's nowhere close to what AWS provides
- Wider cloud offerings S3, lamba, DBs etc. are not available. You have to setup all that stuff yourself.
2. They used to partner with some vendors that would provide S3 or block devices (iscsi or nvmeof) but not sure if they do anymore
I’m a huge fan of SQLite and have open sourced some .NET stuff around it (eg https://github.com/neosmart/AspSqliteCache ) but learned a very expensive mistake in using it for an ASP.NET Core Project with the default pattern (i.e. with EF Core).
SQLite locks (tables or the entire db depending on configuration) upon write. If you use shared cache mode and WAL you can get very far with one write thread and many competing reads - depending on shared cache mode, WAL, and other options. I benchmarked the different configurations with one or more writing threads here to show how it scales: https://github.com/mqudsi/sqlite-readers-writers
But this approach is hard to model with EF Core. If you use the default request-scoped DI injected connection, you risk any writes upgrading the read lock to a write lock for the duration of the request. The better approach is to use the default request-scoped connection for RO operations and then request a scoped/transient DI connection for any write ops, but copying internal EF entity tracking state from one EF instance to another is tedious and fraught with issues. You’re at least able to work around this if you try to always keep in mind write transaction lifetimes, though.
The problem comes as soon as you need a “background service” in the sense of “an operation running independently of requests and parallel to them.” If that service needs a write lock for any amount of time, you’re suddenly going to be seeing write timeouts (since default behavior is to poll repeatedly until a write lock is obtained) and that is pretty much impossible to fix.
As one of the biggest advantages of using a resident executor like .NET or Java vs a per-request stateless option like PHP is that you can do stuff independent of requests, SQLite is tricky to use correctly in prod in this model.
The good news is that if you use the SQLite EF provider and run into this, it’s usually not too hard to switch to a real DB provider as a lot of the work is abstracted. (Especially Postgres because even manually crafted SQLite queries will likely run as-is or with little alteration, given that they are - largely - modeled after the Postgres ones.)
If you do want to build a (web or otherwise) service around an SQLite database, the best model I’ve found is to use a language with first-class channel (with queuing) support (rust, go, and of late, C# too) and have a dedicated write thread. Servicing threads should have direct RO db access but model any writes or updates as requests posted to the channel (or priority channel). Bonus points if your type system prevents you from accidentally or purposely upgrading an RO service thread/fiber’s db connection to an RW one.
Did the parent comment author play with the mmap / synchronous / temp_store options in their tests? Wondering how those affect the write performance. I know those options from this article: https://blog.wesleyac.com/posts/consider-sqlite
I'm running my SaaS web app with a SQLite db, Node/JS, and Litestream. Getting some number of millions of requests per month and haven't needed to dive in to tuning yet, but I'm curious about it and there's not a lot of data or guides about folks using SQLite as their production db, especially with specific languages or frameworks.
Those options you named will mainly change the specific performance characteristics but not have any impact on architectural matters. I.E. they’ll give you a bit more or less oomph out of a node but typically not make or break your app design.
If you look at the GitHub benchmark I linked, you’ll see how the specific parameters I was referring to give order of magnitude changes in performance whereas eg something like using mmap over distinct syscalls will likely only give you single- or low double-digit gains depending on your configuration (more with speculative execution workarounds enabled on older hardware, less without or on newer).
(Synchronous isn’t an pragma option that you can just enable or disable since it has actual ACID ramifications - i.e. either your usage will let you do it or it won’t.)