Shared map is used to share data among nginx worker processes without any other external services (e.g. redis, memorycached ) or libraries (e.g. SharedHashMap/Chronicle-Map, nginx lua shared dic). So far it has two implementations: tiny map & hash map both of which use MurmurHash3 32-bit to generate hash code. The key/value of shared hash map can be int
,long
,String
, byte array
.
limitation
But note that if needed memory size is less than half of OS page size the real allocated size of nginx slab only can be 2^3 = 8, 2^4 = 16, 2^5 = 32,..., 2^(ngx_pagesize_shift - 1).So on 64-bit OS entry structure size of tiny map really uses 32Bytes hash map uses 64Bytes. We'll do some optimize work in the future versions.
Neither tiny map nor hash map will rehash entries because both of them will have a constant number of buckets once they are initialized.
${number of buckets} = round_up_to_power_of_2( ${entries} * 0.75 )
Optimization for int/long
Some optimization have been done about java int/long key/value, int/long key/value and they won't allocate additional memory because them are stored in the entry structure itself. e.g. in a hash map for a java long key (64bits) we will store it into
viz. use c code
*((uint64_t *)(void*)&entry->key) = ${64bits java long value};
Example
Here's an example to use shared map to count uri access times.
In nginx.conf
shared_map uri_access_counters tinymap?space=1m&entries=8096;
;; be friendly to embeded nginx-clojure where we maybe def shared map before server starts (def dsmap (delay (nginx.clojure.clj.ClojureSharedHashMap. "uri_access_counters"))) ;; if uri not exists set 1 otherwise increase its count. (when (zero? (.putIntIfAbsent @dsmap uri (int 1))) (.atomicAddInt @dsmap uri (int 1)))
// get the shared map. Mostly we do this in a handler // (e.g. jvm init handler, content handler) 's constructor. NginxSharedHashMap smap = NginxSharedHashMap.build("uri_access_counters"); //if uri not exists set 1 otherwise increase its count. //putIntIfAbsent is a faster version of putIfAbsent for int value if (smap.putIntIfAbsent(uri, 1) != 0) { smap.atomicAddInt(uri, 1); }Shared Map Based Ring Session Store
When worker_processes > 1 in nginx.conf, we can not use the default in-memory session store because there're more than one JVM instances and requests from the same session perhaps will be handled by different JVM instances. We can try cookie store, or shared map based ring session store and if we use redis to shared sessions we can try carmine-store or redis session store. Create a shared map based ring session store is very simple. e.g.
In nginx.conf
shared_map my-session-store tinymap?space=10m&entries=1024;
(def nginx.clojure.session/my-session-store (shared-map-store "my-session-store"))
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4