Building a Networked Key-Value-Store on an FPGA
adamwalker.github.io
adamwalker.github.io
Just to clarify there, many key value stores are not hash tables but btrees or LSM trees. One reason not to use hashtables is that you can't do efficient prefix scans since hashtables aren't sorted. Though it's possible redis and memcached do use a hashtable. Rocksdb/Leveldb, and pebble use LSM trees. Berkeleydb allows you to use a btree or hashtable.
Yep. In fact, in an FPGA, you can even have true TCAM/CAMs (content addressable memory).
https://www.xilinx.com/products/intellectual-property/ef-di-...
I really like the idea of stripping away essentially everything that is not needed and being left with what is.
If this is done all the way, it would be an incredibly sturdy and reliable (but a bit small) key-value-store.
Does the SRAM latency still allow for single-cycle reads at 10G?
The SRAM clock and the Ethernet clock can be independent. The SRAM clock rate is what determines the rate of lookups for a single cuckoo hashtable.
On a modern FPGA, the SRAM clock can run up to about 500MHz. So, if you pipeline things, you can get 500 million lookups per second in the FPGA fabric. The maximum packet rate in 10G Ethernet is around 15 million/sec. So, no matter how you design the protocol you use to communicate with the FPGA, if you only request a single lookup per packet, you will be well below the maximum rate the RAMs can support.
Of course, I haven't actually built any of this. The clock rates in the blog post are much lower, and the chip is much smaller. So, this is all an educated guess.
Well, yes. With a short enough piece of network cable it's probably lower latency to query a different one of these devices a short way away than wait for DRAM to very slowly charge up a row.
However, if you are building a hashtable in external RAM that is accessed via Ethernet, I think there are still some performance gains to be had with an FPGA compared to a non-specialized device.
For one, you get to skip the PCIe bus with an FPGA, reducing latency, since the Ethernet transceivers go straight into the FPGA fabric. Also, while I don't know a lot about power consumption, I expect it would be a fair bit lower on a dedicated FPGA compared to a server performing the same work.
Also, I hadn’t heard of cuckoo hashing before, it sounds neat. I briefly looked at the Wikipedia page about cuckoo hashing that the OP linked to, but didn’t find an answer, so I’ll ask this here:
What happens when the load factor of a set of tables gets “too high”, can you just create a new table and prepend it to the list of tables and call it a day, or do you still need to rehash the existing tables?
In general this is a bad idea. It's a very tempting idea, but it leans heavily on "sufficiently smart compiler" that's inevitably not that smart and also not well supported since it's one guy's research project. Even the vendor supported ones aren't that great.
You'd be better off with a higher-level or more modern HDL that compiles to Verilog/VHDL. "Chisel" is one such.
The need to control state vs time and manage pipelining makes most higher level software languages unhelpful when trying to get efficient FPGA performance. Not only that, higher level software languages tend to encourage recursion, which maps really badly to FPGA architecture.
As is Clash, the language this project was written in :) https://clash-lang.org/
Since you have multiple hash functions in use at the same time you can simply increase the number of hash functions when you grow a table to include ones that also cover the new table space.
You can then lazily hash keys with the new functions whenever they are cuckooed out of the current position, and perform lookup with all of them.
If you keep track of how many elements are using each function, you can then start deprecating the old ones once all of their keys have been hashed with the new range.
If entry one hits a series of eviction locations A0, A1, A2... and entry two ends up going into AN with the same key as A(N-1) in a fewer number of steps than N, wouldn't that result in an earlier entry overwriting a later entry? Trying to wrap my head around how concurrency works when the steps are all on the same clock.
However, I can say that I used a SMT solver as part of the wonderful SymbiYosys verification flow to verify that the design was good for around 20 cycles, no matter what the inputs are. That, and the randomised testing gives me quite a bit of confidence in the design.
However, I do have a bit of experience designing low latency FPGA based networking firmware. <100 nanoseconds measured wire to wire at the Ethernet level should be possible with 10G Ethernet. That's actually quite a long time on an FPGA. But, when you have latencies on the order of packet (de)serialization times, you need to be very careful about what you are measuring.
Also, I haven't actually built what I'm describing, so take my estimates with a grain of salt.
This is a big reason why chatgpt is useful. Because some people are not better than a keyword search.