Willem
2013-Apr-18 18:28 UTC
[Gluster-users] Low (<0.2ms) latency reads, is it possible at all?
I'm testing GlusterFS viability for use with a typical PHP webapp (ie. lots
of small files). I don't care so much for the C in the CAP theorem, as I
have very few writes. I could live with a write propagation delay of 5
minutes (or dirty caches for up to 5 minutes).
So I'm optimizing for low latency reads of small files. My testsetup is 2
node replication. Each node is both server and gluster client. Both are in
sync. I stop glusterfs-server @ node2. @node1, I run a simple benchmark:
repeatedly (to prime the cache) open & close 1000 small files. I have
enabled the client-side io-cache and quick-read translators (see below for
config).
The results are consistently 2 ms per open (O_RDONLY) call. Which is too
slow, unfortunately, as I need < 0.2ms.
The same test with a local Gluster server and NFS mount, I get somewhat
better performance but still 0.6ms.
The same test with Linux NFS server (v3) and local mount, I get 0.12ms per
open.
I can't explain the lag using Gluster, because I can't see any traffic
being sent to node2. I would expect that using the io-cache translator and
local-only operation, the performance would approach that of the kernel FS
cache.
Is this assumption correct? If yes, how would I profile the client sub
system to detect the bottleneck?
If no, then I have to accept that 0.8ms open calls are the best that I
could squeeze out of this system. Then I'll probably look into AFS,
userspace async replication or gluster NFS mount with cachefilesd. Which
would you recommend?
Thanks a lot!
BTW I like Gluster a lot, and hope that it is also suitable for this small
files use case ;)
//Willem
PS Am testing with kernel 3.5.0-17-generic 64bit and gluster 3.2.5-1ubuntu1.
Client volfile:
+------------------------------------------------------------------------------+
1: volume testvol-client-0
2: type protocol/client
3: option remote-host g1
4: option remote-subvolume /data
5: option transport-type tcp
6: end-volume
7:
8: volume testvol-client-1
9: type protocol/client
10: option remote-host g2
11: option remote-subvolume /data
12: option transport-type tcp
13: end-volume
14:
15: volume testvol-replicate-0
16: type cluster/replicate
17: subvolumes testvol-client-0 testvol-client-1
18: end-volume
19:
20: volume testvol-write-behind
21: type performance/write-behind
22: option flush-behind on
23: subvolumes testvol-replicate-0
24: end-volume
25:
26: volume testvol-io-cache
27: type performance/io-cache
28: option max-file-size 256KB
29: option cache-timeout 60
30: option priority *.php:3,*:0
31: option cache-size 256MB
32: subvolumes testvol-write-behind
33: end-volume
34:
35: volume testvol-quick-read
36: type performance/quick-read
37: option cache-size 256MB
38: subvolumes testvol-io-cache
39: end-volume
40:
41: volume testvol
42: type debug/io-stats
43: option latency-measurement off
44: option count-fop-hits off
45: subvolumes testvol-quick-read
46: end-volume
Server volfile:
+------------------------------------------------------------------------------+
1: volume testvol-posix
2: type storage/posix
3: option directory /data
4: end-volume
5:
6: volume testvol-access-control
7: type features/access-control
8: subvolumes testvol-posix
9: end-volume
10:
11: volume testvol-locks
12: type features/locks
13: subvolumes testvol-access-control
14: end-volume
15:
16: volume testvol-io-threads
17: type performance/io-threads
18: subvolumes testvol-locks
19: end-volume
20:
21: volume testvol-marker
22: type features/marker
23: option volume-uuid bc89684f-569c-48b0-bc67-09bfd30ba253
24: option timestamp-file /etc/glusterd/vols/testvol/marker.tstamp
25: option xtime off
26: option quota off
27: subvolumes testvol-io-threads
28: end-volume
29:
30: volume /data
31: type debug/io-stats
32: option latency-measurement off
33: option count-fop-hits off
34: subvolumes testvol-marker
35: end-volume
36:
37: volume testvol-server
38: type protocol/server
39: option transport-type tcp
40: option auth.addr./data.allow *
41: subvolumes /data
42: end-volume
My benchmark to simulate PHP webapp i/o:
#!/usr/bin/env python
import sys
import os
import time
import optparse
def print_timing(func):
def wrapper(*arg):
t1 = time.time()
res = func(*arg)
t2 = time.time()
print '%-15.15s %6d ms' % (func.func_name, int ( (t2-t1)*1000.0
))
return res
return wrapper
def parse_options():
parser = optparse.OptionParser()
parser.add_option("--path", '-p',
default="/mnt/glusterfs",
help="Base directory for running tests (default:
/mnt/glusterfs)",
)
parser.add_option("--num", '-n', type="int",
default=100,
help="Number of files per test (default: 100)",
)
(options, args) = parser.parse_args()
return options
class FSBench():
def __init__(self,path="/tmp",num=100):
self.path = path
self.num = num
@print_timing
def test_open_read(self):
for filename in self.get_files():
f = open(filename)
data = f.read()
f.close()
def get_files(self):
for i in range(self.num):
filename = self.path + "/test_%03d" % i
yield filename
@print_timing
def test_stat(self):
for filename in self.get_files():
os.stat(filename)
@print_timing
def test_stat_nonexist(self):
for filename in self.get_files():
try:
os.stat(filename+"blkdsflskdf")
except OSError:
pass
@print_timing
def test_write(self):
for filename in self.get_files():
f = open(filename,'w')
f.write('hi there\n')
f.close()
@print_timing
def test_delete(self):
for filename in self.get_files():
os.unlink(filename)
if __name__ == '__main__':
options = parse_options()
bench = FSBench(path=options.path, num=options.num)
bench.test_write()
bench.test_open_read()
bench.test_stat()
bench.test_stat_nonexist()
bench.test_delete()
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://supercolony.gluster.org/pipermail/gluster-users/attachments/20130418/9b8ff478/attachment.html>
Raghavendra Gowdappa
2013-Apr-24 03:31 UTC
[Gluster-users] Low (<0.2ms) latency reads, is it possible at all?
Hi willem, Please find the inlined comments: ----- Original Message -----> From: "Willem" <gwillem at gmail.com> > To: gluster-users at gluster.org > Sent: Thursday, April 18, 2013 11:58:46 PM > Subject: [Gluster-users] Low (<0.2ms) latency reads, is it possible at all? > > I'm testing GlusterFS viability for use with a typical PHP webapp (ie. lots > of small files). I don't care so much for the C in the CAP theorem, as I > have very few writes. I could live with a write propagation delay of 5 > minutes (or dirty caches for up to 5 minutes). > > So I'm optimizing for low latency reads of small files. My testsetup is 2 > node replication. Each node is both server and gluster client. Both are in > sync. I stop glusterfs-server @ node2. @node1, I run a simple benchmark: > repeatedly (to prime the cache) open & close 1000 small files. I have > enabled the client-side io-cache and quick-read translators (see below for > config). > > The results are consistently 2 ms per open (O_RDONLY) call. Which is too > slow, unfortunately, as I need < 0.2ms. > > The same test with a local Gluster server and NFS mount, I get somewhat > better performance but still 0.6ms. > > The same test with Linux NFS server (v3) and local mount, I get 0.12ms per > open. > > I can't explain the lag using Gluster, because I can't see any traffic being > sent to node2. I would expect that using the io-cache translator and > local-only operation, the performance would approach that of the kernel FS > cache. > > Is this assumption correct? If yes, how would I profile the client sub system > to detect the bottleneck? > > If no, then I have to accept that 0.8ms open calls are the best that I could > squeeze out of this system. Then I'll probably look into AFS, userspace > async replication or gluster NFS mount with cachefilesd. Which would you > recommend? > > Thanks a lot! > BTW I like Gluster a lot, and hope that it is also suitable for this small > files use case ;) > > //Willem > > PS Am testing with kernel 3.5.0-17-generic 64bit and gluster 3.2.5-1ubuntu1. > > Client volfile: > +------------------------------------------------------------------------------+ > 1: volume testvol-client-0 > 2: type protocol/client > 3: option remote-host g1 > 4: option remote-subvolume /data > 5: option transport-type tcp > 6: end-volume > 7: > 8: volume testvol-client-1 > 9: type protocol/client > 10: option remote-host g2 > 11: option remote-subvolume /data > 12: option transport-type tcp > 13: end-volume > 14: > 15: volume testvol-replicate-0 > 16: type cluster/replicate > 17: subvolumes testvol-client-0 testvol-client-1 > 18: end-volume > 19: > 20: volume testvol-write-behind > 21: type performance/write-behind > 22: option flush-behind on > 23: subvolumes testvol-replicate-0 > 24: end-volume > 25: > 26: volume testvol-io-cache > 27: type performance/io-cache > 28: option max-file-size 256KB > 29: option cache-timeout 60 > 30: option priority *.php:3,*:0 > 31: option cache-size 256MB > 32: subvolumes testvol-write-behind > 33: end-volume > 34: > 35: volume testvol-quick-read > 36: type performance/quick-readdefault value for option "max-file-size" is 64KB. Seems like your files are bigger than 64KB. Can you add this option and rerun the tests? Also can you rerun the tests by disabling quick-read and compare the results?> 37: option cache-size 256MB > 38: subvolumes testvol-io-cache > 39: end-volume > 40: > 41: volume testvol > 42: type debug/io-stats > 43: option latency-measurement off > 44: option count-fop-hits off > 45: subvolumes testvol-quick-read > 46: end-volume > > Server volfile: > +------------------------------------------------------------------------------+ > 1: volume testvol-posix > 2: type storage/posix > 3: option directory /data > 4: end-volume > 5: > 6: volume testvol-access-control > 7: type features/access-control > 8: subvolumes testvol-posix > 9: end-volume > 10: > 11: volume testvol-locks > 12: type features/locks > 13: subvolumes testvol-access-control > 14: end-volume > 15: > 16: volume testvol-io-threads > 17: type performance/io-threads > 18: subvolumes testvol-locks > 19: end-volume > 20: > 21: volume testvol-marker > 22: type features/marker > 23: option volume-uuid bc89684f-569c-48b0-bc67-09bfd30ba253 > 24: option timestamp-file /etc/glusterd/vols/testvol/marker.tstamp > 25: option xtime off > 26: option quota off > 27: subvolumes testvol-io-threads > 28: end-volume > 29: > 30: volume /data > 31: type debug/io-stats > 32: option latency-measurement off > 33: option count-fop-hits off > 34: subvolumes testvol-marker > 35: end-volume > 36: > 37: volume testvol-server > 38: type protocol/server > 39: option transport-type tcp > 40: option auth.addr./data.allow * > 41: subvolumes /data > 42: end-volume > > My benchmark to simulate PHP webapp i/o: > #!/usr/bin/env python > > import sys > import os > import time > import optparse > > def print_timing(func): > def wrapper(*arg): > t1 = time.time() > res = func(*arg) > t2 = time.time() > print '%-15.15s %6d ms' % (func.func_name, int ( (t2-t1)*1000.0 )) > return res > return wrapper > > > def parse_options(): > parser = optparse.OptionParser() > parser.add_option("--path", '-p', default="/mnt/glusterfs", > help="Base directory for running tests (default: /mnt/glusterfs)", > ) > parser.add_option("--num", '-n', type="int", default=100, > help="Number of files per test (default: 100)", > ) > (options, args) = parser.parse_args() > return options > > class FSBench(): > def __init__(self,path="/tmp",num=100): > self.path = path > self.num = num > @print_timing > def test_open_read(self): > for filename in self.get_files(): > f = open(filename) > data = f.read() > f.close() > def get_files(self): > for i in range(self.num): > filename = self.path + "/test_%03d" % i > yield filename > @print_timing > def test_stat(self): > for filename in self.get_files(): > os.stat(filename) > > @print_timing > def test_stat_nonexist(self): > for filename in self.get_files(): > try: > os.stat(filename+"blkdsflskdf") > except OSError: > pass > @print_timing > def test_write(self): > for filename in self.get_files(): > f = open(filename,'w') > f.write('hi there\n') > f.close() > @print_timing > def test_delete(self): > for filename in self.get_files(): > os.unlink(filename) > if __name__ == '__main__': > > options = parse_options() > bench = FSBench(path=options.path, num=options.num) > bench.test_write() > bench.test_open_read() > bench.test_stat() > bench.test_stat_nonexist() > bench.test_delete() > > > > > _______________________________________________ > Gluster-users mailing list > Gluster-users at gluster.org > http://supercolony.gluster.org/mailman/listinfo/gluster-users
Marcus Bointon
2013-Apr-24 12:18 UTC
[Gluster-users] Low (<0.2ms) latency reads, is it possible at all?
On 24 Apr 2013, at 14:00, "Willem" <gwillem at gmail.com> wrote:>> I'm testing GlusterFS viability for use with a typical PHP webapp (ie. lots >> of small files). I don't care so much for the C in the CAP theorem, as I >> have very few writes. I could live with a write propagation delay of 5 >> minutes (or dirty caches for up to 5 minutes).We know that gluster's small-file performance isn't good, and since you can live with such long write propagation, reciprocal rsync could be a better and simpler solution. That way you'd get much faster local performance. The only issue really is that deletes aren't possible to propagate correctly with 2-way rsync (because a delete at one end is indistinguishable from an add at the other), but you may be able to live with it. csync2 aims to solve the delete issue with a transaction database, but I could never make it work. To get a consistent 0.2ms off anything you're going to need to be on SSDs - you can't fit everything in your cache. Marcus -- Marcus Bointon Synchromedia Limited: Creators of http://www.smartmessages.net/ UK info at hand CRM solutions marcus at synchromedia.co.uk | http://www.synchromedia.co.uk/