ledisdb / ledisdb

A high performance NoSQL Database Server powered by Go

Home Page:https://ledisdb.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RAM is very slow for HMset and and HMget

unisqu opened this issue · comments

#354

extremely slow, how do I speed it up? Afterall, I'm using RAM, using redis directly is 2x slower (because of the TCP roundtrip i suspect) but other in-memory such as freecache is running around 50ms average for both SET and GET.

Currently with the example you have provided, I'm running HMset at 6s. Can you pls give example on how to speed this up? I suspect it's at the FVPair area but... any ideas?

Hope you can look into the GC area like freecache. Thanks in advance.

pure SET and GET only 3x slower than freecache which is "acceptable"

I'm using https://pastebin.com/raw/fntT7PKJ

it's actually as a package. How do I do cfg.DBName = "RAM" from a package called "myLedisDB"?
I dont know how to call it in func main() too... but I prefer it's set inside "myLedisDB" package. Can you provide some guidance? Thanks.

i've tried
lediscfg.NewConfigDefault().DBName = "RAM" (doesnt work obviously)

I've tried also inside "package myLedisDB" (which seems to be working)

         func init() {
                    cfg.DBName = "RAM"
         }

how can I tell if it's working as RAM package library? is there a way to check?

IMO, I can't get your point about how to set "RAM", you can set it every where before you initialize ledisdb.

I'm running HMset at 6s

Can you give me your benchmark case? 6s is too slow.

6s for 100,000 HMset, around 16666.6667 HMset per second. I would like to speed this up because I'm getting freecache for 100,000 set at 60ms, around 1,666,666.67 req/s using freecache set.

possible to improve this? 16k hmset request/s i think it can be much higher, it's 100x slower than freecache

try this :
https://pastebin.com/raw/df4pMAsz

pls give suggestions on how to speed it up. it's really too slow. I think 20x slower is acceptable but not >20x slower... actually i think <10x slower is considered good.

actually both are in RAM so i dont really understand why HASH should be so much slower.

@unisqu

The RAW mod you used is wrong, here is my change:

var cfg *lediscfg.Config
var fcachel *ledis.Ledis
var fcachedb *ledis.DB

func main() {
	cfg = lediscfg.NewConfigDefault()
	cfg.DBName = "memory"
	var err error
	fcachel, _ = ledis.Open(cfg)
	fcachedb, _ = fcachel.Select(0)

Above can use the memory mode. But this is still slower than freecache, some reasons:

  • You set multi field-values, each pair is a new key-value written, so the number of total written keys is 4 times than freecache.
  • HMset and HExpire also need to write meta data, another extra two Write operations.
  • HMSet and HExpire also need to read the meta data of Hash, another extra two Read operation
  • HMSet and HExpire will encode the key internally, this causes allocation and memmove.
  • goleveldb uses skiplist, which is not optimized

As you can see, many things need to be done in LedisDB, but I am still not satisfied with its performance, I have been planning to refactor this project, but have not enough time, sorry.

another thing is that even we use memory mode, goleveldb will still write data to WAL which will cause another I/O...

@unisqu

The RAW mod you used is wrong, here is my change:

var cfg *lediscfg.Config
var fcachel *ledis.Ledis
var fcachedb *ledis.DB

func main() {
	cfg = lediscfg.NewConfigDefault()
	cfg.DBName = "memory"
	var err error
	fcachel, _ = ledis.Open(cfg)
	fcachedb, _ = fcachel.Select(0)
  1. I see a significant improvement from 6.5s to 5.3s with the above change. Thx

  2. I see, how to disable the WAL? I need it in memory mode only.

  3. there's advantage to using hash data type in cache on my application. if memory is exceeded, what will happen? the hash "key" is dropped based on LRU? (i would prefer this way)

i can rewrite the code for the "pure ram version" if u can guide me on the section to do so.

otherwise i would prefer getting the application up and temporary disabling WAL with code modification. Please point me to the direction for disabling WAL too. Thx.

by the way, i'm quite surprised there's no easier way to rewrite this... seems very "redundant/extra"

       c := ledis.FVPair{Field: []byte("c" + urlreq), Value: []byte(htmlcode)}
       h := ledis.FVPair{Field: []byte("h" + urlreq), Value: []byte(qwcache)}
       t := ledis.FVPair{Field: []byte("t" + urlreq), Value: []byte(strconv.Itoa(timeNow))}
       s := ledis.FVPair{Field: []byte("s" + urlreq), Value: []byte(strconv.Itoa(statuscode))}

@unisqu

There is no way to disable WAL, you have to change the goleveldb code, but I don't know wether it is right or not. You can comment https://github.com/siddontang/ledisdb/blob/master/vendor/github.com/syndtr/goleveldb/leveldb/db_write.go#L244

For memory mode, all data will be saved in memory, no LRU, so you may meet OOM.

you can use

paris := []ledis.FVPair{
  {key, value},
  {key, value},
}

to simplify your code.

IMO, if you care too much about performance and just want a cache now, my project is not a good choice for you, because I have no time to improve it.

OOM

  1. is there a quick fix to this? limiting ram usage and evicting based on LRU. do you mind pointing me to where i can fix this myself? i can buy you a few more coffee for this feature.

  2. ok i've seen the code to goleveldb... i think i can comment enough things to skip those goleveldb sections.

truly, this package is more useful if purely MEMORY only. I really thought it was just memory only but i can't believe still needing to go through goleveldb.

from my assessment of your code, should only take 1 day for you to write for pure memory only with LRU.

I dont mind waiting a bit for this but when do you think you can do this? over the weekend?

is there a quick fix to this? limiting ram usage and evicting based on LRU. do you mind pointing me to where i can fix this myself? i can buy you a few more coffee for this feature.

maybe we can try other memory engines instead. But you must realize that LedisDB is not designed for cache. So if you forget to expire the key, you will meet OOM.

This is not one day or one-weekend work, and another problem is that I have not enough time even at the weekends these days. To my honest, I want many guys to use my project, but now I have to suggest not using this project because it can't fit your need and can't be improved quickly.

do you have alternatives for the moment that uses hash like data structure for cache in golang? in-memory

it doesn't have hash key field value
only key value

groupcache doesnt have expire value