1<?xml version="1.0" encoding="US-ASCII"?> 2<!DOCTYPE rfc SYSTEM "xml2rfc/rfc2629.dtd"> 3<?xml-stylesheet type='text/xsl' href='rfc2629.xslt'?> 4<?rfc toc="yes"?> 5<?rfc strict="yes"?> 6<?rfc symrefs="yes"?> 7<?rfc sortrefs="yes" ?> 8<?rfc compact="yes" ?> 9<?rfc subcompact="yes" ?> 10<rfc category="info" docName="draft-stone-memcache-binary-01" ipr="none"> 11 12 <front> 13 14 <title> Memcache Binary Protocol </title> 15 16 <author fullname="Aaron Stone" surname="Aaron Stone" role="editor"> 17 <organization>Six Apart, Ltd.</organization> 18 <address> 19 <postal> 20 <street>548 4th Street</street> 21 <city>San Francisco</city> 22 <region>CA</region> 23 <code>94107</code> 24 <country>USA</country> 25 </postal> 26 <email>[email protected]</email> 27 </address> 28 </author> 29 30 <date day="14" month="December" year="2007" /> 31 32 <area>Applications</area> 33 34 <keyword>memcache memcached cache</keyword> 35 36 <abstract> 37 <t> 38 This memo explains the memcache binary protocol for informational purposes. 39 </t> 40 41 <t> 42 Memcache is a high performance key-value cache. It is intentionally a 43 dumb cache, optimized for speed only. Applications using memcache do 44 not rely on it for data -- a persistent database with guaranteed reliability 45 is strongly recommended -- but applications can run much faster when 46 cached data is available in memcache. 47 </t> 48 </abstract> 49 </front> 50 51 <middle> 52 <section anchor="introduction" title="Introduction"> 53 <t> 54 Memcache is a high performance key-value cache. It is intentionally a 55 dumb cache, optimized for speed only. Applications using memcache do 56 not rely on it for data -- a persistent database with guaranteed reliability 57 is strongly recommended -- but applications can run much faster when 58 cached data is available in memcache. 59 </t> 60 <t> 61 Memcache was originally written to make <xref target="LJ">LiveJournal</xref> go faster. 62 It now powers all of the fastest web sites that you love. 63 </t> 64 <section anchor="conventions" title="Conventions Used In This Document"> 65 <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 66 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 67 document are to be interpreted as described in <xref target="KEYWORDS"/>. 68 </t> 69 </section> 70 </section> 71 72 <section anchor="packet" title="Packet Structure"> 73 <t> 74 <figure> 75 <preamble>General format of a packet:</preamble> 76 <artwork> 77 Byte/ 0 | 1 | 2 | 3 | 78 / | | | | 79 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 80 +---------------+---------------+---------------+---------------+ 81 0/ HEADER / 82 / / 83 / / 84 / / 85 +---------------+---------------+---------------+---------------+ 86 16/ COMMAND-SPECIFIC EXTRAS (as needed) / 87 +/ (note length in th extras length header field) / 88 +---------------+---------------+---------------+---------------+ 89 m/ Key (as needed) / 90 +/ (note length in key length header field) / 91 +---------------+---------------+---------------+---------------+ 92 n/ Value (as needed) / 93 +/ (note length is total body length header field, minus / 94 +/ sum of the extras and key length body fields) / 95 +---------------+---------------+---------------+---------------+ 96 Total 16 bytes 97 </artwork></figure> 98 </t> 99 100 <t> 101 <figure> 102 <preamble>Request header:</preamble> 103 <artwork> 104 Byte/ 0 | 1 | 2 | 3 | 105 / | | | | 106 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 107 +---------------+---------------+---------------+---------------+ 108 0| Magic | Opcode | Key length | 109 +---------------+---------------+---------------+---------------+ 110 4| Extras length | Data type | Reserved | 111 +---------------+---------------+---------------+---------------+ 112 8| Total body length | 113 +---------------+---------------+---------------+---------------+ 114 12| Message ID | 115 +---------------+---------------+---------------+---------------+ 116 Total 16 bytes 117 </artwork></figure> 118 </t> 119 120 <t> 121 <figure> 122 <preamble>Response header:</preamble> 123 <artwork> 124 Byte/ 0 | 1 | 2 | 3 | 125 / | | | | 126 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 127 +---------------+---------------+---------------+---------------+ 128 0| Magic | Opcode | Status | 129 +---------------+---------------+---------------+---------------+ 130 4| Extras length | Data type | Reserved | 131 +---------------+---------------+---------------+---------------+ 132 8| Total body length | 133 +---------------+---------------+---------------+---------------+ 134 12| Message ID | 135 +---------------+---------------+---------------+---------------+ 136 Total 16 bytes 137 </artwork></figure> 138 </t> 139 140 <t> 141 Header fields: 142 <list hangIndent="20" style="hanging"> 143 <t hangText="Magic">Magic number.</t> 144 <t hangText="Opcode">Command code.</t> 145 <t hangText="Key length">Length in bytes of the text key that follows the command extras.</t> 146 <t hangText="Status">Status of the response (non-zero on error).</t> 147 <t hangText="Extras length">Length in bytes of the command extras.</t> 148 <t hangText="Data type">Reserved for future use (Sean is using this soon).</t> 149 <t hangText="Reserved">Really reserved for future use (up for grabs).</t> 150 <t hangText="Total body length">Length in bytes of extra + key + value.</t> 151 <t hangText="Message ID">Will be copied back to you in the response. 152 FIXME: Can this be used to organize <xref target="UDP"/> packets?</t> 153 </list> 154 </t> 155 </section> 156 157 <section anchor="values" title="Defined Values"> 158 <section anchor="value-magic" title="Magic Byte"> 159 <t> 160 <list hangIndent="8" style="hanging"> 161 <t hangText="0x80">Request packet for this protocol version</t> 162 <t hangText="0x81">Response packet for this protocol version</t> 163 </list> 164 </t> 165 166 <t> 167 Magic byte / version. For each version of the protocol, we'll use a 168 different request/reponse value pair. This is useful for protocol 169 analyzers to know what a packet is in isolation from which direction 170 it is moving. Note that it is common to run a memcached instance on a 171 host that also runs an application server. Such a host will both send 172 and receive memcache packets. 173 </t> 174 175 <t> 176 The version should hopefully correspond only to different meanings of 177 the command byte. In an ideal world, we will not change the header 178 format. As reserved bytes are given defined meaning, the protocol 179 version / magic byte values should be incremented. 180 </t> 181 182 <t> 183 Traffic analysis tools are encouraged to identify memcache packets 184 and provide detailed interpretation if the magic bytes are recognized 185 and otherwise to provide a generic breakdown of the packet. Note that 186 the key and value positions can always be identified even if the magic 187 byte or command opcode are not recognized. 188 </t> 189 </section> 190 191 <section anchor="value-status" title="Response Status"> 192 <t> 193 Possible values of this two-byte field: 194 <list hangIndent="8" style="hanging"> 195 <t hangText="0x0000">No error</t> 196 <t hangText="0x0081">Unknown command</t> 197 <t hangText="0x0001">Key not found</t> 198 <t hangText="0x0002">Key exists</t> 199 </list> 200 </t> 201 </section> 202 203 <section anchor="value-opcodes" title="Command Opcodes"> 204 <t> 205 Possible values of the one-byte field: 206 <list hangIndent="8" style="hanging"> 207 <t hangText="0x00">Get</t> 208 <t hangText="0x01">Set</t> 209 <t hangText="0x02">Add</t> 210 <t hangText="0x03">Replace</t> 211 <t hangText="0x04">Delete</t> 212 <t hangText="0x05">Increment</t> 213 <t hangText="0x06">Decrement</t> 214 <t hangText="0x07">Quit</t> 215 <t hangText="0x08">Flush</t> 216 <t hangText="0x09">GetQ</t> 217 <t hangText="0x0A">No-op</t> 218 <t hangText="0x0B">Version</t> 219 </list> 220 </t> 221 </section> 222 223 <section anchor="value-types" title="Data Types"> 224 <t> 225 Possible values of the one-byte field: 226 <list hangIndent="8" style="hanging"> 227 <t hangText="0x00">Raw bytes</t> 228 </list> 229 </t> 230 </section> 231 </section> 232 233 <section title="Commands"> 234 <section anchor="command-get" title="Get, Get Quietly"> 235 <t> 236 <list style="empty"> 237 <t>MUST have extras.</t> 238 <t>MUST have key.</t> 239 <t>MUST NOT have value.</t> 240 </list> 241 </t> 242 243 <t> 244 <list style="symbols"> 245 <t>4 byte flags</t> 246 <t>8 byte data version check</t> 247 </list> 248 </t> 249 250 <t> 251 <figure> 252 <preamble>Extra data for get/getq:</preamble> 253 <artwork> 254 Byte/ 0 | 1 | 2 | 3 | 255 / | | | | 256 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 257 +---------------+---------------+---------------+---------------+ 258 0| Data version check | 259 | | 260 +---------------+---------------+---------------+---------------+ 261 8| Flags | 262 +---------------+---------------+---------------+---------------+ 263 Total 12 bytes 264 </artwork></figure> 265 </t> 266 267 <t> 268 The get command gets a single key. The getq command is both mum 269 on cache miss and quiet, holding its response until a non-quiet 270 command is issued. 271 </t> 272 273 <t> 274 You're not guaranteed a response to a getq cache hit until 275 you send a non-getq command later, which uncorks the 276 server which bundles up IOs to send to the client in one go. 277 </t> 278 279 <t> 280 Clients should implement multi-get (still important for 281 reducing network roundtrips!) as n pipelined requests, the 282 first n-1 being getq, the last being a regular 283 get. that way you're guaranteed to get a response, and 284 you know when the server's done. you can also do the naive 285 thing and send n pipelined gets, but then you could potentially 286 get back a lot of "NOT_FOUND!" error code packets. 287 alternatively, you can send 'n' getqs, followed by an 'echo' 288 or 'noop' command. 289 </t> 290 291 </section> 292 293 <section anchor="command-delete" title="Delete"> 294 <t> 295 <list style="empty"> 296 <t>MAY have extras (FIXME: Is it OK to issue a delete without extras?).</t> 297 <t>MUST have key.</t> 298 <t>MUST NOT have value.</t> 299 </list> 300 </t> 301 302 <t> 303 <list style="symbols"> 304 <t>4 byte expiration time</t> 305 </list> 306 </t> 307 308 <t> 309 <figure> 310 <preamble>Extra data for delete:</preamble> 311 <artwork> 312 Byte/ 0 | 1 | 2 | 3 | 313 / | | | | 314 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 315 +---------------+---------------+---------------+---------------+ 316 0| Expiration | 317 +---------------+---------------+---------------+---------------+ 318 Total 4 bytes 319 </artwork></figure> 320 </t> 321 322 <t> 323 When allows you to 'reserve' a key. When 'when' is set 324 for, say, ten seconds in the future, the 'add' and 'replace' operations will fail for that key 325 until ten seconds from now. The 'set' operation will succeed regardless of any reserved deletes. 326 FIXME: Is the reservation also cancelled? Say there's a delete with a 10 second hold. Two seconds 327 later, an 'add' is received. It fails. Two second later, a 'set' is received. Is succeeds unconditionally. 328 What if another 'add' is received two more seconds later (a total of six seconds since the original 329 10 second delete-hold, thus still within its purview). 330 </t> 331 332 </section> 333 334 <section anchor="command-set" title="Set, Add, Replace"> 335 <t> 336 <list style="empty"> 337 <t>MUST have extras.</t> 338 <t>MUST have key.</t> 339 <t>MUST have value.</t> 340 </list> 341 </t> 342 343 <t> 344 <list style="symbols"> 345 <t>4 byte flags</t> 346 <t>4 byte expiration time</t> 347 <t>8 byte data version check</t> 348 </list> 349 </t> 350 351 <t> 352 <figure> 353 <preamble>Extra data for set/add/replace:</preamble> 354 <artwork> 355 Byte/ 0 | 1 | 2 | 3 | 356 / | | | | 357 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 358 +---------------+---------------+---------------+---------------+ 359 0| Data version check | 360 | | 361 +---------------+---------------+---------------+---------------+ 362 8| Flags | 363 +---------------+---------------+---------------+---------------+ 364 12| Expiration | 365 +---------------+---------------+---------------+---------------+ 366 Total 16 bytes 367 </artwork></figure> 368 </t> 369 370 <t> 371 If the Data Version Check is present and nonzero, the set MUST succeed if the 372 key exists and has a version identifier identical to the provided value, and 373 MUST NOT succeed if the key does not exist or has a different version identifier. 374 The set response packet will include the same values in all three fields. 375 </t> 376 377 <t> 378 If the Data Version Check is zero, the set MUST succeed unconditionally. 379 The set response packet will include idential values for flags and expiration, 380 and a new value for Data Version Check, which the client SHOULD keep track of. 381 </t> 382 383 <t> 384 The key MAY be reserved according to <xref target="command-delete"/>, 385 causing the set to fail. 386 </t> 387 </section> 388 389 <section title="noop"> 390 <t> 391 <list style="empty"> 392 <t>MUST NOT have extras.</t> 393 <t>MUST NOT have key.</t> 394 <t>MUST NOT have value.</t> 395 </list> 396 </t> 397 398 <t> 399 Used as a keep alive. Flushes outstanding getq's. 400 </t> 401 </section> 402 403 <section anchor="command-incr" title="Increment, Decrement"> 404 <t> 405 <list style="empty"> 406 <t>MUST have extras.</t> 407 <t>MUST have key.</t> 408 <t>MUST NOT have value.</t> 409 </list> 410 </t> 411 412 <t> 413 <list style="symbols"> 414 <t>8 byte value to add / subtract (FIXME: Is this unsigned?)</t> 415 <t>8 byte initial value (unsigned)</t> 416 <t>4 byte expiration time</t> 417 </list> 418 </t> 419 420 <t> 421 <figure> 422 <preamble>Extra data for incr/decr:</preamble> 423 <artwork> 424 Byte/ 0 | 1 | 2 | 3 | 425 / | | | | 426 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 427 +---------------+---------------+---------------+---------------+ 428 0| Amount to add | 429 | | 430 +---------------+---------------+---------------+---------------+ 431 8| Initial value | 432 | | 433 +---------------+---------------+---------------+---------------+ 434 16| Expiration | 435 +---------------+---------------+---------------+---------------+ 436 Total 20 bytes 437 </artwork></figure> 438 </t> 439 440 <t> 441 <figure> 442 <preamble>incr/decr response body:</preamble> 443 <artwork> 444 Byte/ 0 | 1 | 2 | 3 | 445 / | | | | 446 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 447 +---------------+---------------+---------------+---------------+ 448 0| 64-bit unsigned response. | 449 | | 450 +---------------+---------------+---------------+---------------+ 451 Total 8 bytes 452 </artwork></figure> 453 </t> 454 455 <t> 456 These commands will either add or remove the specified 457 amount to the requested counter. 458 459 If the counter does not exist, one of two things may happen: 460 461 <list style="numbers"> 462 <t>If the expiration value is all one-bits (0xffffffff), the 463 operation will fail with NOT_FOUND.</t> 464 <t>For all other expiration values, the operation will succeed 465 by seeding the value for this key with the provided initial 466 value to expire with the provided expiration time.</t> 467 </list> 468 </t> 469 470 <t> 471 Note that in the creation case, flags will be set to zero 472 (FIXME: Should they be provided here as well?) 473 </t> 474 </section> 475 </section> 476 477 <section title="Example Session"> 478 <t> 479 We start up our application, and it asks for the value associated with the 'Hello' key. 480 <figure> 481 <preamble>Get request:</preamble> 482 <artwork> 483 Byte/ 0 | 1 | 2 | 3 | 484 / | | | | 485 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 486 +---------------+---------------+---------------+---------------+ 487 0| 0x80 | 0x00 | 5 in big endian (BE) | 488 +---------------+---------------+---------------+---------------+ 489 | 12 in BE | 0x00 | | 490 +---------------+---------------+---------------+---------------+ 491 | 17 in BE | 492 +---------------+---------------+---------------+---------------+ 493 | 0xDEADBEEF | 494 +---------------+---------------+---------------+---------------+ 495 16| 0x00000000 | 496 +---------------+---------------+---------------+---------------+ 497 24| 0xDECAF 0x15 0xBAD 0xC0FFEE | 498 | | 499 +---------------+---------------+---------------+---------------+ 500 28| 'H' 'e' 'l' 'l' | 501 | 'o' | 502 +---------------+ 503 Total 33 bytes (16 header + 12 get-extras + 5 key) 504 </artwork></figure> 505 </t> 506 507 <t> 508 Since nobody has set this key, it returns not found. 509 <figure> 510 <preamble>Get response:</preamble> 511 <artwork> 512 Byte/ 0 | 1 | 2 | 3 | 513 / | | | | 514 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 515 +---------------+---------------+---------------+---------------+ 516 0| 0x81 | 0x00 | 0x0001 | 517 +---------------+---------------+---------------+---------------+ 518 | 0 in BE | 0x00 | | 519 +---------------+---------------+---------------+---------------+ 520 | 0 in BE | 521 +---------------+---------------+---------------+---------------+ 522 | 0xDEADBEEF | 523 +---------------+---------------+---------------+---------------+ 524 Total 16 bytes 525 </artwork></figure> 526 </t> 527 528 <t> 529 Well, looks like we need to set the key! Let's set it to expire on 530 December 15, 2007 at 9:51:09 PM. 531 <figure> 532 <preamble>Set request:</preamble> 533 <artwork> 534 Byte/ 0 | 1 | 2 | 3 | 535 / | | | | 536 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 537 +---------------+---------------+---------------+---------------+ 538 0| 0x80 | 0x01 | 5 in BE | 539 +---------------+---------------+---------------+---------------+ 540 | 16 in BE | 0x00 | | 541 +---------------+---------------+---------------+---------------+ 542 | 26 in BE | 543 +---------------+---------------+---------------+---------------+ 544 | 0xDA7ABA5E | 545 +---------------+---------------+---------------+---------------+ 546 16| 0x00000000 | 547 +---------------+---------------+---------------+---------------+ 548 20| 0xDCCB4674 | 549 +---------------+---------------+---------------+---------------+ 550 24| 0xDECAF 0x15 0xBAD 0xC0FFEE | 551 | | 552 +---------------+---------------+---------------+---------------+ 553 32| 'H' 'e' 'l' 'l' | 554 | 'o' | 'W' 'o' 'r' | 555 | 'l' 'd' | 556 +---------------+---------------+ 557 Total 42 bytes (16 header + 16 set-extras + 5 key + 5 value) 558 </artwork></figure> 559 </t> 560 561 <t> 562 The set succeeds. 563 <figure> 564 <preamble>Set response:</preamble> 565 <artwork> 566 Byte/ 0 | 1 | 2 | 3 | 567 / | | | | 568 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 569 +---------------+---------------+---------------+---------------+ 570 0| 0x81 | 0x01 | 0x0000 | 571 +---------------+---------------+---------------+---------------+ 572 | 16 in BE | 0x00 | | 573 +---------------+---------------+---------------+---------------+ 574 | 16 in BE | 575 +---------------+---------------+---------------+---------------+ 576 | 0xDA7ABA5E | 577 +---------------+---------------+---------------+---------------+ 578 16| 0x00000000 | 579 +---------------+---------------+---------------+---------------+ 580 20| 0xDCCB4674 | 581 +---------------+---------------+---------------+---------------+ 582 24| 0xDECAF 0x15 0xBAD 0xC0FFEE | 583 | | 584 +---------------+---------------+---------------+---------------+ 585 Total 32 bytes (16 header + 16 set-extras) 586 </artwork></figure> 587 </t> 588 589 <t> 590 If the original get request is sent again, the key would be found. 591 <figure> 592 <preamble>Get response:</preamble> 593 <artwork> 594 Byte/ 0 | 1 | 2 | 3 | 595 / | | | | 596 |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| 597 +---------------+---------------+---------------+---------------+ 598 0| 0x81 | 0x00 | 0x00 | | 599 +---------------+---------------+---------------+---------------+ 600 | 12 in BE | 0x00 | | 601 +---------------+---------------+---------------+---------------+ 602 | 17 in BE | 603 +---------------+---------------+---------------+---------------+ 604 | 0xDEADBEEF | 605 +---------------+---------------+---------------+---------------+ 606 16| 0xDCCB4674 | 607 +---------------+---------------+---------------+---------------+ 608 24| 0xDECAF 0x15 0xBAD 0xC0FFEE | 609 | | 610 +---------------+---------------+---------------+---------------+ 611 28| 'W' 'o' 'r' 'l' | 612 | 'd' | 613 +---------------+ 614 Total 33 bytes (16 header + 12 get-extras + 5 value) 615 </artwork></figure> 616 </t> 617 </section> 618 619 <section anchor="security" title="Security Considerations"> 620 <t> 621 Memcache has no authentication or security layers whatsoever. It is 622 RECOMMENDED that memcache be deployed strictly on closed, protected, 623 back-end networks within a single data center, within a single cluster of 624 servers, or even on a single host, providing shared caching for multiple 625 applications. Memcache MUST NOT be made available on a public network. 626 </t> 627 </section> 628 629 </middle> 630 631 <back> 632 <references title="Normative References"> 633 <reference anchor="LJ"> 634 <front> 635 <title>LJ NEEDS MOAR SPEED</title> 636 <author fullname="Brad Fitzpatrick"> 637 <organization>Danga Interactive</organization> 638 </author> 639 <date day="5" month="10" year="1999" /> 640 <abstract> 641 <t>http://www.livejournal.com/</t> 642 </abstract> 643 </front> 644 </reference> 645 <dwdrfc-ref anchor='UDP' src='http://xml.resource.org/public/rfc/bibxml/reference.RFC.0768.xml'/> 646 <dwdrfc-ref anchor='KEYWORDS' src='http://xml.resource.org/public/rfc/bibxml/reference.RFC.2119.xml'/> 647 </references> 648 649 <section anchor="acknowledgments" title="Acknowledgments"> 650 <t> 651 Thanks to Brad Fitzpatrick, Anatoly Vorobey, Steven Grimm, and Dustin 652 Sallings, for their work on the memcached server. 653 </t> 654 655 <t> 656 Thanks to Sean Chittenden, Jonathan Steinert, Brian Aker, Evan Martin, 657 Nathan Neulinger, Eric Hodel, Michael Johnson, Paul Querna, Jamie 658 McCarthy, Philip Neustrom, Andrew O'Brien, Josh Rotenberg, Robin H. 659 Johnson, Tim Yardley, Paolo Borelli, Eli Bingham, Jean-Francois 660 Bustarret, Paul G, Paul Lindner, Alan Kasindorf, Chris Goffinet, Tomash 661 Brechko, and others for their work reporting bugs and maintaining 662 memcached client libraries and bindings in many languages. 663 </t> 664 </section> 665 </back> 666 667</rfc> 668 669