Live data from Hacker News

TrailBase: Sub-millisecond open-source application base with Rust, SQLite and V8

trailbase.io

31–37 of 37 posts

Re: TrailBase: Sub-millisecond open-source application base with Rust, SQLite and V8

#31

Earlier quoted context omitted.

> I'm not sure this is expected but it didn't seem to make much of a difference with my setup I expect it to be faster but it is also possible that maybe in your specific collection and execution scenario it somehow perform worst, or at least not the same as in my benchmarks, I'm not sure. The ~4x mentioned speed up is based on the tests for Hetzner CAX41 with the CGO driver when creating 50k records with 500 concurr…

> Edit: Based on your benchmarks repo ( https://github.com/trailbaseio/trailbase-benchmark/tree/main ...) note that compiling PocketBase with `CGO_ENABLED=1` is no longer enough to kick in the github.com/mattn/go-sqlite3 driver and you need to enable it manually as shown in the db_cgo.go in our benchmarks OR like in https://pocketbase.io/docs/go-overview/#github-commattngo-sq ... (the reason for this change was to av…

> My initial comment was more of a note/suggestion to simply list the used versions of the tested platforms (not just for PocketBase) because often they change over time and the shown results could be misleading if someone stumble on it 2 years later for example.

FWIW, it never felt like a dispute and very much agree with your suggestion. I'm also just trying to do a decent enough job, both with the benchmarks and TrailBase itself. Either way, my offer to keep an open channel stands in case you want to share experiences or are in desperate need for a beverage :)

Re: TrailBase: Sub-millisecond open-source application base with Rust, SQLite and V8

#32

Given the underlying SQLite calls are sync why is the query API async? From my own experiments with Node and SQLite I've found synchronous sqlite libraries like https://www.npmjs.com/package/better-sqlite3 substantially faster, especially when making many simple queries (a pattern encouraged by SQLite.)

I'm not sure if you're referencing the client libs or the server-side v8 integration. Either way, both are async. The client is async because there's network in between. And the server-side v8 integration is async to schedule execution on a dedicated SQLite event loop. What you're saying makes a lot of sense. SQLite is sync and if you're program is alone accessing SQLite doing a single task, going sync is the way. If…

Im referring to the server-side v8 integration.

> What you're saying makes a lot of sense. SQLite is sync and if you're program is alone accessing SQLite doing a single task, going sync is the way. If you're doing a lot of parallel work, both your JS event loop interleaving many tasks and several event loops accessing SQLite in parallel you have to make trade-offs. Specifically, `conn.query` may block for a long time w/o doing any work. Depending on your use-case it may or may not be ok to block the event-loop that entire period.

In WAL mode SQLite is very good at supporting parallel reads from multiple threads. It should only block for a long time when writing (since writes require an exclusive lock.)

It sounds like your v8 worker threads are mixing read and write work so you are running the query in another sqlite thread pool to prevent writes from blocking reads.

> TrailBase's setup is optimized to maximize throughput under highly concurrent loads, rather than minimizing latency in single-threaded workloads. That's not to say, TrailBase isn't quick. It's pretty low-latency even under load. However, if that's all you're after you're probably better off with better-sqlite3 or dropping down to C :).

Given the additional costs of cross-thread communication I would be surprised if this approach maximizes throughput under highly concurrent loads compared to segregating write requests into a dedicated thread and running read queries synchronously from within their threadpool with a single task per thread.

Re: TrailBase: Sub-millisecond open-source application base with Rust, SQLite and V8

#33

Earlier quoted context omitted.

I'm not sure if you're referencing the client libs or the server-side v8 integration. Either way, both are async. The client is async because there's network in between. And the server-side v8 integration is async to schedule execution on a dedicated SQLite event loop. What you're saying makes a lot of sense. SQLite is sync and if you're program is alone accessing SQLite doing a single task, going sync is the way. If…

Im referring to the server-side v8 integration. > What you're saying makes a lot of sense. SQLite is sync and if you're program is alone accessing SQLite doing a single task, going sync is the way. If you're doing a lot of parallel work, both your JS event loop interleaving many tasks and several event loops accessing SQLite in parallel you have to make trade-offs. Specifically, `conn.query` may block for a long time…

> In WAL mode SQLite is very good at supporting parallel reads from multiple threads. It should only block for a long time when writing (since writes require an exclusive lock.)

Agreed.

> It sounds like your v8 worker threads are mixing read and write work so you are running the query in another sqlite thread pool to preven> In WAL mode SQLite is very good at supporting parallel reads from multiple threads. It should only block for a long time when writing (since writes require an exclusive lock.)

Agreed.

> It sounds like your v8 worker threads are mixing read and write work so you are running the query in another sqlite thread pool to prevent writes from blocking reads.

The v8 isolates run whatever you as a TrailBase user feed them. I would certainly expect writes to be a common occurrence.

> Given the additional costs of cross-thread communication I would be surprised if this approach maximizes throughput under highly concurrent loads compared to segregating write requests into a dedicated thread and running read queries synchronously from within their threadpool with a single task per thread.

Ultimately, it will depend a lot on the ratios. If you have mostly reads and the occasional write you're probably right. I did spend a bit of time exploring different execution models: https://github.com/ignatz/libsql_bench in case you're interested. There's also some prior works from the folks GIL'ed languages (especially ruby) around how to wrangle write congestion for multi-process workloads. Sadly for them, they don't have inter-thread comms in their arsenal :)

One big unknown for me is, how you'd clearly separate reads from writes. As far as I can think, you'd have to rely on users to pick the right sync or async funnel. Which may be ok at least for simple queries.

FWIW, the thing or elephant that bothered me more than inter-thread comms is the opportunity cost of not running reads in parallel. Then at the same time, the current setup does seem to manage to saturate the machines I've run on. Very high core-count machines would probably be a different story. It will certainly also depend on how much actual other work the server has to do, i.e. is it just a glorified SQLite accessor? I certainly would love to further optimize that aspect. You seem very well informed so I'd love to hear your thoughts. Hit me up, if you'd like to chat more.t writes from blocking reads.

The v8 isolates run whatever you as a TrailBase user feed them. I would certainly expect writes to be a common occurrence.

> Given the additional costs of cross-thread communication I would be surprised if this approach maximizes throughput under highly concurrent loads compared to segregating write requests into a dedicated thread and running read queries synchronously from within their threadpool with a single task per thread.

Ultimately, it will depend a lot on the ratios. If you have mostly reads and the occasional write you're probably right. I did spend a bit of time exploring different execution models: https://github.com/ignatz/libsql_bench in case you're interested. There's also some prior works from the folks GIL'ed languages (especially ruby) around how to wrangle write congestion for multi-process workloads. Sadly for them, they don't have inter-thread comms in their arsenal :)

One big unknown for me is, how you'd clearly separate reads from writes. As far as I can think, you'd have to rely on users to pick the right sync or async funnel. Which may be ok at least for simple queries.

FWIW, the thing or elephant that bothered me more than inter-thread comms is the opportunity cost of not running reads in parallel. Then at the same time, the current setup does seem to manage to saturate the machines I've run on. Very high core-count machines may be a different story. It will certainly also depend on how much actual other work the server has to do, i.e. is it just a glorified SQLite accessor? I certainly would love to further optimize that aspect. You seem very well informed so I'd love to hear your thoughts. Hit me up, if you're willing to chat more.

Re: TrailBase: Sub-millisecond open-source application base with Rust, SQLite and V8

#34
post #25

Earlier quoted context omitted.

No I meant, is it "just like Firebase (ACLs on the backend) but simpler"? I understand ACLs on the backend and API queries on the client, I just don't find it that practical to use

Could you expand a bit on, how > I feel I prefer to have a locked-down database, and implement everything "backend-side" with a kind of "admin API" which has access to everything, and checks user roles in the backend, it feels cleaner to me, is that also possible? is different from what FireBase or TrailBase does? Are you saying that you'd prefer to run your own backend binary (as opposed to running in an integrated…

Yes, I prefer to have no direct access to the database from the client, just go through my API, and my API handles ACLs and do the SQL calls

Re: TrailBase: Sub-millisecond open-source application base with Rust, SQLite and V8

#35
post #34

Earlier quoted context omitted.

Could you expand a bit on, how > I feel I prefer to have a locked-down database, and implement everything "backend-side" with a kind of "admin API" which has access to everything, and checks user roles in the backend, it feels cleaner to me, is that also possible? is different from what FireBase or TrailBase does? Are you saying that you'd prefer to run your own backend binary (as opposed to running in an integrated…

Yes, I prefer to have no direct access to the database from the client, just go through my API, and my API handles ACLs and do the SQL calls

Got it. Sounds like you're in the market for a SQL database. In your setup, is there anything extra you'd want? I guess I'm merely wondering what FireBase and Co could even provide to you?

Re: TrailBase: Sub-millisecond open-source application base with Rust, SQLite and V8

#36
post #34

Earlier quoted context omitted.

Yes, I prefer to have no direct access to the database from the client, just go through my API, and my API handles ACLs and do the SQL calls

Got it. Sounds like you're in the market for a SQL database. In your setup, is there anything extra you'd want? I guess I'm merely wondering what FireBase and Co could even provide to you?

Firebase provides the auth, and the fact that it's easy to take a look at the database, but indeed I'd rather use Postgres

Re: TrailBase: Sub-millisecond open-source application base with Rust, SQLite and V8

#37
post #36

Earlier quoted context omitted.

Got it. Sounds like you're in the market for a SQL database. In your setup, is there anything extra you'd want? I guess I'm merely wondering what FireBase and Co could even provide to you?

Firebase provides the auth, and the fact that it's easy to take a look at the database, but indeed I'd rather use Postgres

Makes sense. If it's mostly auth you're after, there's a bunch of dedicated products: https://github.com/zitadel/zitadel, https://github.com/teamhanko/hanko, https://github.com/casdoor/casdoor, https://github.com/authelia/authelia (At least the first is Postgres compatible)
Post reply on HN