From brad@danga.com Thu Aug 7 17:53:30 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Thu, 7 Aug 2003 09:53:30 -0700 (PDT) Subject: summary of misc off-list traffic Message-ID: Uriah Welcome is looking at using memcached for SourceForge.net, so he started working on a Python API, but without multiple servers. Evan (at danga) then ported the Perl one to Python, and he's cleaning it up now. I'll put it up and announce it when it's ready. Somebody asked about porting memcached to Windows, but we don't see the point: paying for a Windows license for each box? Ouch! But, I guess if you're just sticking memcache on existing Windows web nodes, and you're already paying for the license, then it'd work. (that is recommended, btw: take your existing web nodes, add more memory, and also run memcached on them.... memcached takes almost no CPU.) In any case, if you want to run memcached on Windows, port it, then send us patches and we'll integrate them. Avva (works for Danga and wrote most of memcached server) is working on making object expirations happen as soon as possible, instead of falling off the LRU, or being killed on retrieve. Currently it's possible for an object with a lifetime of 30 seconds to live in memory for hours, as long as nobody accesses it. If somebody does access it 31 seconds later, or an hour later, its expiration time is noted and it's then destroyed, and the client gets an empty result, but it was still in memory longer than it needed to be, so it was probably pushing other objects with infinite expiration times off the LRU. So, the early expiration patch will increase hit rates a little. Probably a tiny amount, but it really depends on what you're throwing in memcache. Don't be afraid to use the list. Everybody I've talked to off-list has been smart, friendly, and had good questions/advice. - Brad From martine@danga.com Thu Aug 7 23:04:23 2003 From: martine@danga.com (Evan Martin) Date: Thu, 7 Aug 2003 15:04:23 -0700 Subject: preliminary python memcache client Message-ID: <20030807220423.GA15808@danga.com> --FCuugMFkClbJLl1L Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Attached is a patch against memcached CVS that adds a Python client. It currently lacks some features, but it should provide the basic functionality you'd need to try using memcached with Python. It also lacks docs, but it pretty much follows the Perl API; there's also a simple example included at the end of the module itself ('python memcached.py'). You'll need to be running a memcached process before the test does anything useful. Bug reports / feature requests / enhancements are welcome. Finally, it's been a while since I've used Python, so I'd appreciate stylistic feedback: am I using the proper idioms, am I naming/capitalizing things the way you'd expect, etc. If anyone here is knowledgable about those sorts of things, please respond to me off-list, as I have a lot of questions (like: which of the doc tools should I use?). -- Evan Martin martine@danga.com http://neugierig.org --FCuugMFkClbJLl1L Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="memcached-python.patch" diff -ruN memcache-orig/api/python/ChangeLog memcache-python/api/python/ChangeLog --- memcache-orig/api/python/ChangeLog 1969-12-31 16:00:00.000000000 -0800 +++ memcache-python/api/python/ChangeLog 2003-08-07 14:24:20.000000000 -0700 @@ -0,0 +1,4 @@ +Thu, 07 Aug 2003 14:20:27 -0700 Evan Martin + + * Initial prerelease. + diff -ruN memcache-orig/api/python/MANIFEST memcache-python/api/python/MANIFEST --- memcache-orig/api/python/MANIFEST 1969-12-31 16:00:00.000000000 -0800 +++ memcache-python/api/python/MANIFEST 2003-08-07 14:21:38.000000000 -0700 @@ -0,0 +1,3 @@ +memcache.py +setup.py +ChangeLog diff -ruN memcache-orig/api/python/memcache.py memcache-python/api/python/memcache.py --- memcache-orig/api/python/memcache.py 1969-12-31 16:00:00.000000000 -0800 +++ memcache-python/api/python/memcache.py 2003-08-07 15:02:21.000000000 -0700 @@ -0,0 +1,367 @@ +#!/usr/bin/env python + +"""MemCachedClient: a client for memcached. + +http://www.danga.com/memcached""" + +import sys +import socket +import pickle +import time +import re +import string +import types + +__author__ = "Evan Martin " +__version__ = "1.0" +__copyright__ = "Copyright (C) 2003 Danga Interactive" +__license__ = "Python" + +class Error(Exception): + pass + +class Client: + _valuere = re.compile(r'^VALUE (\S+) (\d+) (\d+)') + _FLAG_PICKLE = 1<<0 + _FLAG_INTEGER = 1<<1 + _FLAG_LONG = 1<<2 + + _SERVER_RETRIES = 10 # how many times to try finding a free server. + + def __init__(self, servers, debug=0): + self.set_servers(servers) + self.debug = debug + self.stats = {} + + def set_servers(self, servers): + self.servers = [Host(s, self.debuglog) for s in servers] + self.init_buckets() + + def debuglog(self, str): + if self.debug: + sys.stderr.write("MemCached: %s\n" % str) + + def statlog(self, func): + if not self.stats.has_key(func): + self.stats[func] = 1 + else: + self.stats[func] += 1 + + def forget_dead_hosts(self): + for s in self.servers: + s.dead_until = 0 + + def init_buckets(self): + self.buckets = [] + for server in self.servers: + for i in range(server.weight): + self.buckets.append(server) + + def get_server(self, key): + if type(key) == types.TupleType: + serverhash = key[0] + key = key[1] + else: + serverhash = hash(key) + + for i in range(Client._SERVER_RETRIES): + server = self.buckets[serverhash % len(self.buckets)] + if server.connect(): + #print "(using server %s)" % server, + return server + serverhash = hash(str(serverhash) + str(i)) + return None + + def disconnect_all(self): + for s in self.servers: + s.close_socket() + + def delete(self, key, time): + # XXX implement me. + pass + + def incr(self, key, time): + # XXX implement me. + pass + + def decr(self, key, time): + # XXX implement me. + pass + + def add(self, key, val, time=0): + '''Add {key: val}, expiring at time.''' + return self._set("add", key, val, time) + def replace(self, key, val, time=0): + '''Replace existing key with {key: val}, expiring at time.''' + return self._set("replace", key, val, time) + def set(self, key, val, time=0): + '''Set {key: val}, expiring at time.''' + return self._set("set", key, val, time) + + def _set(self, cmd, key, val, time): + server = self.get_server(key) + if not server: + return 0 + + self.statlog(cmd) + + flags = 0 + if isinstance(val, types.StringTypes): + pass + elif isinstance(val, int): + flags |= Client._FLAG_INTEGER + val = "%d" % val + elif isinstance(val, long): + flags |= Client._FLAG_LONG + val = "%d" % val + else: + flags |= Client._FLAG_PICKLE + val = pickle.dumps(val, 2) + + fullcmd = "%s %s %d %d %d\r\n%s" % (cmd, key, flags, time, len(val), val) + try: + server.send_cmd(fullcmd) + server.expect("STORED") + except socket.error, msg: + server.mark_dead(msg[1]) + return 0 + return 1 + + def get(self, key): + server = self.get_server(key) + if not server: + return None + + self.statlog('get') + + try: + server.send_cmd("get %s" % key) + rkey, flags, rlen, = self._expectvalue(server) + if not rkey: + return None + value = self._recv_value(server, flags, rlen) + server.expect("END") + except (Error, socket.error), msg: + if type(msg) is types.TupleType: + msg = msg[1] + server.mark_dead(msg) + return None + return value + + def get_multi(self, *keys): + self.statlog('get_multi') + + server_keys = {} + + # build up a list for each server of all the keys we want. + for key in keys: + server = self.get_server(key) + if not server: + continue + if type(key) == types.TupleType: + key = key[1] + if not server_keys.has_key(server): + server_keys[server] = [] + server_keys[server].append(key) + + # send out all requests on each server before reading anything + dead_servers = [] + for server in server_keys.keys(): + try: + server.send_cmd("get %s" % string.join(server_keys[server])) + except socket.error, msg: + server.mark_dead(msg[1]) + dead_servers.append(server) + + # if any servers died on the way, don't expect them to respond. + for server in dead_servers: + del server_keys[server] + + retvals = {} + for server in server_keys.keys(): + try: + line = server.readline() + while line and line != 'END': + rkey, flags, rlen = self._expectvalue(server, line) + val = self._recv_value(server, flags, rlen) + retvals[rkey] = val + line = server.readline() + except (Error, socket.error), msg: + server.mark_dead(msg) + return retvals + + def _expectvalue(self, server, line=None): + if not line: + line = server.readline() + match = self._valuere.match(line) + if not match: + return (None, None, None) + rkey = match.group(1) + flags = int(match.group(2)) + rlen = int(match.group(3)) + return (rkey, flags, rlen) + + def _recv_value(self, server, flags, rlen): + rlen += 2 # include \r\n + buf = server.recv(rlen) + if len(buf) != rlen: + raise Error("received %d bytes when expecting %d" % (len(buf), rlen)) + + if len(buf) == rlen: + buf = buf[:-2] # strip \r\n + + if flags == 0: + val = buf + elif flags & Client._FLAG_INTEGER: + val = int(buf) + elif flags & Client._FLAG_LONG: + val = long(buf) + elif flags & Client._FLAG_PICKLE: + val = pickle.loads(buf) + else: + self.debuglog("unknown flags on get: %x\n" % flags) + + return val + + +class Host: + """A single server in the memcachepool that MemCachedClient chooses from.""" + def __init__(self, host, debugfunc=None): + if isinstance(host, types.TupleType): + host = host[0] + self.weight = host[1] + else: + self.weight = 1 + + if string.find(host, ":") > 0: + self.ip, self.port = string.split(host, ":") + self.port = int(self.port) + else: + self.ip, self.port = host, 11211 + + if not debugfunc: + debugfunc = lambda x: x + self.debuglog = debugfunc + + self.deaduntil = 0 + self.socket = None + + def _check_dead(self): + if self.deaduntil and self.deaduntil > time.time(): + return 1 + self.deaduntil = 0 + return 0 + + def connect(self): + if self._get_socket(): + return 1 + return 0 + + def mark_dead(self, reason): + print "MemCache: %s: %s. Marking dead." % (self, reason) + self.deaduntil = time.time()+5 #XXX magic + self.close_socket() + + def _get_socket(self): + if self._check_dead(): + return None + if self.socket: + return self.socket + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + #s.settimeout(1) # XXX magic number + try: + s.connect((self.ip, self.port)) + except socket.error, msg: + self.mark_dead("connect: %s" % msg[1]) + return None + self.socket = s + return s + + def close_socket(self): + if self.socket: + self.socket.close() + self.socket = None + + def send_cmd(self, cmd): + self.socket.sendall(cmd + "\r\n") + + def readline(self): + newlines = 0 + buf = '' + while newlines < 2: + char = self.socket.recv(1) # XXX does this buffer or is this slow? + if len(char) == 0: + # connection closed. + print "MemCache: Connection closed while reading from %s. Marking dead." % self + self.mark_dead + return buf + if char == '\r' and newlines == 0: + newlines = 1 + elif char == '\n' and newlines == 1: + newlines = 2 + else: + newlines = 0 + buf = buf + char + return buf + + def expect(self, text): + line = self.readline() + if line != text: + self.debuglog("while expecting '%s', got unexpected response '%s'" % (text, line)) + return line + + def recv(self, rlen): + buf = '' + while len(buf) < rlen: + buf = buf + self.socket.recv(rlen - len(buf)) + return buf + + def __str__(self): + d = '' + if self.deaduntil: + d = " (dead until %d)" % self.deaduntil + return "%s:%d%s" % (self.ip, self.port, d) + +if __name__ == "__main__": + print "Running tests:" + print + #servers = ["127.0.0.1:11211", "127.0.0.1:11212"] + servers = ["127.0.0.1:11211"] + mc = Client(servers, debug=1) + + def to_s(val): + if not isinstance(val, types.StringTypes): + return "%s (%s)" % (val, type(val)) + return "%s" % val + def test_setget(key, val): + print "Testing set/get {'%s': %s} ..." % (to_s(key), to_s(val)), + mc.set(key, val) + newval = mc.get(key) + if newval == val: + print "OK" + else: + print "FAIL" + + class FooStruct: + def __init__(self): + self.bar = "baz" + def __str__(self): + return "A FooStruct" + def __eq__(self, other): + if isinstance(other, FooStruct): + return self.bar == other.bar + return 0 + + test_setget("a_string", "some random string") + test_setget("an_integer", 42) + print "Testing get_multi ...", + print mc.get_multi("a_string", "an_integer") + test_setget("long", long(1<<30)) + + print "Testing get(unknown value) ...", + print to_s(mc.get("unknown_value")) + + f = FooStruct() + test_setget("foostruct", f) + +# vim: ts=4 sw=4 et : diff -ruN memcache-orig/api/python/setup.py memcache-python/api/python/setup.py --- memcache-orig/api/python/setup.py 1969-12-31 16:00:00.000000000 -0800 +++ memcache-python/api/python/setup.py 2003-08-07 15:02:34.000000000 -0700 @@ -0,0 +1,12 @@ +#!/usr/bin/env python + +from distutils.core import setup +import memcache + +setup(name="memcache", + version=memcache.__version__, + author="Evan Martin", + author_email="martine@danga.com", + url="http://www.danga.com/memcached", + py_modules=["memcache"]) + diff -ruN memcache-orig/api/python/tests/pooltest.py memcache-python/api/python/tests/pooltest.py --- memcache-orig/api/python/tests/pooltest.py 1969-12-31 16:00:00.000000000 -0800 +++ memcache-python/api/python/tests/pooltest.py 2003-08-07 14:26:38.000000000 -0700 @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +"""pooltest + +Bring up two memcaches on :11211 and :11212. Try killing one or both. +If this code raises any exceptions, it's a bug.""" + +import memcache +import time + +mc = memcache.Client(["127.0.0.1:11211", "127.0.0.1:11212"], debug=1) + +def test_setget(key, val): + print "Testing set/get {'%s': %s} ..." % (key, val), + mc.set(key, val) + newval = mc.get(key) + if newval == val: + print "OK" + else: + print "FAIL" + +i = 0 +while 1: + test_setget("foo%d" % i, "bar%d" % i) + time.sleep(1) + i += 1 diff -ruN memcache-orig/CONTRIBUTORS memcache-python/CONTRIBUTORS --- memcache-orig/CONTRIBUTORS 2003-07-28 01:40:02.000000000 -0700 +++ memcache-python/CONTRIBUTORS 2003-08-07 15:02:10.000000000 -0700 @@ -10,8 +10,9 @@ -- C server -- memory allocator design -Evan Martine +Evan Martin -- automake/autoconf support + -- Python client Ryan -- PHP client --FCuugMFkClbJLl1L-- From martine@danga.com Fri Aug 8 03:23:21 2003 From: martine@danga.com (Evan Martin) Date: Thu, 7 Aug 2003 19:23:21 -0700 Subject: python api, try two Message-ID: <20030808022321.GC17601@danga.com> --4Ckj6UjgE2iN1+kY Content-Type: text/plain; charset=us-ascii Content-Disposition: inline This is 1.1. * Add incr, decr, and delete. * Better Python (based on comments from Uriah Welcome). * Docs, using epydoc. Hopefully it's ready for CVS now. -- Evan Martin martine@danga.com http://neugierig.org --4Ckj6UjgE2iN1+kY Content-Type: application/octet-stream Content-Disposition: attachment; filename="python-memcache-1.1.tar.gz" Content-Transfer-Encoding: base64 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 1/baXttre22v7bW9ttf2+je//g8J8zllAHgAAA== --4Ckj6UjgE2iN1+kY-- From lisa@gentoo.org Fri Aug 8 03:29:30 2003 From: lisa@gentoo.org (Lisa Marie Seelye) Date: 07 Aug 2003 22:29:30 -0400 Subject: python api, try two In-Reply-To: <20030808022321.GC17601@danga.com> References: <20030808022321.GC17601@danga.com> Message-ID: <1060309770.1765.17.camel@lisa.thedoh.com> --=-rvyOkoDBbwMoPSqYkVcx Content-Type: text/plain Content-Transfer-Encoding: quoted-printable On Thu, 2003-08-07 at 22:23, Evan Martin wrote: > This is 1.1. > * Add incr, decr, and delete. > * Better Python (based on comments from Uriah Welcome). > * Docs, using epydoc. >=20 > Hopefully it's ready for CVS now. When this makes it to the API download page it'll be available for Gentoo users. Thanks for your hard work, Evan! --=20 Regards, -Lisa --=-rvyOkoDBbwMoPSqYkVcx Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQA/MwsKy0a1Vh5Jb8URAq7YAKCADwJoCQ1w3sawkIWY836OMsQ2ugCgnpa7 h9NQZH/VKAKspaSJ2qgHM5I= =AF// -----END PGP SIGNATURE----- --=-rvyOkoDBbwMoPSqYkVcx-- From brad@danga.com Fri Aug 8 08:39:38 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Fri, 8 Aug 2003 00:39:38 -0700 (PDT) Subject: memcached in freebsd Message-ID: I noticed FreeBSD has a number of patches to memcached in their ports tree. I'm wondering if we shouldn't try and get those autoconfed into the main tree, to make it easier on the other BSDs? (I'm so not the person to do that, though, so this is more of a cry for help...) - Brad From brad@danga.com Fri Aug 8 19:44:28 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Fri, 8 Aug 2003 11:44:28 -0700 (PDT) Subject: memcached in freebsd In-Reply-To: References: Message-ID: BTW, those files are at: http://www.freebsd.org/cgi/cvsweb.cgi/ports/databases/memcached/files/ Anybody have access to both Linux and FreeBSD and knows autoconf? I guess we can't do mallinfo on FreeBSD, and their mlockall support isn't totally done yet. (Oddly, somebody I read on LiveJournal has been working on mlockall support for FreeBSD....) On Fri, 8 Aug 2003, Brad Fitzpatrick wrote: > I noticed FreeBSD has a number of patches to memcached in their ports > tree. > > I'm wondering if we shouldn't try and get those autoconfed into the main > tree, to make it easier on the other BSDs? > > (I'm so not the person to do that, though, so this is more of a cry for > help...) > > - Brad > > > From brad@danga.com Fri Aug 8 20:06:02 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Fri, 8 Aug 2003 12:06:02 -0700 (PDT) Subject: gentoo roadmap Message-ID: Thoughts on the Gentoo memcached roadmap[1]: * The APIs shouldn't RDEPEND on memcached. In LiveJournal's case, our memcached machines are on totally separate hosts from our web nodes. * I'd like the init/conf scripts included in memcached. It's not so much that I'm lazy, but I'm not sure the correct way to do it. I'd just write it in Perl, but probably wouldn't fly with most people. However it is, we need to support multiple processes in the conf file. For instance, we have a 12 GB machine where we run 5x2 GB processes, leaving 2 GB on the machine for other stuff. Because it's a 32 bit machine, we can't just run 1 10 GB process. Anybody using memcached seriously is going to want these same sorts of configs. - Brad [1] http://dev.gentoo.org/~lisa/memcached/roadmap.txt From lisa@gentoo.org Fri Aug 8 20:19:05 2003 From: lisa@gentoo.org (Lisa Marie Seelye) Date: 08 Aug 2003 15:19:05 -0400 Subject: gentoo roadmap In-Reply-To: References: Message-ID: <1060370345.1765.30.camel@lisa.thedoh.com> --=-6+RYBuef5Bc2zLIunR0B Content-Type: text/plain Content-Transfer-Encoding: quoted-printable On Fri, 2003-08-08 at 15:06, Brad Fitzpatrick wrote: > Thoughts on the Gentoo memcached roadmap[1]: >=20 > * The APIs shouldn't RDEPEND on memcached. In LiveJournal's case, our > memcached machines are on totally separate hosts from our web nodes. I had debated this with myself before I put the ebuilds in. I came to the conclusion that memcached is not a large package, and it compiles very quickly. It isn't too much of a big deal; I'll remove the depends. > * I'd like the init/conf scripts included in memcached. It's not so much > that I'm lazy, but I'm not sure the correct way to do it. I'd just > write it in Perl, but probably wouldn't fly with most people. The init scripts are in the image of Bash, so we can't use Perl. > However it is, we need to support multiple processes in the conf file. > For instance, we have a 12 GB machine where we run 5x2 GB processes, > leaving 2 GB on the machine for other stuff. Because it's a 32 bit > machine, we can't just run 1 10 GB process. This seems like a candidate for program enhancement: memcached -d --servers 5 --mem 2048 =3D 5 servers at 2048MB each. Mainly because I don't particularly relish the job of modifying the init script. ;-) I'll see what I can do... --=20 Regards, -Lisa --=-6+RYBuef5Bc2zLIunR0B Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQA/M/epy0a1Vh5Jb8URAr5MAKCuMOHw/JV2KY0BrUe36PVkhw+TZgCeNT4y 9SsEkOMbuLtK/uipgO8Rgpo= =QKCP -----END PGP SIGNATURE----- --=-6+RYBuef5Bc2zLIunR0B-- From brad@danga.com Fri Aug 8 20:38:14 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Fri, 8 Aug 2003 12:38:14 -0700 (PDT) Subject: gentoo roadmap In-Reply-To: <1060370345.1765.30.camel@lisa.thedoh.com> References: <1060370345.1765.30.camel@lisa.thedoh.com> Message-ID: Also, how do you handle libevent? Do you build libevent with epoll, even if the kernel doesn't support it? Because libevent selects poll/select/epoll/kqueue at runtime, it's best to build the most powerful libevent as possible, so users can upgrade their kernel later. In my experience, building the kernel with epoll is way easier than fixing all the userspace headers. How does Gentoo handle all that? Is epoll* syscalls in the glibc headers you guys distribute? (note to others: memcached runs fine with poll/select. you don't need to rebuild your kernel. but it's pretty cool if you do.) On Fri, 8 Aug 2003, Lisa Marie Seelye wrote: > On Fri, 2003-08-08 at 15:06, Brad Fitzpatrick wrote: > > Thoughts on the Gentoo memcached roadmap[1]: > > > > * The APIs shouldn't RDEPEND on memcached. In LiveJournal's case, our > > memcached machines are on totally separate hosts from our web nodes. > > I had debated this with myself before I put the ebuilds in. I came to > the conclusion that memcached is not a large package, and it compiles > very quickly. > > It isn't too much of a big deal; I'll remove the depends. > > > * I'd like the init/conf scripts included in memcached. It's not so much > > that I'm lazy, but I'm not sure the correct way to do it. I'd just > > write it in Perl, but probably wouldn't fly with most people. > > The init scripts are in the image of Bash, so we can't use Perl. > > > > However it is, we need to support multiple processes in the conf file. > > For instance, we have a 12 GB machine where we run 5x2 GB processes, > > leaving 2 GB on the machine for other stuff. Because it's a 32 bit > > machine, we can't just run 1 10 GB process. > > This seems like a candidate for program enhancement: > > memcached -d --servers 5 --mem 2048 = 5 servers at 2048MB each. > > Mainly because I don't particularly relish the job of modifying the init > script. ;-) I'll see what I can do... > > > -- > Regards, > -Lisa > > From brad@danga.com Fri Aug 8 20:42:37 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Fri, 8 Aug 2003 12:42:37 -0700 (PDT) Subject: gentoo roadmap In-Reply-To: <1060370345.1765.30.camel@lisa.thedoh.com> References: <1060370345.1765.30.camel@lisa.thedoh.com> Message-ID: On Fri, 8 Aug 2003, Lisa Marie Seelye wrote: > > However it is, we need to support multiple processes in the conf file. > > For instance, we have a 12 GB machine where we run 5x2 GB processes, > > leaving 2 GB on the machine for other stuff. Because it's a 32 bit > > machine, we can't just run 1 10 GB process. > > This seems like a candidate for program enhancement: > > memcached -d --servers 5 --mem 2048 = 5 servers at 2048MB each. > > Mainly because I don't particularly relish the job of modifying the init > script. ;-) I'll see what I can do... The problem is, when you have a huge memcached farm, and you want to upgrade to a new version of memcached, you don't want to stop/start everything at once... you want to do one process at a time. Having them all parent/child off each other makes it really hard. Plus, our goal is to write in C as little as possible. No config parsing, etc. My goal was always to write a Perl wrapper to control them. Couldn't we just make memcached depend on Perl? Then the init scripts could just do stop-start-daemons on the wrapper? - Brad From lisa@gentoo.org Fri Aug 8 20:57:03 2003 From: lisa@gentoo.org (Lisa Marie Seelye) Date: 08 Aug 2003 15:57:03 -0400 Subject: gentoo roadmap In-Reply-To: References: <1060370345.1765.30.camel@lisa.thedoh.com> Message-ID: <1060372622.1762.42.camel@lisa.thedoh.com> --=-tikSy7YwScZQeS7bgW4U Content-Type: text/plain Content-Transfer-Encoding: quoted-printable On Fri, 2003-08-08 at 15:42, Brad Fitzpatrick wrote: > The problem is, when you have a huge memcached farm, and you want to > upgrade to a new version of memcached, you don't want to stop/start > everything at once... you want to do one process at a time. Having them > all parent/child off each other makes it really hard. >=20 > Plus, our goal is to write in C as little as possible. No config > parsing, etc. My goal was always to write a Perl wrapper to control them= . >=20 > Couldn't we just make memcached depend on Perl? Then the init scripts > could just do stop-start-daemons on the wrapper? That sounds like the best way to go -- a Perl wrapper to launch and terminate multiple instances of the memcache daemon. (Even with each instance having separate configurations... handy!) A Perl wrapper would still be called with start-stop-daemon, but would allow for a lot more control and flexibility. I'll respond to your other email here, too, so as to not keep two threads going. To the best of my knowledge the epoll kernel patch is not included with any Gentoo kernels (Not gentoo-sources, for certain). I've submitted a request to one of our Kernel guys (Bug #25671 @ bugs.gentoo.org) but I don't know when this will be handled. So libevent is built as it would normally be when /dev/epoll was not present. I'd assume that since epoll isn't included with the kernel that glibc isn't made "aware" of it (headers). After things settle down from LWE I'll ask around a bit. --=20 Regards, -Lisa --=-tikSy7YwScZQeS7bgW4U Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQA/NACOy0a1Vh5Jb8URAp2DAJ4jfeGTivvDHCqJxvG4i6CSvkf/LgCfQcAg z476bhuiAzFnmRfY+kgUX84= =sZ/q -----END PGP SIGNATURE----- --=-tikSy7YwScZQeS7bgW4U-- From brad@danga.com Fri Aug 8 22:12:24 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Fri, 8 Aug 2003 14:12:24 -0700 (PDT) Subject: gentoo roadmap In-Reply-To: <1060372622.1762.42.camel@lisa.thedoh.com> References: <1060370345.1765.30.camel@lisa.thedoh.com> <1060372622.1762.42.camel@lisa.thedoh.com> Message-ID: > That sounds like the best way to go -- a Perl wrapper to launch and > terminate multiple instances of the memcache daemon. (Even with each > instance having separate configurations... handy!) > > A Perl wrapper would still be called with start-stop-daemon, but would > allow for a lot more control and flexibility. I'll work on that, then. > I'll respond to your other email here, too, so as to not keep two > threads going. > > To the best of my knowledge the epoll kernel patch is not included with > any Gentoo kernels (Not gentoo-sources, for certain). I've submitted a > request to one of our Kernel guys (Bug #25671 @ bugs.gentoo.org) but I > don't know when this will be handled. /dev/epoll is the 'old' way. The new way that Linus approved (which went in 2.5) is the system call. I'm not sure if libevent supports /dev/epoll. On their website they say support for /dev/poll is planned, which is the Solaris equivalent of /dev/epoll? > So libevent is built as it would normally be when /dev/epoll was not > present. I'd assume that since epoll isn't included with the kernel > that glibc isn't made "aware" of it (headers). After things settle down > from LWE I'll ask around a bit. In any case, the headers should be updated in Gentoo for the new system call numbers, so programs like libevent can build with all their functionality, even if the current running kernel doesn't support it. BTW, to test if memcached (rather, libevent) is using epoll: # EVENT_SHOW_METHOD=1 memcached From brad@danga.com Fri Aug 8 23:38:57 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Fri, 8 Aug 2003 15:38:57 -0700 (PDT) Subject: Python API release Message-ID: Python supports joins Perl and PHP, thanks to Evan: http://www.danga.com/memcached/apis.bml SourceForge people: let us know if you have any questions/problems with it. - Brad From brad@danga.com Fri Aug 8 23:44:12 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Fri, 8 Aug 2003 15:44:12 -0700 (PDT) Subject: Everything2 and memcached Message-ID: Jay gave me permission to repost this conversation here. Looks like the Everything2.com people will be adding memcache support, because all their web processes are full of cached data that isn't shared. (the first limit people hit... then you do IPC::Shareable or something, and hit per-machine limits...) Anyway, good to see more people using it. I haven't heard from most people on this list about why they're using it, though. Current users seem to include: LiveJournal (main user) Slashdot (using it for 15 GB+ of comments, adding more) SourceForge (starting to work on it? (python support)) Everything (starting to work on it) I'm not sure why it's in FreeBSD or Gentoo. Who's using it there? - Brad ---------- Forwarded message ---------- Date: 08 Aug 2003 14:35:37 -0400 From: Jay Bonci To: Brad Fitzpatrick Subject: Re: memcached and custom kernels Right now we cache pre-made objects into webserver proc memory (use vars $foo sorta stuff). It's not pretty and makes it memory intensive for us. Memcached is a way for us to cut down our memory footprint, and distribute some of the object hell going forward. I'll let you know when we have that all subclassed in and stable =) Thanks --jay On Fri, 2003-08-08 at 14:30, Brad Fitzpatrick wrote: > Let me know when you do and I'll add you guys to our as-of-yet-unmade > "Users Page". > > If you're having any database problems now, I can't recommend memcached > enough. It was a night & day difference for us. We hated blocking so > much, that memcached itself never blocks for anything. > > - Brad > > > On Fri, 8 Aug 2003, Jay Bonci wrote: > > > Thanks for getting back to me. Looks like we'll be putting in memcached > > support for ecore's nodecache, as it makes a lot of sense (when I get > > the free time). > > > > Slashdot's using it now, so hey, good enough for them... ;) > > > > Thanks again, > > > > > > --jay > > > > On Fri, 2003-08-08 at 03:58, Brad Fitzpatrick wrote: > > > Accidentally ran across an old mailing list post of yours. > > > > > > Just mailing you to let you know you don't need a custom whiz-bang kernel > > > to run memcached. Memcache only depends on libevent, which selects > > > between select, poll, kqueue, and epoll at run time. Linux 2.5 supports > > > epoll. There are patches to make 2.4 do it, which we use. > > > > > > There's also a patch to libevent (going in after 0.7a?) that adds realtime > > > signal support, wihch 2.4 supports, and is almost as fast as epoll. > > > > > > But the point is: memcached itself will run with anything. select/poll > > > suck a little, but they're perfectly acceptable. But if you want to > > > use hardly any CPU, definitely go the epoll route. (or kqueue on FreeBSD) > > > > > > - Brad > > From brad@danga.com Sat Aug 9 00:52:08 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Fri, 8 Aug 2003 16:52:08 -0700 (PDT) Subject: website updates Message-ID: I added a note about memcached vs. shared memory, after recently reading somebody on a mailing list debating between the two: http://www.danga.com/memcached/ And also a users page: http://www.danga.com/memcached/users.bml If you're on the users page and hate your description or want to be removed, let me know. Also, if you're not on there and use memcached, let me know. I want to link the CVS browse page for the CONTRIBUTORS file, but I can't decide where to link it from. Suggestions? - Brad From martine@danga.com Sat Aug 9 01:48:23 2003 From: martine@danga.com (Evan Martin) Date: 08 Aug 2003 17:48:23 -0700 Subject: gentoo roadmap In-Reply-To: References: <1060370345.1765.30.camel@lisa.thedoh.com> Message-ID: <1060390103.14780.34.camel@trout> On Fri, 2003-08-08 at 12:42, Brad Fitzpatrick wrote: > Plus, our goal is to write in C as little as possible. No config > parsing, etc. My goal was always to write a Perl wrapper to control them. > > Couldn't we just make memcached depend on Perl? Then the init scripts > could just do stop-start-daemons on the wrapper? It would seem natural to write them in as shell scripts. Then, there's no dependencies at all. Or am I missing something? -- Evan Martin martine@danga.com http://neugierig.org From brad@danga.com Sat Aug 9 01:55:47 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Fri, 8 Aug 2003 17:55:47 -0700 (PDT) Subject: gentoo roadmap In-Reply-To: <1060390103.14780.34.camel@trout> References: <1060370345.1765.30.camel@lisa.thedoh.com> <1060390103.14780.34.camel@trout> Message-ID: I don't do bash-foo. I prefer the pain of perl. It's accustomed pain. On Fri, 8 Aug 2003, Evan Martin wrote: > On Fri, 2003-08-08 at 12:42, Brad Fitzpatrick wrote: > > Plus, our goal is to write in C as little as possible. No config > > parsing, etc. My goal was always to write a Perl wrapper to control them. > > > > Couldn't we just make memcached depend on Perl? Then the init scripts > > could just do stop-start-daemons on the wrapper? > > It would seem natural to write them in as shell scripts. Then, there's > no dependencies at all. > > Or am I missing something? > > -- > Evan Martin > martine@danga.com > http://neugierig.org > > From ryan@gilfether.com Sat Aug 9 18:08:13 2003 From: ryan@gilfether.com (Ryan Gilfether) Date: Sat, 09 Aug 2003 13:08:13 -0400 Subject: PHP API 1.0.7 Message-ID: <3F352A7D.9090306@gilfether.com> A new version of the PHP API has been completed, verson 1.0.7. I've had some requests for adding PHPDocs style comments to the API. Along with that 3 new function have been added error() - returns an error code for the last error genterated error_string() - returns a string with a description of the error error_clear() - clears the last error Ryan -- Ryan Gilfether Software Engineer http://www.gilfether.com From brion@pobox.com Sun Aug 10 07:49:47 2003 From: brion@pobox.com (Brion Vibber) Date: Sat, 09 Aug 2003 23:49:47 -0700 Subject: PHP API 1.0.7 In-Reply-To: <3F352A7D.9090306@gilfether.com> References: <3F352A7D.9090306@gilfether.com> Message-ID: <3F35EB0B.7010506@pobox.com> This is a multi-part message in MIME format. --------------060402060905030606060808 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Ryan Gilfether wrote: > A new version of the PHP API has been completed, verson 1.0.7. Cool! Where can I find it? I'm doing some preliminary work on getting memcached support into Wikipedia (or rather MediaWiki, as we've recently redubbed the software thereof), so far I've started with the 1.0.6 PHP client. > Along with that 3 new function have been added > error() - returns an error code for the last error genterated > error_string() - returns a string with a description of the error > error_clear() - clears the last error On a related note, the debug mode doesn't mix well with MediaWiki's output model. I replaced all the "print"s with calls to a _debug() private function which can I can then override in a subclass to dump things to our debug log; diff for 1.0.6 attached. -- brion vibber (brion @ pobox.com) --------------060402060905030606060808 Content-Type: text/plain; name="php-memc-debug.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="php-memc-debug.diff" --- /home/brion/src/php-memcached-1.0.6/MemCachedClient.inc.php Mon Jul 28 19:04:24 2003 +++ MemCachedClient.inc.php Sat Aug 9 23:35:19 2003 @@ -74,7 +74,7 @@ if(!$this->active) { if($this->debug) - print "delete(): There are no active servers available\r\n"; + $this->_debug("delete(): There are no active servers available"); return FALSE; } @@ -104,7 +104,7 @@ if($this->debug) { $errno = socket_last_error($sock); - print "_delete(): socket_write() returned FALSE. Error $errno: ".socket_strerror($errno)."\r\n"; + $this->_debug("_delete(): socket_write() returned FALSE. Error $errno: ".socket_strerror($errno)); } return FALSE; @@ -117,7 +117,7 @@ if($this->debug) { $errno = socket_last_error($sock); - print "_delete(): socket_read() returned FALSE. Error $errno: ".socket_strerror($errno)."\r\n"; + $this->_debug("_delete(): socket_read() returned FALSE. Error $errno: ".socket_strerror($errno)); } return FALSE; @@ -131,7 +131,7 @@ return TRUE; if($this->debug) - print "_delete(): Failed to receive DELETED response from server. Received $retval instead.\r\n"; + $this->_debug("_delete(): Failed to receive DELETED response from server. Received $retval instead."); return FALSE; } @@ -220,7 +220,7 @@ if($this->debug) { while(list($k, $v) = each($val)) - print "MemCache: got $k = $v\n"; + $this->_debug("MemCache: got $k = $v"); } return $val; @@ -263,7 +263,7 @@ if(count($conn) != 2) { if($this->debug) - print "sock_to_host(): Host address was not in the format of host:port\r\n"; + $this->_debug("sock_to_host(): Host address was not in the format of host:port"); return FALSE; } @@ -272,7 +272,7 @@ ($this->host_dead[$conn[0]] && $this->host_dead[$conn[0]] > $now)) { if($this->debug) - print "sock_to_host(): The host $host is not available.\r\n"; + $this->_debug("sock_to_host(): The host $host is not available."); return FALSE; } @@ -286,7 +286,7 @@ $this->host_dead[$host]=$this->host_dead[$conn[0]]=$now+60+intval(rand(0, 10)); if($this->debug) - print "sock_to_host(): Failed to connect to ".$conn[0].":".$conn[1]."\r\n"; + $this->_debug("sock_to_host(): Failed to connect to ".$conn[0].":".$conn[1]); return FALSE; } @@ -304,7 +304,7 @@ if(!$this->active) { if($this->debug) - print "get_sock(): There are no active servers available\r\n"; + $this->_debug("get_sock(): There are no active servers available"); return FALSE; } @@ -344,7 +344,7 @@ } if($this->debug) - print "get_sock(): get_sock(): Unable to retrieve a valid socket\r\n"; + $this->_debug("get_sock(): get_sock(): Unable to retrieve a valid socket"); return FALSE; } @@ -359,7 +359,7 @@ if(!$this->active) { if($this->debug) - print "_incrdecr(): There are no active servers available\r\n"; + $this->_debug("_incrdecr(): There are no active servers available"); return FALSE; } @@ -368,7 +368,7 @@ if(!is_resource($sock)) { if($this->debug) - print "_incrdecr(): Invalid socket returned by get_sock()\r\n"; + $this->_debug("_incrdecr(): Invalid socket returned by get_sock()"); return FALSE; } @@ -394,7 +394,7 @@ if($this->debug) { $errno = socket_last_error($sock); - print "_incrdecr(): socket_write() returned FALSE. Error $errno: ".socket_strerror($errno)."\r\n"; + $this->_debug("_incrdecr(): socket_write() returned FALSE. Error $errno: ".socket_strerror($errno)); } return FALSE; @@ -405,7 +405,7 @@ if(($retval = socket_read($sock, MC_BUFFER_SZ, PHP_NORMAL_READ)) === FALSE) { $errno = socket_last_error($sock); - print "_incrdecr(): socket_read() returned FALSE. Error $errno: ".socket_strerror($errno)."\r\n"; + $this->_debug("_incrdecr(): socket_read() returned FALSE. Error $errno: ".socket_strerror($errno)); } // strip the /r/n from the end @@ -424,7 +424,7 @@ if(!$this->active) { if($this->debug) - print "_set(): There are no active servers available\r\n"; + $this->_debug("_set(): There are no active servers available"); return FALSE; } @@ -433,7 +433,7 @@ if(!is_resource($sock)) { if($this->debug) - print "_set(): Invalid socket returned by get_sock()\r\n"; + $this->_debug("_set(): Invalid socket returned by get_sock()"); return FALSE; } @@ -472,7 +472,7 @@ if($this->debug) { $errno = socket_last_error($sock); - print "_set(): socket_write() returned FALSE. Error $errno: ".socket_strerror($errno)."\r\n"; + $this->_debug("_set(): socket_write() returned FALSE. Error $errno: ".socket_strerror($errno)); } return FALSE; @@ -485,7 +485,7 @@ if($this->debug) { $errno = socket_last_error($sock); - print "_set(): socket_read() returned FALSE. Error $errno: ".socket_strerror($errno)."\r\n"; + $this->_debug("_set(): socket_read() returned FALSE. Error $errno: ".socket_strerror($errno)); } return FALSE; @@ -494,13 +494,13 @@ if($l_szResponse == "STORED") { if($this->debug) - print "MemCache: $cmdname $key = $raw_val\n"; + $this->_debug("MemCache: $cmdname $key = $raw_val"); return TRUE; } if($this->debug) - print "_set(): Did not receive STORED as the server response! Received $l_szResponse instead\r\n"; + $this->_debug("_set(): Did not receive STORED as the server response! Received $l_szResponse instead"); return FALSE; } @@ -536,7 +536,7 @@ if($this->debug) { $errno = socket_last_error($sock); - print "_load_items(): socket_write() returned FALSE. Error $errno: ".socket_strerror($errno)."\r\n"; + $this->_debug("_load_items(): socket_write() returned FALSE. Error $errno: ".socket_strerror($errno)); } return FALSE; @@ -556,7 +556,7 @@ if($this->debug) { $errno = socket_last_error($sock); - print "_load_items(): socket_read() returned FALSE. Error $errno: ".socket_strerror($errno)."\r\n"; + $this->_debug("_load_items(): socket_read() returned FALSE. Error $errno: ".socket_strerror($errno)); } return FALSE; @@ -584,7 +584,7 @@ { // something went wrong, we never recieved the header if($this->debug) - print "_load_items(): Failed to recieve valid header!\r\n"; + $this->_debug("_load_items(): Failed to recieve valid header!"); return FALSE; } @@ -625,7 +625,7 @@ else { if($this->debug) - print "_load_items(): Failed to receive END. Received $end instead.\r\n"; + $this->_debug("_load_items(): Failed to receive END. Received $end instead."); return FALSE; } @@ -635,7 +635,7 @@ if($bytes_read > ($len + 7)) { if($this->debug) - print "_load_items(): Bytes read is greater than requested data size!\r\n"; + $this->_debug("_load_items(): Bytes read is greater than requested data size!"); return FALSE; } @@ -656,6 +656,10 @@ return $hash; } + + function _debug($text) { + print $text . "\r\n"; + } } /* @@ -672,12 +676,3 @@ * http://www.gilfether.com */ ?> - - - - - - - - - --------------060402060905030606060808-- From brion@pobox.com Sun Aug 10 08:17:24 2003 From: brion@pobox.com (Brion Vibber) Date: Sun, 10 Aug 2003 00:17:24 -0700 Subject: memcached in freebsd Message-ID: <3F35F184.7050205@pobox.com> *Brad Fitzpatrick wrote:* >BTW, those files are at: > >http://www.freebsd.org/cgi/cvsweb.cgi/ports/databases/memcached/files/ > >Anybody have access to both Linux and FreeBSD and knows autoconf? > > Well, I happen to have both Linux and FreeBSD boxen that I'm testing on, but I'm no autoconf guru. On my FreeBSD 5.1 box I managed to install the above-linked port of memcached 1.1.6. It compiles, installs, and runs, and seems to be willing to _store_ items, but when I try to _retrieve_ something it fails: _load_items(): Failed to recieve valid header! I haven't gotten 1.1.8 to compile on FreeBSD yet. 1.1.8 running on my Linux box (Red Hat 8.0) both stores and retrieves, which is good. :) I'm using the 1.0.6 PHP client on the FreeBSD box, with PHP 4.3.2. Is there any way to get memcached to print out some info on what it's doing? I thought I'd put it into verbose mode ("memcached -v -p 11000") but it's eerily silent, printing neither error nor success messages. -- brion vibber (brion @ pobox.com) From martine@danga.com Sun Aug 10 09:44:45 2003 From: martine@danga.com (Evan Martin) Date: Sun, 10 Aug 2003 01:44:45 -0700 Subject: memcached in freebsd In-Reply-To: <3F35F184.7050205@pobox.com> Message-ID: On Sunday, August 10, 2003, at 12:17 AM, Brion Vibber wrote: > On my FreeBSD 5.1 box I managed to install the above-linked port of > memcached 1.1.6. It compiles, installs, and runs, and seems to be > willing to _store_ items, but when I try to _retrieve_ something it > fails: > > _load_items(): Failed to recieve valid header! The memcache protocol works over telnet, which is nice for debugging. Try something like: % telnet my.host 11211 after connecting, type: set test 0 0 5 hello and you should get STORED back. then try get test and see if you get "hello" back. From brion@pobox.com Sun Aug 10 10:42:38 2003 From: brion@pobox.com (Brion Vibber) Date: Sun, 10 Aug 2003 02:42:38 -0700 Subject: memcached in freebsd In-Reply-To: References: Message-ID: <3F36138E.50503@pobox.com> Evan Martin wrote: > On Sunday, August 10, 2003, at 12:17 AM, Brion Vibber wrote: > >> On my FreeBSD 5.1 box I managed to install the above-linked port of >> memcached 1.1.6. It compiles, installs, and runs, and seems to be >> willing to _store_ items, but when I try to _retrieve_ something it >> fails: >> >> _load_items(): Failed to recieve valid header! > > > The memcache protocol works over telnet, which is nice for debugging. > Try something like: On further investigation, I note two things: a) The "_load_items(): Failed to recieve valid header!" is what I get anytime I ask for data that isn't available, and seems to be normal. b) It _does_ retrieve data back from the BSD box if I don't set an expiration time when doing sets/adds. I had been using an expiration time of 3600, which should be one hour if I'm reading the docs right. ... D'oh! Looks like relative expiration times are a new feature of 1.1.7/1.1.8, and 1.1.6 expects either 0 or a full Unix timestamp. Okay, if I set it to 3600 + time(), then it gives me my data back from both boxen. Hoo-rah... at least it seems to be working on FreeBSD, it's just a version behind. :) -- brion vibber (brion @ pobox.com) From mellon@pobox.com Sun Aug 10 14:11:20 2003 From: mellon@pobox.com (Anatoly Vorobey) Date: Sun, 10 Aug 2003 13:11:20 +0000 Subject: memcached in freebsd In-Reply-To: <3F36138E.50503@pobox.com> References: <3F36138E.50503@pobox.com> Message-ID: <20030810131120.GA30897@pobox.com> Brion Vibber wrote on Sun, Aug 10, 2003 at 02:42:38AM -0700: > On further investigation, I note two things: > > a) The "_load_items(): Failed to recieve valid header!" is what I get > anytime I ask for data that isn't available, and seems to be normal. Well, if some data you asked for isn't available, it's _not_ an error, and you don't fail to receive a valid header, so something strange is going on. A cursory look at the client's source (I don't really know any PHP) seems to indicate that the client makes some unwarranted assumptions. I _think_ it only recognises the "END\r\n" line which finishes any batch of data a server sends when this line comes in the same buffer (as a result of the same read call) with some previous data for some key. As a result, when the server fails to match any keys, and only sends "END\r\n" (correctly, according to the protocol), the client thinks it's an error. This by itself may be harmless, but I think that more serious errors could occur if the "END\r\n" doesn't come in the same IP packet as the rest of server's reply (say if the reply is too large to fit in one packet) and subsequently arrives via a separate read request. This logic should be fixed (there shouldn't be any assumptions about how data is separated across read/write calls). > D'oh! Looks like relative expiration times are a new feature of > 1.1.7/1.1.8, and 1.1.6 expects either 0 or a full Unix timestamp. That's correct (don't use 1.1.7, it has an embarrassing bug related to this very feature). --avva From brion@pobox.com Sun Aug 10 11:32:23 2003 From: brion@pobox.com (Brion Vibber) Date: Sun, 10 Aug 2003 03:32:23 -0700 Subject: Fast writes, slow reads Message-ID: <3F361F37.8010204@pobox.com> This is a multi-part message in MIME format. --------------040400050004020103050504 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit I'm finding that reading data back from memcached is surprisingly slow. I've probably done something wrong. :) I wrote a simple loop that reads 500 integers or strings, adding each one to the cache if it's not already in. The first run, which checks for 500 uncached items and adds 500 items to the cache, runs fast enough; more or less a second. The second run, which fetches back the set values, consistently takes about 50 seconds, about a tenth of a second per fetched item. 1000 items take 100 seconds, 50 items take 5 seconds. Since I expect to do a lot more reading than writing, this has me a little worried! I'm getting this same slow read speed from the PHP and Perl clients, and both talking to a local server on the BSD box or over the network to the Linux box. Moving the Perl client from the 2 GHz Athlon (BSD) to the 266 MHz Pentium II (Linux), oddly enough my speeds increase a bit: it takes a mere 20 seconds to fetch 500 items (though the check + add sequence goes up to 2 seconds). It doesn't seem to make a difference whether it's talking to the local or the remote server. Any ideas? I've attached the Perl version of the test script; I'm using the 1.0.6 MemCachedClient... Perl 5.6.1 is installed on the FreeBSD box, 5.8.0 on the Linux box. -- brion vibber (brion @ pobox.com) --------------040400050004020103050504 Content-Type: text/plain; name="mctest.pl" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="mctest.pl" #!/usr/bin/perl # memcached -p 11000 use MemCachedClient; $wgMemc = new MemCachedClient { 'servers' => [ "127.0.0.1:11000" ], # 'servers' => [ "10.0.0.1:11000" ], # 'servers' => [ "10.0.0.2:11000" ], 'debug' => 0 }; $max = 500; print "Grab $max integers:\n"; $time_start = time(); @arr = []; for($i=0; $i<$max; $i++) { $n = $wgMemc->get( $key = "test:intarray:$i" ); if(!$n) { print "* $i not in cache, adding\n"; $n = $i; $wgMemc->add( $key, $n ); } else { print "* $n found\n"; } $arr[$i] = $n; } $time_end = time(); $time = $time_end - $time_start; print "Retrieved $max ints in $time secs.\n\n"; print "Grab $max strings:\n"; $time_start = time(); @arr = []; for($i=0; $i<$max; $i++) { $n = $wgMemc->get( $key = "test:stringarray:$i" ); if(!$n) { print "* $i not in cache, adding\n"; $n = "this is the ${i}th string"; $wgMemc->add( $key, $n ); } else { print "* $n found\n"; } $arr[$i] = $n; } $time_end = time(); $time = $time_end - $time_start; print "Retrieved $max strings in $time secs.\n\n"; --------------040400050004020103050504-- From martine@danga.com Sun Aug 10 11:40:33 2003 From: martine@danga.com (Evan Martin) Date: Sun, 10 Aug 2003 03:40:33 -0700 Subject: [patch] autoconf cleanups, build on osx (incl. freebsd patches) Message-ID: <12249ABF-CB1F-11D7-B0B6-003065B8A5CC@danga.com> --Apple-Mail-2-600455367 Content-Disposition: attachment; filename=memcached-bsd.patch Content-Transfer-Encoding: 7bit Content-Type: application/octet-stream; x-unix-mode=0644; name="memcached-bsd.patch" Index: ChangeLog =================================================================== RCS file: /home/cvspub/wcmtools/memcached/ChangeLog,v retrieving revision 1.11 diff -u -r1.11 ChangeLog --- ChangeLog 30 Jul 2003 05:53:49 -0000 1.11 +++ ChangeLog 10 Aug 2003 10:38:20 -0000 @@ -1,3 +1,14 @@ +2003-08-10 (Evan Martin) + * Makefile.am: debug, optimization, and static flags are controlled + by the configure script. + * configure.ac: + - allow specifying libevent directory with --with-libevent=DIR + - check for malloc.h (unavailable on BSDs) + - check for socklen_t (unavailable on OSX) + * assoc.c, items.c, slabs.c: Remove some unused headers. + * memcached.c: allow for nonexistence of malloc.h; #define a POSIX + macro to import mlockall flags. + 2003-07-29 * version 1.1.7 * big bug fix: item exptime 0 meant expire immediately, not never Index: Makefile.am =================================================================== RCS file: /home/cvspub/wcmtools/memcached/Makefile.am,v retrieving revision 1.8 diff -u -r1.8 Makefile.am --- Makefile.am 7 Aug 2003 17:31:17 -0000 1.8 +++ Makefile.am 10 Aug 2003 10:38:20 -0000 @@ -5,6 +5,5 @@ DIST_SUBDIRS = doc EXTRA_DIST = doc TODO -CFLAGS=-g -O2 -static -DNDEBUG - +AM_CFLAGS=-DNDEBUG Index: assoc.c =================================================================== RCS file: /home/cvspub/wcmtools/memcached/assoc.c,v retrieving revision 1.5 diff -u -r1.5 assoc.c --- assoc.c 27 Jun 2003 21:15:55 -0000 1.5 +++ assoc.c 10 Aug 2003 10:38:20 -0000 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -28,7 +27,6 @@ #include #include #include -#include #include #include "memcached.h" Index: configure.ac =================================================================== RCS file: /home/cvspub/wcmtools/memcached/configure.ac,v retrieving revision 1.15 diff -u -r1.15 configure.ac --- configure.ac 30 Jul 2003 05:53:49 -0000 1.15 +++ configure.ac 10 Aug 2003 10:38:20 -0000 @@ -7,6 +7,42 @@ AC_PROG_CC AC_PROG_INSTALL +AC_ARG_WITH(libevent, + AC_HELP_STRING([--with-libevent=DIRECTORY],[base directory for libevent])) +if test ${with_libevent+set} = set && test $with_libevent != no; then + CFLAGS="$CFLAGS -I$with_libevent/include" + LDFLAGS="$LDFLAGS -L$with_libevent/lib" +fi + +LIBEVENT_URL=http://www.monkey.org/~provos/libevent/ +AC_CHECK_LIB(event, event_set, , + [AC_MSG_ERROR(libevent is required. You can get it from $LIBEVENT_URL)]) + +AC_CHECK_HEADER(malloc.h, AC_DEFINE(HAVE_MALLOC_H,,[do we have malloc.h?])) + +dnl From licq: Copyright (c) 2000 Dirk Mueller +dnl Check if the type socklen_t is defined anywhere +AC_DEFUN(AC_C_SOCKLEN_T, +[AC_CACHE_CHECK(for socklen_t, ac_cv_c_socklen_t, +[ + AC_TRY_COMPILE([ + #include + #include + ],[ + socklen_t foo; + ],[ + ac_cv_c_socklen_t=yes + ],[ + ac_cv_c_socklen_t=no + ]) +]) +if test $ac_cv_c_socklen_t = no; then + AC_DEFINE(socklen_t, int, [define to int if socklen_t not available]) +fi +]) + +AC_C_SOCKLEN_T + dnl Default to building a static executable. AC_ARG_ENABLE(static, AC_HELP_STRING([--disable-static],[build a dynamically linked executable]), @@ -19,10 +55,6 @@ CFLAGS="$CFLAGS -static" AC_MSG_RESULT(yes) fi - -LIBEVENT_URL=http://www.monkey.org/~provos/libevent/ -AC_CHECK_LIB(event, event_set, , - [AC_MSG_ERROR(libevent is required. You can get it from $LIBEVENT_URL)]) AC_CONFIG_FILES(Makefile) AC_OUTPUT Index: items.c =================================================================== RCS file: /home/cvspub/wcmtools/memcached/items.c,v retrieving revision 1.18 diff -u -r1.18 items.c --- items.c 23 Jul 2003 00:00:20 -0000 1.18 +++ items.c 10 Aug 2003 10:38:20 -0000 @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -17,7 +16,6 @@ #include #include #include -#include #include #include "memcached.h" Index: memcached.c =================================================================== RCS file: /home/cvspub/wcmtools/memcached/memcached.c,v retrieving revision 1.29 diff -u -r1.29 memcached.c --- memcached.c 30 Jul 2003 05:53:49 -0000 1.29 +++ memcached.c 10 Aug 2003 10:38:22 -0000 @@ -23,6 +23,11 @@ #include #include #include +/* some POSIX systems need the following definition + * to get mlockall flags out of sys/mman.h. */ +#ifndef _P1003_1B_VISIBLE +#define _P1003_1B_VISIBLE +#endif #include #include #include @@ -34,9 +39,12 @@ #include #include #include -#include #include +#ifdef HAVE_MALLOC_H +#include +#endif + #include "memcached.h" struct stats stats; @@ -314,6 +322,7 @@ return; } +#ifdef HAVE_MALLOC_H if (strcmp(command, "stats malloc") == 0) { char temp[512]; struct mallinfo info; @@ -333,6 +342,7 @@ out_string(c, temp); return; } +#endif /* HAVE_MALLOC_H */ if (strcmp(command, "stats maps") == 0) { char *wbuf; Index: slabs.c =================================================================== RCS file: /home/cvspub/wcmtools/memcached/slabs.c,v retrieving revision 1.13 diff -u -r1.13 slabs.c --- slabs.c 27 Jul 2003 05:04:37 -0000 1.13 +++ slabs.c 10 Aug 2003 10:38:22 -0000 @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -20,7 +19,6 @@ #include #include #include -#include #include #include "memcached.h" --Apple-Mail-2-600455367 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed The ChangeLog: * Makefile.am: debug, optimization, and static flags are controlled by the configure script. * configure.ac: - allow specifying libevent directory with --with-libevent=DIR - check for malloc.h (unavailable on BSDs) - check for socklen_t (unavailable on OSX) * assoc.c, items.c, slabs.c: Remove some unused headers. * memcached.c: allow for nonexistence of malloc.h; #define a POSIX macro to import mlockall flags. My notes: This now builds on OSX, though I get some weird linker errors unless I --disable-static. But in theory, working on OSX means it probably works on FreeBSD. That socklen_t check looks hairy, but even libevent does a similar check. (Ours is a bit more complicated to allow autoconf caching but it's a cut'n'paste job so it should work.) Special thanks to Sean Chittenden (have we met? I swear I know that name); I used his FreeBSD patches as a reference for what doesn't work on BSD. Rather than removing blocks of code as his patches did, this patch #ifdefs out code that is platform-specific (only the slab stats stuff, really). Hopefully, mlockall actually does work on FreeBSD and the problem there was only that MCL_* weren't getting set; it looks like mlockall is in POSIX[1] and should work everywhere. The +#define _P1003_1B_VISIBLE needed to get those flags at first glance looks like a huge hack but some googling indicates it's moderately standard[2]. I'm afraid it's a derived setting from some other setting (possibly simple P1003_B, as some things I'm finding on Google indicate), but at least on OSX it's never set and only read in one file, as far as I can tell: lulu:~% grep -lrs _P1003_1B_VISIBLE /usr/include/* /usr/include/sys/mman.h In retrospect the patch is tiny, but damn did that all take me a while to figure out. Untested on Linux or FreeBSD, so comments are welcome. :) [1] http://www.opengroup.org/onlinepubs/007908799/xsh/mlockall.html [2] http://www.chedong.com/phpMan.php/man/posix4/9 -- Evan Martin martine@danga.com http://neugierig.org --Apple-Mail-2-600455367-- From martine@danga.com Sun Aug 10 11:45:24 2003 From: martine@danga.com (Evan Martin) Date: Sun, 10 Aug 2003 03:45:24 -0700 Subject: Fast writes, slow reads In-Reply-To: <3F361F37.8010204@pobox.com> References: <3F361F37.8010204@pobox.com> Message-ID: <20030810104524.GA7244@danga.com> On Sun, Aug 10, 2003 at 03:32:23AM -0700, Brion Vibber wrote: > The second run, which fetches back the set values, consistently takes > about 50 seconds, about a tenth of a second per fetched item. 1000 items > take 100 seconds, 50 items take 5 seconds. This sounds like a problem I was having related to the backend method libevent was using. Which one are you using? To find out: % EVENT_SHOW_METHOD=1 ./memcached libevent using: select -- Evan Martin martine@danga.com http://neugierig.org From brion@pobox.com Sun Aug 10 11:52:23 2003 From: brion@pobox.com (Brion Vibber) Date: Sun, 10 Aug 2003 03:52:23 -0700 Subject: Fast writes, slow reads In-Reply-To: <20030810104524.GA7244@danga.com> References: <3F361F37.8010204@pobox.com> <20030810104524.GA7244@danga.com> Message-ID: <3F3623E7.5040105@pobox.com> Evan Martin wrote: >This sounds like a problem I was having related to the backend method >libevent was using. > Uh-oh... :) > Which one are you using? To find out: >% EVENT_SHOW_METHOD=1 ./memcached >libevent using: select > FreeBSD 5.1, libevent 0.7a installed from ports: $ EVENT_SHOW_METHOD=1 memcached libevent using: kqueue Red Hat 8.0, libevent 0.7a installed from source with no special options: $ EVENT_SHOW_METHOD=1 ./memcached libevent using: poll -- brion vibber (brion @ pobox.com) From mellon@pobox.com Sun Aug 10 15:38:10 2003 From: mellon@pobox.com (Anatoly Vorobey) Date: Sun, 10 Aug 2003 14:38:10 +0000 Subject: Fast writes, slow reads In-Reply-To: <3F361F37.8010204@pobox.com> References: <3F361F37.8010204@pobox.com> Message-ID: <20030810143810.GA31414@pobox.com> You wrote on Sun, Aug 10, 2003 at 03:32:23AM -0700: > Since I expect to do a lot more reading than writing, this has me a > little worried! I'm getting this same slow read speed from the PHP and > Perl clients, and both talking to a local server on the BSD box or over > the network to the Linux box. What happens if you batch all the reads together, as one request? > Moving the Perl client from the 2 GHz Athlon (BSD) to the 266 MHz > Pentium II (Linux), oddly enough my speeds increase a bit: it takes a > mere 20 seconds to fetch 500 items (though the check + add sequence goes > up to 2 seconds). It doesn't seem to make a difference whether it's > talking to the local or the remote server. The slowdown must be due to something on the client side then. If you change the client's platform without changing the server's platform, the time changes from 50 to 20 seconds, right? -- avva From brion@pobox.com Sun Aug 10 13:18:53 2003 From: brion@pobox.com (Brion Vibber) Date: Sun, 10 Aug 2003 05:18:53 -0700 Subject: Fast writes, slow reads In-Reply-To: <20030810143810.GA31414@pobox.com> References: <3F361F37.8010204@pobox.com> <20030810143810.GA31414@pobox.com> Message-ID: <3F36382D.7030000@pobox.com> Anatoly Vorobey wrote: >What happens if you batch all the reads together, as one request? > I'm having trouble getting this to work... so far, it takes the same amount of time (plus a fraction of a second for setting up more arrays) but I only actually get the last item requested returned in the hash. This _may_ be a problem in the PHP client, or I _may_ be doing something wrong. I haven't been able to get it working in perl, which _may_ be because I can't figure out how to get anything out of a hash reference. :) Here's the PHP code for the batched get: $keys = array(); for($i=0; $i<$max; $i++) { $keys[$i] = "test:intarray:$i"; } $res = $wgMemc->get_multi( $keys ); $arr = array(); for($i=0; $i<$max; $i++) { $n = $res[$key = "test:intarray:$i"]; if($n === NULL) { echo "
  • $i not in cache, adding\n"; $n = $i; $wgMemc->add( $key, $n ); } else { echo "
  • $n found\n"; } } >The slowdown must be due to something on the client side then. If you >change the client's platform without changing the server's platform, the >time changes from 50 to 20 seconds, right? > Seems to be so, yes. -- brion vibber (brion @ pobox.com) From lisa@gentoo.org Sun Aug 10 13:22:43 2003 From: lisa@gentoo.org (Lisa Marie Seelye) Date: 10 Aug 2003 08:22:43 -0400 Subject: gentoo roadmap In-Reply-To: References: <1060370345.1765.30.camel@lisa.thedoh.com> <1060372622.1762.42.camel@lisa.thedoh.com> Message-ID: <1060518162.17210.0.camel@lisa.thedoh.com> --=-DU2pXl0ZLwquOQJ3qkpr Content-Type: text/plain Content-Transfer-Encoding: quoted-printable On Fri, 2003-08-08 at 17:12, Brad Fitzpatrick wrote: > In any case, the headers should be updated in Gentoo for the new system > call numbers, so programs like libevent can build with all their > functionality, even if the current running kernel doesn't support it. I'm not a real glibc guru, but the epoll.h header is shipped with our glibc. --=20 Regards, -Lisa --=-DU2pXl0ZLwquOQJ3qkpr Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQA/NjkSy0a1Vh5Jb8URArRuAKDB1XHhIlps8JVUBzTKk+SupTzixgCghHuH QnN+dkvL1P+S1hv4buKMHXw= =CsRO -----END PGP SIGNATURE----- --=-DU2pXl0ZLwquOQJ3qkpr-- From brad@danga.com Sun Aug 10 16:01:44 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 08:01:44 -0700 (PDT) Subject: Fast writes, slow reads In-Reply-To: <20030810104524.GA7244@danga.com> References: <3F361F37.8010204@pobox.com> <20030810104524.GA7244@danga.com> Message-ID: In particular, don't mismatch the wrong kernels with wrong libevents. Only use >= libevent-0.7a and epoll-lt (level-triggered). On Sun, 10 Aug 2003, Evan Martin wrote: > On Sun, Aug 10, 2003 at 03:32:23AM -0700, Brion Vibber wrote: > > The second run, which fetches back the set values, consistently takes > > about 50 seconds, about a tenth of a second per fetched item. 1000 items > > take 100 seconds, 50 items take 5 seconds. > > This sounds like a problem I was having related to the backend method > libevent was using. Which one are you using? To find out: > % EVENT_SHOW_METHOD=1 ./memcached > libevent using: select > > -- > Evan Martin > martine@danga.com > http://neugierig.org > > From brad@danga.com Sun Aug 10 16:05:33 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 08:05:33 -0700 (PDT) Subject: memcached in freebsd In-Reply-To: <3F36138E.50503@pobox.com> References: <3F36138E.50503@pobox.com> Message-ID: > On further investigation, I note two things: > > a) The "_load_items(): Failed to recieve valid header!" is what I get > anytime I ask for data that isn't available, and seems to be normal. Hm, that warning should be removed, then. Asking for data that's not there is a totally normal case. From brion@pobox.com Sun Aug 10 16:11:25 2003 From: brion@pobox.com (Brion Vibber) Date: Sun, 10 Aug 2003 08:11:25 -0700 Subject: memcached in freebsd In-Reply-To: References: <3F36138E.50503@pobox.com> Message-ID: <3F36609D.8090102@pobox.com> Brad Fitzpatrick wrote: >>a) The "_load_items(): Failed to recieve valid header!" is what I get >>anytime I ask for data that isn't available, and seems to be normal. >> >> > >Hm, that warning should be removed, then. Asking for data that's not >there is a totally normal case. > It only shows that with debug output turned on. I suspect it's not meant to be as scary as it sounds. :) -- brion vibber (brion @ pobox.com) From martine@danga.com Sun Aug 10 19:50:46 2003 From: martine@danga.com (Evan Martin) Date: Sun, 10 Aug 2003 11:50:46 -0700 Subject: [patch] increased verbosity setting Message-ID: <8D18F975-CB63-11D7-B1F0-003065B8A5CC@danga.com> --Apple-Mail-6-629867428 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed This patch lets you add multiple -v flags. Now -vv will dump the client commands/responses as they come in. (Someone on the list remarked that the -v output doesn't really show anything, but looking at the source indicates it shows errors. I was also surprised by seeing nothing when I added -v. Perhaps it would be better to show errors by default, use -v for this functionality I added, and either add a -q (quiet) or just suggest piping to /dev/null if you want no output.) --Apple-Mail-6-629867428 Content-Disposition: attachment; filename=memcached-verbose.patch Content-Transfer-Encoding: 7bit Content-Type: application/octet-stream; x-unix-mode=0644; name="memcached-verbose.patch" --- memcached/memcached.c Sun Aug 10 11:30:49 2003 +++ memcached-bsd/memcached.c Sun Aug 10 11:00:06 2003 @@ -208,6 +208,9 @@ void out_string(conn *c, char *str) { int len; + if (settings.verbose > 1) + fprintf(stderr, ">%d %s\n", c->sfd, str); + len = strlen(str); if (len + 2 > c->wsize) { /* ought to be always enough. just fail for simplicity */ @@ -458,6 +461,9 @@ * directly into it, then continue in nread_complete(). */ + if (settings.verbose > 1) + fprintf(stderr, "<%d %s\n", c->sfd, command); + if ((strncmp(command, "add ", 4) == 0 && (comm = NREAD_ADD)) || (strncmp(command, "set ", 4) == 0 && (comm = NREAD_SET)) || (strncmp(command, "replace ", 8) == 0 && (comm = NREAD_REPLACE))) { @@ -708,7 +714,7 @@ if (c->rbytes >= c->rsize) { char *new_rbuf = realloc(c->rbuf, c->rsize*2); if (!new_rbuf) { - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Couldn't realloc input buffer\n"); c->rbytes = 0; /* ignore what we read */ out_string(c, "SERVER_ERROR out of memory"); @@ -738,6 +744,7 @@ } int update_event(conn *c, int new_flags) { + printf("update_event %x %x\n", c->ev_flags, new_flags); if (c->ev_flags == new_flags) return 1; if (event_del(&c->event) == -1) return 0; @@ -757,7 +764,7 @@ int res; while (!exit) { - /*printf("state %d\n", c->state); */ + /* printf("state %d\n", c->state);*/ switch(c->state) { case conn_listening: addrlen = sizeof(addr); @@ -777,7 +784,7 @@ } newc = conn_new(sfd, conn_read, EV_READ | EV_PERSIST); if (!newc) { - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "couldn't create new connection\n"); close(sfd); return; @@ -794,7 +801,7 @@ } /* we have no command line and no data to read from network */ if (!update_event(c, EV_READ | EV_PERSIST)) { - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; @@ -835,7 +842,7 @@ } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_READ | EV_PERSIST)) { - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; @@ -844,7 +851,7 @@ break; } /* otherwise we have a real error, on which we close the connection */ - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Failed to read, and not due to blocking\n"); c->state = conn_closing; break; @@ -880,7 +887,7 @@ } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_READ | EV_PERSIST)) { - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; @@ -889,7 +896,7 @@ break; } /* otherwise we have a real error, on which we close the connection */ - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Failed to read, and not due to blocking\n"); c->state = conn_closing; break; @@ -913,7 +920,7 @@ } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_WRITE | EV_PERSIST)) { - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; @@ -923,7 +930,7 @@ } /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK, we have a real error, on which we close the connection */ - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Failed to write, and not due to blocking\n"); c->state = conn_closing; break; @@ -947,7 +954,7 @@ } if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { if (!update_event(c, EV_WRITE | EV_PERSIST)) { - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Couldn't update event\n"); c->state = conn_closing; break; @@ -957,7 +964,7 @@ } /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK, we have a real error, on which we close the connection */ - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Failed to write, and not due to blocking\n"); c->state = conn_closing; break; @@ -1016,9 +1023,10 @@ c = (conn *)arg; c->which = which; + printf("event_handler %d\n", fd); /* sanity */ if (fd != c->sfd) { - if(settings.verbose) + if (settings.verbose > 0) fprintf(stderr, "Catastrophic: event fd doesn't match conn fd!\n"); conn_close(c); return; @@ -1126,6 +1134,7 @@ printf("-c max simultaneous connections, default is 1024\n"); printf("-k lock down all paged memory\n"); printf("-v verbose (print errors/warnings while in event loop)\n"); + printf("-vv more verbose (also print client commands/reponses)\n"); printf("-h print this help and exit\n"); printf("-i print memcached and libevent license\n"); return; @@ -1236,7 +1245,7 @@ lock_memory = 1; break; case 'v': - settings.verbose = 1; + settings.verbose++; break; case 'l': if (!inet_aton(optarg, &addr)) { --Apple-Mail-6-629867428-- From mellon@pobox.com Sun Aug 10 22:59:40 2003 From: mellon@pobox.com (Anatoly Vorobey) Date: Sun, 10 Aug 2003 21:59:40 +0000 Subject: [patch] increased verbosity setting In-Reply-To: <8D18F975-CB63-11D7-B1F0-003065B8A5CC@danga.com> References: <8D18F975-CB63-11D7-B1F0-003065B8A5CC@danga.com> Message-ID: <20030810215940.GA28898@pobox.com> On Sun, Aug 10, 2003 at 11:50:46AM -0700, Evan Martin wrote: > This patch lets you add multiple -v flags. Now -vv will dump the > client commands/responses as they come in. Does this patch have some debugging printf's mistakenly left in? + printf("update_event %x %x\n", c->ev_flags, new_flags); + printf("event_handler %d\n", fd); Also: - if(settings.verbose) + if (settings.verbose > 0) Why? ;) From martine@danga.com Sun Aug 10 20:06:37 2003 From: martine@danga.com (Evan Martin) Date: Sun, 10 Aug 2003 12:06:37 -0700 Subject: [test case] terrible performance with select() Message-ID: --Apple-Mail-12-630818559 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed As a few people (including me) have found out, memcache is suspiciously slow when using libevent backends other than epoll. (I think? I guess I've only seen the behavior myself with select().) FWIW, it appears the problem that event_hander is taking up to five seconds to get called, but only after repeat commands. Why that happens is a more difficult problem, because it works fine with epoll so it must be some behavior that's inconsistent underneath libevent. Attached is a test case that exhibits the behavior. Of note is the perfectly round numbers that come up when it's being slow. Is something timing out here? (The "delay" here is the delay between subsequent requests.) lulu:~/projects/memcached/api/python% ./slow.py 1 Trying get()s with 1.00s delay get took 0.13 seconds get took 0.30 seconds get took 4.00 seconds get took 4.00 seconds get took 4.00 seconds get took 4.00 seconds lulu:~/projects/memcached/api/python% ./slow.py 0.9 Trying get()s with 0.90s delay get took 0.18 seconds get took 1.38 seconds get took 4.10 seconds get took 4.10 seconds get took 4.10 seconds get took 4.10 seconds --Apple-Mail-12-630818559 Content-Disposition: attachment; filename=slow.py Content-Transfer-Encoding: 7bit Content-Type: application/octet-stream; x-unix-mode=0755; name="slow.py" #!/usr/bin/env python import sys import memcache import time sleeptime = 1 if len(sys.argv) > 1: sleeptime = float(sys.argv[1]) mc = memcache.Client(['127.0.0.1:11211']) print "Trying get()s with %0.2fs delay" % sleeptime try: while 1: t1 = time.time() mc.get("hi") t2 = time.time() print "get took %0.2f seconds" % (t2-t1) time.sleep(sleeptime) except KeyboardInterrupt: pass --Apple-Mail-12-630818559-- From martine@danga.com Sun Aug 10 20:14:14 2003 From: martine@danga.com (Evan Martin) Date: Sun, 10 Aug 2003 12:14:14 -0700 Subject: [patch] increased verbosity setting In-Reply-To: <20030810215940.GA28898@pobox.com> Message-ID: On Sunday, August 10, 2003, at 02:59 PM, Anatoly Vorobey wrote: > On Sun, Aug 10, 2003 at 11:50:46AM -0700, Evan Martin wrote: >> This patch lets you add multiple -v flags. Now -vv will dump the >> client commands/responses as they come in. > > Does this patch have some debugging printf's mistakenly left in? > > + printf("update_event %x %x\n", c->ev_flags, new_flags); > + printf("event_handler %d\n", fd); Oops. :) I noticed that just after I sent it, and then sent a new patch that also included a ChangeLog entry, but I managed to send that new patch only to myself. (I'm using the OSX mail client and I'm a bit unfamiliar with it, which is also why these patches are coming out a bit weird.) > Also: > > - if(settings.verbose) > + if (settings.verbose > 0) > > Why? ;) Yeah, good point. I had something else in mind when I made the change... I guess it'd be most appropriate to do some sort of enum { LOG_ERRORS, LOG_PROTOCOL }; and then use if (settings.verbose > LOG_ERRORS) instead of that > 0, but that's probably not worth the effort. From martine@danga.com Sun Aug 10 20:22:08 2003 From: martine@danga.com (Evan Martin) Date: Sun, 10 Aug 2003 12:22:08 -0700 Subject: [patch] python api touchup Message-ID: --Apple-Mail-14-631750345 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; format=flowed Most importantly: I renamed a class and missed a place where it was referenced, which means it dies inappropriately if a host goes down. --Apple-Mail-14-631750345 Content-Disposition: attachment; filename=memcached-python.patch Content-Transfer-Encoding: 7bit Content-Type: application/octet-stream; x-unix-mode=0644; name="memcached-python.patch" diff -ur --exclude=CVS memcached-bsd/api/python/ChangeLog memcached-pyfix/api/python/ChangeLog --- memcached-bsd/api/python/ChangeLog Sun Aug 10 12:16:41 2003 +++ memcached-pyfix/api/python/ChangeLog Sun Aug 10 12:20:17 2003 @@ -1,3 +1,9 @@ +Thu, 10 Aug 2003 12:17:50 -0700 Evan Martin + + * Slightly more verbose self-test output. + * Fix mark_dead() to use proper classname. + * Make pooltest.py run from the test directory. + Thu, 07 Aug 2003 16:32:32 -0700 Evan Martin * Add incr, decr, and delete. diff -ur --exclude=CVS memcached-bsd/api/python/memcache.py memcached-pyfix/api/python/memcache.py --- memcached-bsd/api/python/memcache.py Sun Aug 10 12:16:44 2003 +++ memcached-pyfix/api/python/memcache.py Sun Aug 10 12:15:50 2003 @@ -445,7 +445,7 @@ def mark_dead(self, reason): print "MemCache: %s: %s. Marking dead." % (self, reason) - self.deaduntil = time.time() + Host._DEAD_RETRY + self.deaduntil = time.time() + _Host._DEAD_RETRY self.close_socket() def _get_socket(self): @@ -508,7 +508,7 @@ d = " (dead until %d)" % self.deaduntil return "%s:%d%s" % (self.ip, self.port, d) -def _test(): +def _doctest(): import doctest, memcache servers = ["127.0.0.1:11211"] mc = Client(servers, debug=1) @@ -516,7 +516,8 @@ return doctest.testmod(memcache, globs=globs) if __name__ == "__main__": - _test() + print "Testing docstrings..." + _doctest() print "Running tests:" print #servers = ["127.0.0.1:11211", "127.0.0.1:11212"] Only in memcached-pyfix/api/python: memcache.pyc Only in memcached-pyfix/api/python: slow.py diff -ur --exclude=CVS memcached-bsd/api/python/tests/pooltest.py memcached-pyfix/api/python/tests/pooltest.py --- memcached-bsd/api/python/tests/pooltest.py Sun Aug 10 12:16:44 2003 +++ memcached-pyfix/api/python/tests/pooltest.py Sun Aug 10 12:15:50 2003 @@ -5,6 +5,8 @@ Bring up two memcaches on :11211 and :11212. Try killing one or both. If this code raises any exceptions, it's a bug.""" +import sys +sys.path.append("..") import memcache import time --Apple-Mail-14-631750345-- From brad@danga.com Sun Aug 10 23:30:10 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 15:30:10 -0700 (PDT) Subject: [patch] python api touchup In-Reply-To: References: Message-ID: Cool. Incremented the version number to 1.2 and put on the website. On Sun, 10 Aug 2003, Evan Martin wrote: > Most importantly: I renamed a class and missed a place where it was > referenced, which means it dies inappropriately if a host goes down. > > From brad@danga.com Sun Aug 10 23:34:35 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 15:34:35 -0700 (PDT) Subject: rtsig.patch (fwd) Message-ID: This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. Send mail to mime@docserver.cac.washington.edu for more info. --yrj/dFKFPuw6o+aM Content-Type: TEXT/PLAIN; CHARSET=US-ASCII Content-ID: Content-Disposition: INLINE Taral from LiveJournal added realtime signal support to libevent, which is supported in Linux 2.4 natively (without patches like epoll) and is way better than select/poll. I haven't tested this, but it might be interesting to somebody else on this list. - Brad --yrj/dFKFPuw6o+aM Content-Type: TEXT/PLAIN; CHARSET=us-ascii Content-Transfer-Encoding: QUOTED-PRINTABLE Content-ID: Content-Description: Content-Disposition: ATTACHMENT; FILENAME="rtsig.patch" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.1 (GNU/Linux) iD8DBQE+80SQoQQF8xCPwJQRAo/BAJ97/a+7qSEHkAwk3RuMTZ+11UhbMgCfTd1R nFN3sTRxzxhOcWnnVy39PyQ= =orNr -----END PGP SIGNATURE----- --yrj/dFKFPuw6o+aM-- From brad@danga.com Sun Aug 10 23:52:47 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 15:52:47 -0700 (PDT) Subject: rtsig.patch (fwd) In-Reply-To: <20030811014057.GA30166@pobox.com> References: <20030811014057.GA30166@pobox.com> Message-ID: Er, let's put it here then: http://www.danga.com/memcached/dist/rtsig.patch - Brad On Mon, 11 Aug 2003, Anatoly Vorobey wrote: > You wrote on Sun, Aug 10, 2003 at 03:34:35PM -0700: > > Taral from LiveJournal added realtime signal support to > > libevent, which is supported in Linux 2.4 natively (without patches like > > epoll) and is way better than select/poll. > > > > I haven't tested this, but it might be interesting to somebody else on > > this list. > > You probably realized already, but there's no patch, only a GPG sig. > > -- > avva > > From brad@danga.com Mon Aug 11 00:16:37 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 16:16:37 -0700 (PDT) Subject: PHP API 1.0.7 In-Reply-To: <3F35EB0B.7010506@pobox.com> References: <3F352A7D.9090306@gilfether.com> <3F35EB0B.7010506@pobox.com> Message-ID: PHP client version 1.0.7 is on the website, with your debugging abstraction merged by hand (it didn't apply against Ryan's 1.0.7). Because I did it by hand and didn't test, it may have syntax errors. Let me know. I now have a release script for PHP, so it's easy for me to make new releases. On Sat, 9 Aug 2003, Brion Vibber wrote: > Ryan Gilfether wrote: > > > A new version of the PHP API has been completed, verson 1.0.7. > > > Cool! Where can I find it? > > I'm doing some preliminary work on getting memcached support into > Wikipedia (or rather MediaWiki, as we've recently redubbed the software > thereof), so far I've started with the 1.0.6 PHP client. > > > Along with that 3 new function have been added > > error() - returns an error code for the last error genterated > > error_string() - returns a string with a description of the error > > error_clear() - clears the last error > > > On a related note, the debug mode doesn't mix well with MediaWiki's > output model. I replaced all the "print"s with calls to a _debug() > private function which can I can then override in a subclass to dump > things to our debug log; diff for 1.0.6 attached. > > -- brion vibber (brion @ pobox.com) > From brad@danga.com Mon Aug 11 00:30:17 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 16:30:17 -0700 (PDT) Subject: PHP client's _load_items (was: memcached in freebsd) In-Reply-To: <20030810131120.GA30897@pobox.com> References: <3F36138E.50503@pobox.com> <20030810131120.GA30897@pobox.com> Message-ID: Yeah, the _load_items function in the PHP client is kinda scary. There's no way to treat a socket like a stream in PHP? The command sending in _load_items is good, but the parsing (especially not respecting END\r\n on any "line") is wrong. It'd be so much easier if you could read a line or a block at a time. Then you wouldn't have to remember so much state. Unrelated, that file's in need of some tabs vs. spaces cleanup. Go one way or the other and be consistent, or at least add all the emacs/vim hints at the top/bottom, so people's editors know how wide you thought your spaces were. Ryan, in the future feel free to post diffs to the list, rather than tarballs to me directly, then everybody can get access to things when I'm away for a few hours, and it's easier to read a diff, too. If you need help with cvs and/or making diffs from cvs, email me off-list. - Brad On Sun, 10 Aug 2003, Anatoly Vorobey wrote: > Brion Vibber wrote on Sun, Aug 10, 2003 at 02:42:38AM -0700: > > On further investigation, I note two things: > > > > a) The "_load_items(): Failed to recieve valid header!" is what I get > > anytime I ask for data that isn't available, and seems to be normal. > > Well, if some data you asked for isn't available, it's _not_ an error, > and you don't fail to receive a valid header, so something strange is > going on. A cursory look at the client's source (I don't really know any > PHP) seems to indicate that the client makes some unwarranted > assumptions. I _think_ it only recognises the "END\r\n" line which > finishes any batch of data a server sends when this line comes in the > same buffer (as a result of the same read call) with some previous data > for some key. As a result, when the server fails to match any keys, and > only sends "END\r\n" (correctly, according to the protocol), the client > thinks it's an error. This by itself may be harmless, but I think that > more serious errors could occur if the "END\r\n" doesn't come in the > same IP packet as the rest of server's reply (say if the reply is too > large to fit in one packet) and subsequently arrives via a separate > read request. This logic should be fixed (there shouldn't be any > assumptions about how data is separated across read/write calls). > > > D'oh! Looks like relative expiration times are a new feature of > > 1.1.7/1.1.8, and 1.1.6 expects either 0 or a full Unix timestamp. > > That's correct (don't use 1.1.7, it has an embarrassing bug related to > this very feature). > > --avva > > From brad@danga.com Mon Aug 11 00:39:18 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 16:39:18 -0700 (PDT) Subject: Fast writes, slow reads Message-ID: Brion, Can you reproduce this slow behavior with the Linux x86 binary at http://www.danga.com/memcached/dist/binaries/linux-x86/ ? I want to rule out any sort of build differences, since the binary above is what we use on LiveJournal. (and it flies for us...) If it's still slow with that binary and with the Perl client, it's definitely time to point fingers at libevent. Nothing I see in the PHP client should make things slow, just incorrectly warning in some cases. If you can, make yourself a new kernel. Here's the latest patch, against 2.4.21: http://www.xmailserver.org/linux-patches/epoll-lt-2.4.21-0.16.diff - Brad On Sun, 10 Aug 2003, Brion Vibber wrote: > I'm finding that reading data back from memcached is surprisingly slow. > I've probably done something wrong. :) > > I wrote a simple loop that reads 500 integers or strings, adding each > one to the cache if it's not already in. The first run, which checks for > 500 uncached items and adds 500 items to the cache, runs fast enough; > more or less a second. > > The second run, which fetches back the set values, consistently takes > about 50 seconds, about a tenth of a second per fetched item. 1000 items > take 100 seconds, 50 items take 5 seconds. > > Since I expect to do a lot more reading than writing, this has me a > little worried! I'm getting this same slow read speed from the PHP and > Perl clients, and both talking to a local server on the BSD box or over > the network to the Linux box. > > Moving the Perl client from the 2 GHz Athlon (BSD) to the 266 MHz > Pentium II (Linux), oddly enough my speeds increase a bit: it takes a > mere 20 seconds to fetch 500 items (though the check + add sequence goes > up to 2 seconds). It doesn't seem to make a difference whether it's > talking to the local or the remote server. > > Any ideas? I've attached the Perl version of the test script; I'm using > the 1.0.6 MemCachedClient... Perl 5.6.1 is installed on the FreeBSD box, > 5.8.0 on the Linux box. > > -- brion vibber (brion @ pobox.com) > From brad@danga.com Mon Aug 11 00:43:36 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 16:43:36 -0700 (PDT) Subject: Fast writes, slow reads In-Reply-To: <3F3623E7.5040105@pobox.com> References: <3F361F37.8010204@pobox.com> <20030810104524.GA7244@danga.com> <3F3623E7.5040105@pobox.com> Message-ID: It's even slow when you're using kqueue?! That's supposed to be [slightly] faster than epoll. Was it slow with kqueue and the Perl client or the PHP client? One problem we run into every couple months at LiveJournal is new network hardware coming up in the wrong duplex. Auto-negotiation never seems to work that well. Can you verify both sides are in the same duplex, either half or full? - Brad On Sun, 10 Aug 2003, Brion Vibber wrote: > Evan Martin wrote: > > >This sounds like a problem I was having related to the backend method > >libevent was using. > > > Uh-oh... :) > > > Which one are you using? To find out: > >% EVENT_SHOW_METHOD=1 ./memcached > >libevent using: select > > > FreeBSD 5.1, libevent 0.7a installed from ports: > $ EVENT_SHOW_METHOD=1 memcached > libevent using: kqueue > > Red Hat 8.0, libevent 0.7a installed from source with no special options: > $ EVENT_SHOW_METHOD=1 ./memcached > libevent using: poll > > -- brion vibber (brion @ pobox.com) > > From brion@pobox.com Mon Aug 11 01:47:35 2003 From: brion@pobox.com (Brion Vibber) Date: Sun, 10 Aug 2003 17:47:35 -0700 Subject: Fast writes, slow reads In-Reply-To: References: <3F361F37.8010204@pobox.com> <20030810104524.GA7244@danga.com> <3F3623E7.5040105@pobox.com> Message-ID: <3F36E7A7.5000902@pobox.com> Brad Fitzpatrick wrote: >It's even slow when you're using kqueue?! That's supposed to be >[slightly] faster than epoll. > >Was it slow with kqueue and the Perl client or the PHP client? > I have tried combinations of the following: ports-patched 1.1.6 server on FreeBSD, using kqueue self-compiled 1.1.8 server on Linux, using poll dl'd binary 1.1.8 server on Linux, using poll (I haven't yet managed to get a kernel recompiled with the epoll patch.) with PHP client w/ PHP 4.3.2 on BSD Perl client w/ Perl 5.6.1 on BSD Perl client w/ Perl 5.8.0 on Linux Python client w/ Python 2.2.1 on Linux Python client w/ Python 2.2.2 on BSD So far I've consistently found that: * gets are reasonably fast when there's no data to return * sets, adds, replaces, and deletes are reasonably fast, whether or not the key already exists * gets have a large fixed overhead when there is data to return, which is consistent across all three client libraries and server connections but varies according to the client's system (0.10 seconds on 2GHz Athlon/FreeBSD, 0.04 seconds on 266MHz PII/Linux) With Evan's "slow.py" demo, I see the wait disappear after the first get when using a delay longer than the minimum time on the Linux box, connecting to either server: $ python slow.py 0.03 Trying get()s with 0.03s delay get took 0.04 seconds get took 0.04 seconds get took 0.04 seconds ... $ python slow.py 0.05 Trying get()s with 0.05s delay get took 0.04 seconds get took 0.00 seconds get took 0.00 seconds ... But it never goes away on the BSD box, connecting to either server: $ python slow.py 1 Trying get()s with 1.00s delay get took 0.10 seconds get took 0.10 seconds get took 0.10 seconds ... >One problem we run into every couple months at LiveJournal is new >network hardware coming up in the wrong duplex. Auto-negotiation never >seems to work that well. Can you verify both sides are in the same >duplex, either half or full? > I get the same performance (within my testing tolerance, anyway) over loopback as I do when talking to the other box over the network... -- brion vibber (brion @ pobox.com) From brion@pobox.com Mon Aug 11 02:36:45 2003 From: brion@pobox.com (Brion Vibber) Date: Sun, 10 Aug 2003 18:36:45 -0700 Subject: Fast writes, slow reads In-Reply-To: <3F36E7A7.5000902@pobox.com> References: <3F361F37.8010204@pobox.com> <20030810104524.GA7244@danga.com> <3F3623E7.5040105@pobox.com> <3F36E7A7.5000902@pobox.com> Message-ID: <3F36F32D.70308@pobox.com> I wrote: > With Evan's "slow.py" demo, I see the wait disappear after the first > get when using a delay longer than the minimum time on the Linux box, > connecting to either server: [snip] > $ python slow.py 0.05 > Trying get()s with 0.05s delay > get took 0.04 seconds > get took 0.00 seconds > get took 0.00 seconds > ... If I modify the script to use a different key (for which there is data) for each request, the slowdown remains consistent does not go away with increased delays between requests. -- brion vibber (brion @ pobox.com) From brad@danga.com Mon Aug 11 03:54:57 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 19:54:57 -0700 (PDT) Subject: Read vs. write performance (sloppiness in memcache) Message-ID: I've been investigating the findings that writes are faster than reads. I did a bunch of network sniffing and found the problem is how memcached returns results. It sends way too many packets, resulting in tons of round-trips. In the first case, where the cache is empty, and the client sets 500 keys, it does a get (one packet), and the server sends back a reply saying it has nothing (one packet), the client sets it (one packet), and the server says okay (one packet). Every packet in the transaction except the setup and teardown is a PSH+ACK. That is, it's sending new data and acknowledging the data it just got. However, memcached is a pig when it comes to sending results. Client: get foo, bar Server: I have foo! Client: Okay, I heard you. I'm bored. (ACK) Server: Here is foo. Client: Okay. I'm still waiting (ACK) Server: I have bar! Client: *yawn* (ACK) Server: Here is bar. And we're done. Client: Okay. (ACK) It should be: Client: get foo, bar (PSH) Server: I have foo and bar. here they are. we're done. (ACK,PSH) Client: Okay. (ACK) We'll fix this. In the meantime, don't let this deter you from using memcache. LiveJournal is running with this "slow" code and it's still ridiculously fast (and way faster than a database). This finding just means we can go even faster. - Brad From mellon@pobox.com Mon Aug 11 07:02:56 2003 From: mellon@pobox.com (Anatoly Vorobey) Date: Mon, 11 Aug 2003 06:02:56 +0000 Subject: Read vs. write performance (sloppiness in memcache) In-Reply-To: References: Message-ID: <20030811060256.GA7617@pobox.com> You wrote on Sun, Aug 10, 2003 at 07:54:57PM -0700: > I've been investigating the findings that writes are faster than reads. Here's someone that seems to've run into the same problem. He even reports better results when client is switched from FreeBSD to Linux (just as Brion wrote): http://www.openldap.org/lists/openldap-devel/199907/msg00079.html -- avva From corvus@vadept.com Mon Aug 11 04:13:45 2003 From: corvus@vadept.com (Frank Precissi) Date: Sun, 10 Aug 2003 20:13:45 -0700 Subject: Benchmark? Message-ID: <200308102013.45503.corvus@vadept.com> Hi everyone, Is there a standardized benchmark/test harness available for memcache? With all of the different libevent options (select,kqueue,poll,etc) and different programming/os platforms, I was curious if there was a testing standard developed (insert 500 items, pull a timed random 20 items). We could publish benchmark results based upon libevent/os/language so admin's who use memcache have some sort of reference point to determine if they compiled it correctly or if they are using the slowest libevent for their specific OS. Just a thought.. :) Frank -- A man's gotta know his limitations. -- Clint Eastwood, "Dirty Harry" From mellon@pobox.com Mon Aug 11 07:27:55 2003 From: mellon@pobox.com (Anatoly Vorobey) Date: Mon, 11 Aug 2003 06:27:55 +0000 Subject: Read vs. write performance (sloppiness in memcache) In-Reply-To: References: Message-ID: <20030811062755.GA7772@pobox.com> You wrote on Sun, Aug 10, 2003 at 07:54:57PM -0700: > It should be: > > Client: get foo, bar (PSH) > Server: I have foo and bar. here they are. we're done. (ACK,PSH) > Client: Okay. (ACK) Nah. The problem is not many packets, but the fact that the TCP/IP stack waits a little bit on each of them before sending, hoping we're going to send another one... but when the client requests 500 values one after the other, as in Brion's test, it never does: client: give me key1 server: sending value1 OS: [let's wait a bit] waiting... OS: ok, nothing more has come. sending value1 client: received value1 client: give me key2 .... By setting TCP_NODELAY on the server socket, we eliminate the waits and seem to completely fix the problem, at least for this particular kind of test, where we don't have many consecutive writes. The wait time for receiving 500 values drops from 20sec. to 1 or 0. Brion, can you verify this with your setup? The patch below makes the server set TCP_NODELAY. On the other hand, what if the client requests 100 keys in one GET request? It appears to me that until now, we would send as few IP packets as possible, because we didn't have TCP_NODELAY set and so the OS was waiting a few dozens of milliseconds for us to send more, and we always send more very fast (we don't let go of a GET request as long as the OS accepts our write()'s synchronously). With TCP_NODELAY set, we will instead of have 200 packets instead of, say, 20. Perhaps we should run this under a sniffer, both with and without TCP_NODELAY, to figure out whether this is indeed true, and how this options affects performance of large multi-key GET requests. If it affects the performance badly, but we still want TCP_NODELAY to boost the performance of many consecutive single-key requests, we can think of buffering on the server side, before sending out write()'s -- since this may drastically affect our memory usage, I'd rather not do it unless we really have to. main -> wcmtools src/memcached/memcached.c --- cvs/wcmtools/memcached/memcached.c Tue Jul 29 22:53:49 2003 +++ src/memcached/memcached.c Sun Aug 10 20:13:20 2003 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1052,6 +1053,7 @@ setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)); setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags)); setsockopt(sfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); + setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags)); addr.sin_family = AF_INET; addr.sin_port = htons(port); -- avva From mellon@pobox.com Mon Aug 11 07:30:34 2003 From: mellon@pobox.com (Anatoly Vorobey) Date: Mon, 11 Aug 2003 06:30:34 +0000 Subject: Benchmark? In-Reply-To: <200308102013.45503.corvus@vadept.com> References: <200308102013.45503.corvus@vadept.com> Message-ID: <20030811063034.GA7788@pobox.com> On Sun, Aug 10, 2003 at 08:13:45PM -0700, Frank Precissi wrote: > Hi everyone, > > Is there a standardized benchmark/test harness available for memcache? With > all of the different libevent options (select,kqueue,poll,etc) and different > programming/os platforms, I was curious if there was a testing standard > developed (insert 500 items, pull a timed random 20 items). Not yet, but there should be one; moreover, it should measure not just saves and single-item pulls (like Brion's little test does), but also multiple-item pulls with different amounts of items per request. It seems we'll run into some trade-offs in this area anyway, so we might as well collect more info about it. -- avva sorely in need of a memcache for my brain From brion@pobox.com Mon Aug 11 04:55:00 2003 From: brion@pobox.com (Brion Vibber) Date: Sun, 10 Aug 2003 20:55:00 -0700 Subject: Read vs. write performance (sloppiness in memcache) In-Reply-To: <20030811062755.GA7772@pobox.com> References: <20030811062755.GA7772@pobox.com> Message-ID: <3F371394.8090607@pobox.com> Anatoly Vorobey wrote: >By setting TCP_NODELAY on the server socket, we eliminate the waits >and seem to completely fix the problem, at least for this particular >kind of test, where we don't have many consecutive writes. The wait time >for receiving 500 values drops from 20sec. to 1 or 0. Brion, can you >verify this with your setup? The patch below makes the server set >TCP_NODELAY. > Verified. With the patched server, it runs like lightning. Tested both server and client on both BSD and Linux. >On the other hand, what if the client requests 100 keys in one GET >request? > Can someone whip up a quick script that tests this? I've been unable to make it work using either the Perl or PHP clients, but I may just not know what I'm doing. -- brion vibber (brion @ pobox.com) From brad@danga.com Mon Aug 11 04:56:17 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 20:56:17 -0700 (PDT) Subject: Read vs. write performance (sloppiness in memcache) In-Reply-To: <20030811062755.GA7772@pobox.com> References: <20030811062755.GA7772@pobox.com> Message-ID: Yeah, this patch makes a world of difference. Instead of 20 seconds, it now takes less than 1. However, it's even more packet-happy than before. Dude, we have a more-than-plentiful per-connect buffer on the server side (DATA_BUFFER_SIZE = 2k, by default). Let's use as much of it as we can before writing. I'm not advocating growing it to fit more, but if something else has already grown it (quite likely, since we grow it whenever sending large values), let's write into it, keep track of where we're at (and thus how much we have remaining), and as long as our output can keep fitting in our available per-connection memory, let's put it there until we're out of space, or until we're done. Looking at this tcpdump, we're doing: One packet for "VALUE test:intarray:0 0 1\r\n" One packet for "0\r\n" One packet for "END\r\n" Super lame. That'd fit in 2k. On Mon, 11 Aug 2003, Anatoly Vorobey wrote: > You wrote on Sun, Aug 10, 2003 at 07:54:57PM -0700: > > It should be: > > > > Client: get foo, bar (PSH) > > Server: I have foo and bar. here they are. we're done. (ACK,PSH) > > Client: Okay. (ACK) > > Nah. The problem is not many packets, but the fact that the TCP/IP > stack waits a little bit on each of them before sending, hoping we're > going to send another one... but when the client requests 500 values > one after the other, as in Brion's test, it never does: > > client: give me key1 > server: sending value1 > OS: [let's wait a bit] > waiting... > OS: ok, nothing more has come. sending value1 > client: received value1 > client: give me key2 > .... > > By setting TCP_NODELAY on the server socket, we eliminate the waits > and seem to completely fix the problem, at least for this particular > kind of test, where we don't have many consecutive writes. The wait time > for receiving 500 values drops from 20sec. to 1 or 0. Brion, can you > verify this with your setup? The patch below makes the server set > TCP_NODELAY. > > On the other hand, what if the client requests 100 keys in one GET > request? It appears to me that until now, we would send as few IP > packets as possible, because we didn't have TCP_NODELAY set and so the > OS was waiting a few dozens of milliseconds for us to send more, and > we always send more very fast (we don't let go of a GET request as long > as the OS accepts our write()'s synchronously). With TCP_NODELAY set, > we will instead of have 200 packets instead of, say, 20. Perhaps we > should run this under a sniffer, both with and without TCP_NODELAY, to > figure out whether this is indeed true, and how this options affects > performance of large multi-key GET requests. If it affects the > performance badly, but we still want TCP_NODELAY to boost the > performance of many consecutive single-key requests, we can think of > buffering on the server side, before sending out write()'s -- since this > may drastically affect our memory usage, I'd rather not do it unless we > really have to. > > > > main -> wcmtools src/memcached/memcached.c > --- cvs/wcmtools/memcached/memcached.c Tue Jul 29 22:53:49 2003 > +++ src/memcached/memcached.c Sun Aug 10 20:13:20 2003 > @@ -30,6 +30,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -1052,6 +1053,7 @@ > setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)); > setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags)); > setsockopt(sfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); > + setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags)); > > addr.sin_family = AF_INET; > addr.sin_port = htons(port); > > -- > avva > > From brad@danga.com Mon Aug 11 04:59:47 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 20:59:47 -0700 (PDT) Subject: Read vs. write performance (sloppiness in memcache) In-Reply-To: <3F371394.8090607@pobox.com> References: <20030811062755.GA7772@pobox.com> <3F371394.8090607@pobox.com> Message-ID: On Sun, 10 Aug 2003, Brion Vibber wrote: > Anatoly Vorobey wrote: > > >On the other hand, what if the client requests 100 keys in one GET > >request? > > > > Can someone whip up a quick script that tests this? I've been unable to > make it work using either the Perl or PHP clients, but I may just not > know what I'm doing. > > -- brion vibber (brion @ pobox.com) It'd be fast, but still packet heavy. We know the real issue now. We should probably disable Nagel in the clients, too, or do explicit flushes at certain points. Actually, I already had flushes in my Perl client.... but it looks like the PHP and Python clients could benefit from turning Nagel off (PHP), or doing flushes (Python), based on their output methods. - Brad From lisa@gentoo.org Mon Aug 11 05:02:24 2003 From: lisa@gentoo.org (Lisa Marie Seelye) Date: 11 Aug 2003 00:02:24 -0400 Subject: PHP API 1.0.7 In-Reply-To: <3F352A7D.9090306@gilfether.com> References: <3F352A7D.9090306@gilfether.com> Message-ID: <1060574543.1832.9.camel@lisa.thedoh.com> --=-J5kGgli/oV+/7kwD30AS Content-Type: text/plain Content-Transfer-Encoding: quoted-printable On Sat, 2003-08-09 at 13:08, Ryan Gilfether wrote: > A new version of the PHP API has been completed, verson 1.0.7. > I've had some requests for adding PHPDocs style comments to the API.=20 > Along with that 3 new function have been added > error() - returns an error code for the last error genterated > error_string() - returns a string with a description of the error > error_clear() - clears the last error >=20 > Ryan Not to be incredibly anal, but the .php file should not have any newlines after the closing ?> tag -- this tends to mess with headers should it be included after headers have been sent. :( --=20 Regards, -Lisa --=-J5kGgli/oV+/7kwD30AS Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQA/NxVPy0a1Vh5Jb8URApoXAJ942gJ6KbdliQH2K67onIROzJMEVACfSP8H bWwY1IqWWItsKdJBp/OLwd0= =QsM/ -----END PGP SIGNATURE----- --=-J5kGgli/oV+/7kwD30AS-- From brad@danga.com Mon Aug 11 05:07:31 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 21:07:31 -0700 (PDT) Subject: PHP API 1.0.7 In-Reply-To: <1060574543.1832.9.camel@lisa.thedoh.com> References: <3F352A7D.9090306@gilfether.com> <1060574543.1832.9.camel@lisa.thedoh.com> Message-ID: PHP doesn't detect that? Sad. Ryan might've sent me it corrected and maybe I messed it up when I was merging the other patch. I'll make sure future releases have no bytes after the "?>". - Brad On Sun, 11 Aug 2003, Lisa Marie Seelye wrote: > On Sat, 2003-08-09 at 13:08, Ryan Gilfether wrote: > > A new version of the PHP API has been completed, verson 1.0.7. > > I've had some requests for adding PHPDocs style comments to the API. > > Along with that 3 new function have been added > > error() - returns an error code for the last error genterated > > error_string() - returns a string with a description of the error > > error_clear() - clears the last error > > > > Ryan > > Not to be incredibly anal, but the .php file should not have any > newlines after the closing ?> tag -- this tends to mess with headers > should it be included after headers have been sent. :( > > > -- > Regards, > -Lisa > > From brad@danga.com Mon Aug 11 05:31:00 2003 From: brad@danga.com (Brad Fitzpatrick) Date: Sun, 10 Aug 2003 21:31:00 -0700 (PDT) Subject: PHP client's _load_items In-Reply-To: <3F3704B0.1010903@gilfether.com> References: <3F36138E.50503@pobox.com> <20030810131120.GA30897@pobox.com> <3F3704B0.1010903@gilfether.com> Message-ID: PHP client 1.0.8 is on the website now. Mostly whitespace/punctuation cleanup. Details below. Lisa, I removed the trailing whitespace so PHP won't send HTTP headers prematurely. (Ryan, you'll have to do that on your side too.) I look forward to a proper fix to _load_items. - Brad On Sun, 10 Aug 2003, Ryan Gilfether wrote: > Brad > > attached is the patch to move the 1.0.7 php api to 1.0.8. it fixes the > incorrect debug wording Brion mentioned earlier and also incorporates > his patch that for the debugging abstraction. It also fixes some of the > formatting problems, my editor seemed to use spaces where tabs should > have been applied in some areas. I might consider editing on emacs or vi > in the future. > > I'll work on the _load_items() function for the next release and see > what I can do about it. > > Ryan > > Brad Fitzpatrick wrote: > > Yeah, the _load_items function in the PHP client is kinda scary. > > > > There's no way to treat a socket like a stream in PHP? The command > > sending in _load_items is good, but the parsing (especially not > > respecting END\r\n on any "line") is wrong. It'd be so much easier if > > you could read a line or a block at a time. Then you wouldn't have > > to remember so much state. > > > > Unrelated, that file's in need of some tabs vs. spaces cleanup. Go one > > way or the other and be consistent, or at least add all the emacs/vim > > hints at the top/bottom, so people's editors know how wide you thought > > your spaces were. > > > > Ryan, in the future feel free to post diffs to the list, rather than > > tarballs to me directly, then everybody can get access to things when I'm > > away for a few hours, and it's easier to read a diff, too. If you need > > help with cvs and/or making diffs from cvs, email me off-list. > > > > - Brad > > > > > > On Sun, 10 Aug 2003, Anatoly Vorobey wrote: > > > > > >>Brion Vibber wrote on Sun, Aug 10, 2003 at 02:42:38AM -0700: > >> > >>>On further investigation, I note two things: > >>> > >>>a) The "_load_items(): Failed to recieve valid header!" is what I get > >>>anytime I ask for data that isn't available, and seems to be normal. > >> > >>Well, if some data you asked for isn't available, it's _not_ an error, > >>and you don't fail to receive a valid header, so something strange is > >>going on. A cursory look at the client's source (I don't really know any > >>PHP) seems to indicate that the client makes some unwarranted > >>assumptions. I _think_ it only recognises the "END\r\n" line which > >>finishes any batch of data a server sends when this line comes in the > >>same buffer (as a result of the same read call) with some previous data > >>for some key. As a result, when the server fails to match any keys, and > >>only sends "END\r\n" (correctly, according to the protocol), the client > >>thinks it's an error. This by itself may be harmless, but I think that > >>more serious errors could occur if the "END\r\n" doesn't come in the > >>same IP packet as the rest of server's reply (say if the reply is too > >>large to fit in one packet) and subsequently arrives via a separate > >>read request. This logic should be fixed (there shouldn't be any > >>assumptions about how data is separated across read/write calls). > >> > >> > >>>D'oh! Looks like relative expiration times are a new feature of > >>>1.1.7/1.1.8, and 1.1.6 expects either 0 or a full Unix timestamp. > >> > >>That's correct (don't use 1.1.7, it has an embarrassing bug related to > >>this very feature). > >> > >>--avva > >> > >> > > > > > > > > -- > Ryan Gilfether > Software Engineer > http://www.gilfether.com > From ma