Finally got a chance to sit down and get something I have been working on to become open-source, published, etc. There has been the discussion of having an RPC layer that does not require the use of native libraries for the longest time from what I can tell. I also felt that the same RPC layer itself need not be tied to the project as you should be able to front a transactional, key-value store with a common protocol language (think SQL) that allows one to swap implementations (an in-memory version for testing? something that’s backed by RDS on AWS if you don’t need the scale/cost-profile of FoundationDB?).
Lionrock is a facade for Transactional, Key-value Stores
It includes:
- An implementation agnostic protocol definition that’s heavily inspired by what FoundationDB does (of course, because it’s probably the best way to code against a transactional, key-value store =p)
- An actual implementation of said API against a FoundationDB cluster (or multiple FoundationDB clusters) that allows horizontal scaling, multi-version client support, and ultimately packaged as a container that one could run and scale independently to the underlying cluster.
[lionrock-foundationdb-server] - An implementation of Database and Transaction classes in fdb-java that uses gRPC underneath the hood which should allow (mostly) drop-in replacement of the gRPC-based client in place of the native library one (still need to depend on fdb-java for the interfaces and things like Tuple, we’ll have to break off an fdb-java-api artifact if we want to ditch the native library for good on the FoundationDB side)
[lionrock-foundationdb-client]
Running the Server (until I get the image deployed on dockerhub)
./gradlew bootRun --args='--logging.level.io.github.panghy.lionrock=DEBUG'
Accessing a Server (from Java)
public class FdbClient {
public static void main(String[] args) {
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 6565).
usePlaintext().
build();
// "fdb" is the default database on the server.
Database db = RemoteFoundationDBDatabaseFactory.open("fdb", "my client", channel);
db.runAsync(tx -> {
tx.set(HELLO_B, WORLD_B);
return tx.get(HELLO_B);
}).join();
channel.shutdown();
}
}
Cool stuff
- Paves the way for any clients to be built for all gRPC supported languages (help wanted!)
- Removes the need to have multi-version client binaries on anything that touches FoundationDB
- Supports things like watches and getting versionstamps post-commit (gotcha there is that watches will fail if the server dies while waiting for an update, just need to watch the key again)
- The server publishes metrics and collects tracing spans (you can turn that on with a throw-away account on https://wavefront.surf by following the instructions). Can also be configured to publish prometheus metrics and zipkin traces.
Future Plans
- Build an authorization layer on-top of the lionrock protocol that prevents some users from doing writes? Restricts access for some users to a certain key range?
- Build a caching layer that allows stale reads?
- Build a batching layer that batches blind writes together?
- An in-memory implementation of the gRPC server packaged as a container for unit tests?
- A pure gRPC CLI tool?
- An implementation of the protocol against a SQL-database (probably not optimized for speed but just for simplicity in some deployments)?
I am aware of the efforts in:
- Provide a more standard RPC client interface · Issue #2302 · apple/foundationdb · GitHub
- FoundationDB RPC Layer Requirements · apple/foundationdb Wiki · GitHub
Maybe it solves that problem/issue, open to discussion here.
My next milestone is to be able to run, say, the record layer with the gRPC client instead of the native one. Should be fun!
Traces from the Server (including async operations within a single transaction)