You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Mar 9, 2019. It is now read-only.
My NoSQL LedisDB uses multi optional databases: goleveldb, rocksdb, leveldb, lmdb, boltdb, and random writing performance for boltdb is the worst in my benchmark. You can see the diagram here, raw data here.
@siddontang I'm actually on my way to the airport to go on vacation in a couple hours so I don't have time to dive in deeper right now. I'd love to investigate further when I get back though.
I'm actually surprised that LMDB performs as well as it does for write operations. One reason why Bolt is slower than LMDB (although I'm surprised it's so much slower) is that you're using a lot of dangerous configuration options on LMDB:
NOSYNC & NOMETASYNC can leave your database corrupted in the event of a failure.
WRITEMAP - really dangerous if you have any bugs in your code. You're essentially writing directly to the underlying data file.
MAPASYNC - This flag can leave your database in a corrupted state.
I left these options out of Bolt because it makes the code more complicated (i.e. Bolt is 2KLOC, LMDB is 8KLOC) and because a database shouldn't be corruptible.
Adding a write-ahead log of some kind and grouping updates together into a single transaction can help substantially. Do you still have the coalescer integration code? I'd be curious to see how it's configured.
For a random-write-heavy workload, you're better off using something like LevelDB which writes helps to order random writes sequentially.
I remove lmdb configuration you listed above and bench again, lmdb seems a little better but not much.
LMDB
set: 6415.51 requests per second
incr: 6356.34 requests per second
rpush: 5444.33 requests per second
lpop: 3953.94 requests per second
hset: 5919.33 requests per second
hincrby: 5922.07 requests per second
hdel: 5842.37 requests per second
zadd: 5813.88 requests per second
zincrby: 5753.64 requests per second
zrem: 5430.68 requests per second
BoltDB
set: 970.57 requests per second
incr: 3518.69 requests per second
rpush: 2789.03 requests per second
lpop: 2341.30 requests per second
hset: 3335.03 requests per second
hincrby: 3163.00 requests per second
hdel: 3404.88 requests per second
zadd: 3380.41 requests per second
zincrby: 3296.58 requests per second
zrem: 3391.19 requests per second
Because LedisDB supports replication, it may take the risk when system crashed. (Not 100% OK), I may still use these dangerous configurations.
Using coalescer is here. but the benchmark is very poor, maybe I use wrong?
Although LevelDB's random write is very good, it is not good for range get, especially for reverse range get. but LMDB or BoltDB can do it easily.
@siddontang Can you dump the profiles out to SVG? It's easier to see the call stack from that. I'm curious why mach_semaphore_wait is taking up 61% of the CPU time.
@siddontang Also, I don't have any plans to add dangerous configuration options beside the DB.NoSync that's already there. Dangerous configuration options don't simply corrupt the database so it doesn't open or rolls back a transaction. Without an fsync, hard drives can reorder write operations so that data pages can be written after a meta page and your data is silently corrupt.
The mach_semaphore_wait issue makes me think there's lock contention somewhere but it's hard to say where (or whether it's in Bolt or Ledis) until we look at the SVG.
It's all ultimately a tradeoff. Bolt has lower random write performance but has significantly better sequential read performance than LevelDB.
@siddontang Can you give me the steps to reproduce the benchmark? I found commands on the benchmark page but I didn't see how to select Bolt specifically. From your SVG, I don't think you have the Mac pprof fix. I can try it on mine and try it on Linux as well.
Ultimately, I don't think Bolt is the best choice for Ledis if a user is doing a lot of random writes unless you implement some kind of coalescing. Not sure why the coalescer isn't helping at all but we can figure that out.
Sorry that LedisDB has a painful configuration and an unclear guild, I will improve it as soon as I can.
I have not patched the mac pprof fix, sorry that too.
If you want to bench it yourself, you can do these below:
runmake to build LedisDB, it will build ledis-server and ledis-benchmark
copy ledisdb/etc/ledis.json to /etc/ledis.json which is ledis-server's default config path
run ledis-server -db_name=boltdb
run ledis-benchmark
Many users like Pure Go, and LedisDB now supports two pure Go storage: goleveldb and BoltDB, their advantages vary, user can choose the proper one based on the real situation.
One optimization that Bolt hasn't added yet that LMDB has is using pwritev() to flush multiple pages at once. I added an issue (#238) for this so it can get added. It shouldn't be a difficult fix.
It looks like the performance is dominated by syscalls since you're doing so many tiny transactions. That optimization should help Bolt performance significantly.
One other thing to note, though, is that ledis' respClient is using a significant amount of CPU to read lines. That's probably worth optimizing on your side.
Activity
benbjohnson commentedon Aug 4, 2014
@siddontang I'm actually on my way to the airport to go on vacation in a couple hours so I don't have time to dive in deeper right now. I'd love to investigate further when I get back though.
I'm actually surprised that LMDB performs as well as it does for write operations. One reason why Bolt is slower than LMDB (although I'm surprised it's so much slower) is that you're using a lot of dangerous configuration options on LMDB:
https://github.com/siddontang/ledisdb/blob/master/store/mdb/mdb.go#L47
NOSYNC
&NOMETASYNC
can leave your database corrupted in the event of a failure.WRITEMAP
- really dangerous if you have any bugs in your code. You're essentially writing directly to the underlying data file.MAPASYNC
- This flag can leave your database in a corrupted state.I left these options out of Bolt because it makes the code more complicated (i.e. Bolt is 2KLOC, LMDB is 8KLOC) and because a database shouldn't be corruptible.
Adding a write-ahead log of some kind and grouping updates together into a single transaction can help substantially. Do you still have the coalescer integration code? I'd be curious to see how it's configured.
For a random-write-heavy workload, you're better off using something like LevelDB which writes helps to order random writes sequentially.
siddontang commentedon Aug 4, 2014
Thank you for the detailed reply.
I remove lmdb configuration you listed above and bench again, lmdb seems a little better but not much.
LMDB
BoltDB
Because LedisDB supports replication, it may take the risk when system crashed. (Not 100% OK), I may still use these dangerous configurations.
Using coalescer is here. but the benchmark is very poor, maybe I use wrong?
Although LevelDB's random write is very good, it is not good for range get, especially for reverse range get. but LMDB or BoltDB can do it easily.
siddontang commentedon Aug 4, 2014
Later, like Redis, I may supply a mechanism for LMDB data saving. User can set sync at once or at every N seconds, or even not sync at all.
benbjohnson commentedon Aug 4, 2014
Can you get cpu, memory, and block profiles for the Bolt benchmarks? You can use something like Dave Cheney's profile library to make it easy.
siddontang commentedon Aug 5, 2014
I used
net/http/pprof
to profile it but found nothing performance bottleneck. BoltDB is slower than LMDB maybe Go is slower than C, I think.heap
cpu
Hope you can add above dangerous configurations, then I can control how and when to sync.
Thank you!
benbjohnson commentedon Aug 5, 2014
@siddontang Can you dump the profiles out to SVG? It's easier to see the call stack from that. I'm curious why
mach_semaphore_wait
is taking up 61% of the CPU time.benbjohnson commentedon Aug 5, 2014
@siddontang Also, I don't have any plans to add dangerous configuration options beside the
DB.NoSync
that's already there. Dangerous configuration options don't simply corrupt the database so it doesn't open or rolls back a transaction. Without an fsync, hard drives can reorder write operations so that data pages can be written after a meta page and your data is silently corrupt.The
mach_semaphore_wait
issue makes me think there's lock contention somewhere but it's hard to say where (or whether it's in Bolt or Ledis) until we look at the SVG.It's all ultimately a tradeoff. Bolt has lower random write performance but has significantly better sequential read performance than LevelDB.
siddontang commentedon Aug 6, 2014
Github not supports svg upload, so I share full here
Some parts:
mach_semaphore_wait
is in LedisDB not BoltDB.I think if someone cares security, reads more than writes, BoltDB is a good choice.
benbjohnson commentedon Aug 6, 2014
@siddontang Can you give me the steps to reproduce the benchmark? I found commands on the benchmark page but I didn't see how to select Bolt specifically. From your SVG, I don't think you have the Mac pprof fix. I can try it on mine and try it on Linux as well.
Ultimately, I don't think Bolt is the best choice for Ledis if a user is doing a lot of random writes unless you implement some kind of coalescing. Not sure why the coalescer isn't helping at all but we can figure that out.
siddontang commentedon Aug 6, 2014
Sorry that LedisDB has a painful configuration and an unclear guild, I will improve it as soon as I can.
I have not patched the
mac pprof fix
, sorry that too.If you want to bench it yourself, you can do these below:
make
to build LedisDB, it will build ledis-server and ledis-benchmarkledis-server -db_name=boltdb
ledis-benchmark
Many users like Pure Go, and LedisDB now supports two pure Go storage: goleveldb and BoltDB, their advantages vary, user can choose the proper one based on the real situation.
pkieltyka commentedon Aug 6, 2014
or just make a local ledis.json and use -config=./ledis.json
benbjohnson commentedon Aug 6, 2014
@siddontang Here's the pprofs I got:
One optimization that Bolt hasn't added yet that LMDB has is using
pwritev()
to flush multiple pages at once. I added an issue (#238) for this so it can get added. It shouldn't be a difficult fix.It looks like the performance is dominated by syscalls since you're doing so many tiny transactions. That optimization should help Bolt performance significantly.
benbjohnson commentedon Aug 6, 2014
One other thing to note, though, is that ledis' respClient is using a significant amount of CPU to read lines. That's probably worth optimizing on your side.
siddontang commentedon Aug 6, 2014
LedisDB uses Redis Protocol, respClient must read line by line to parse a request, I will try to optimize it later.
Thank you!