0
$\begingroup$

I have started to play around with HTTP3 which relies on QUIC for transport. I have noticed that I very often have a finite number of Web Transport sessions stream data continuously along side burst-y HTTP3 REST calls. At the QUIC level, all of these streams are going over the same connection and are demultiplexed via a go hash map by Stream ID. This is working fine, but I was wondering about scaling; specifically the Web Transport streams are typically more latency sensitive than the REST API calls. More generally, I find that I want to prioritize the active streams that have sent the most data.

Focusing on the go hashmap that treats all keys equally, is there any hash table that prioritizes keys that get referenced the most? So if Stream N gets referenced 100K times and Stream M gets referenced 10 times, the hash algorithms checks for a match of N before M?

Update

To clarify QUIC's connection/stream model more (and ignore crypto for now):

  • A QUIC connection, ignoring crypto, can be thought of as a typical UDP connection. It is over this that QUIC Frames get passed.
  • QUIC Streams act like TCP connections, data regarding a stream is passed over the connection in a QUIC Stream Frame with the Stream ID in the header.

So a QUIC connection allows for the passing of QUIC Frames, and both client and server must identify which frames belong to which streams (via Stream ID mapped to an internal context) and pass the data along. to local conversation handlers.

Update #2

As stated in the comments by other users, implementing this very well may not be worth the overhead, but here is an unoptimized version of what I am talking about:


type WeightedMap []WeightedEntry

type WeightedEntry struct{
    refcount uint64
    Key int //streamID
    Value interface{} // basically a pointer in go
}

func (w *WeightedMap)Get(key int) (out interface{}){
    vm := *w
    for i := range vm{
       if vm[i] == key{
         vm[i].refcount++
         out = vm[i].Value
         break
       }
    }
    if out != nil{
      sort.SliceStable(wm, func(i, j int) bool {
          return wm[i].refcount > wm[i].refcount
      })
    }
}

A better version could at least greatly improve the Sort step by just looking at the entry in question and its neighbor with a higher index. Just wanted to convey a rough idea.

$\endgroup$
12
  • $\begingroup$ Please let me know if I understand the scenario. A stream has an ID. Now the data for each stream is multiplexed in to a single connection. When data are received, the data for a stream is reconstructed by storing them into the hashmap using the stream ID as key. If this is the case, what do you mean when you want to prioritize a stream via a hashmap? $\endgroup$
    – Russel
    Commented May 18, 2022 at 14:30
  • $\begingroup$ @Russel Streams in the same connection may have different lifetimes and tolerances. Generally the streams i use for alerting stay up, pass a lot of data and benefit from low latency, while general request/response streams may have a short lifetime and not care about delay as much. If I can prioritize the stream lookup for the alert streams as the map gets bigger, that would improve performance. $\endgroup$
    – Liam Kelly
    Commented May 18, 2022 at 17:11
  • 1
    $\begingroup$ What precisely do you mean by "prioritizes keys that get referenced the most"? Hash tables don't check for a match one at a time, so your statement "the hash algorithms checks for a match of N before M" seems meaningless to me. I am wondering if you have a misunderstanding of how hash tables work fine. $\endgroup$
    – D.W.
    Commented May 18, 2022 at 19:20
  • 1
    $\begingroup$ Have you verified that inserting and retrieving stream id incurs significant time when running QUIC's connection/stream model, at least in your case, by some performance measurement/profiling? Have you verified significant slowdown for Web Transport streams if the percentage of the REST API calls are much greater? $\endgroup$
    – John L.
    Commented May 18, 2022 at 20:54
  • 1
    $\begingroup$ If you are using a hash map, there will be no need to perform such linear search just to find the entry matching the key. In the simplest case (no collision) , all you need to do is to compute a hash value i =h(entry.Key), where h() is some hash function, using the key of the entry and insert that entry in the ith index of your array. Then given a key to retrieve an entry, you do the same computation to obtain i and retrieve the ith entry. $\endgroup$
    – Russel
    Commented May 19, 2022 at 14:35

1 Answer 1

1
$\begingroup$

A hash table takes a key, calculates a hash value for the key, and maps the hash value to a sequence of indexes into the table. The mapping key -> hash value is fixed at least while the hash table exists.

Usually the number of possible hash values is huge; it might be $2^{64}$ which means you won't have the same hash value twice in practice. But each hash produces a sequence of indexes, and many keys might use the same index.

Usually you keep the hash table substantially larger than the number of values stored, so if the indexes were random, you would find a key very often at the first index, quite often at the second index, rarely at the third or later index. So the number of indexes to check should be small anyway; otherwise you increase the table size. And skipping the wrong index is very fast: You store the hash key with the value in the hash table, so when you check index i, all you do is to compare the hash values which are stored in the table or just computed. This is very fast.

The things costing substantial effort are: 1. Calculate the hash value for the key to look up. 2. When an index with the right hash value is found, compare the keys. Everything else has minimal execution time, so there's very little need to improve the time for the keys used most often.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.