当前位置:首页 > PHP教程 > PHP总结归纳

libmemcached的MEMCACHED_MAX_BUFFER问题

最近给服务增加了一个cache_put_latency指标,加了之后,吓了一跳。发现往memcached put一个10kb左右的数据,latency居然有7ms左右,难于理解,于是花了一些精力找原因。我分别写了一个shell和c++的测试程序。 1、shell脚本使用nc发送set命令。 #/bin/env ba

最近给服务增加了一个cache_put_latency指标,加了之后,吓了一跳。发现往memcached put一个10kb左右的数据,latency居然有7ms左右,难于理解,于是花了一些精力找原因。我分别写了一个shell和c++的测试程序。

1、shell脚本使用nc发送set命令。

#/bin/env bash let s=1 let i=0 let len=8*1024 while true do if (( i >= $len )) then break fi str=${str}1 let i++ done let i=0 begin_time=`date +%s` while true do if (( i >= 1000 )) then break fi printf "set $i 0 0 $lenrn${str}rn" | nc 10.234.4.24 11211 if [[ $? -eq 0 ]] then echo "echo key: $i" fi let i++ done end_time=`date +%s` let use_time=end_time-begin_time echo "set time consumed: $use_time" let i=0 begin_time=`date +%s` while true do if (( i >= 1000 )) then break fi printf "get $irn" | nc 10.234.4.22 11211 > /dev/null 2>&1 let i++ done end_time=`date +%s` let use_time=end_time-begin_time echo "get time consumed: $use_time"

2、c++程序则通过libmemcached set。

#include #include #include #include #include #include #include "libmemcached/memcached.h" using namespace std; uint32_t item_size = 0; uint32_t loop_num = 0; bool single_server = false; std::string local_ip; std::map servers; int64_t getcurrenttime() { struct timeval tval; gettimeofday(&tval, null); return (tval.tv_sec * 1000000ll + tval.tv_usec); } memcached_st* mc_init() { memcached_st * mc = memcached_create(null); if (mc == null) { cout first.c_str(), iter->second); if(rc != memcached_success) { cout rlbytes : c->rbytes; if (c->ritem != c->rcurr) { memmove(c->ritem, c->rcurr, tocopy); } c->ritem += tocopy; c->rlbytes -= tocopy; c->rcurr += tocopy; c->rbytes -= tocopy; if (c->rlbytes == 0) { break; } } /* now try reading from the socket */ res = read(c->sfd, c->ritem, c->rlbytes); if (res > 0) { pthread_mutex_lock(&c->thread->stats.mutex); c->thread->stats.bytes_read += res; pthread_mutex_unlock(&c->thread->stats.mutex); if (c->rcurr == c->ritem) { c->rcurr += res; } c->ritem += res; c->rlbytes -= res; break; }

折腾了好久,在libmemcached的io_flush函数前后也打了不少时间戳,发现libmemcached发送数据是非常快的。突然灵感闪现,我想起来了tcp_nodelay这个参数,于是在libmemcached memcached_connect.c文件中的set_socket_options函数中增加了这个参数(事实上set_socket_options函数里面可以设置tcp_nodelay,没有仔细看)。

int flag = 1; int error = setsockopt(ptr->fd, ipproto_tcp, tcp_nodelay, (char *)&flag, sizeof(flag) ); if (error == -1) { printf("couldn't setsockopt(tcp_nodelay)n"); exit(-1); }else { printf("set setsockopt(tcp_nodelay)n"); }

在不改memcached_max_buffer的情况下,现在set 100kb的item也是一瞬间的事情了。不过新的困惑又出现了,nagle算法什么情况会起作用呢?为什么第一个包没被缓存,第二个包一定会被缓存呢?

libmemcached发送一个set命令是分成三部分的,首先是header(set 0 0 600 8192rn,共18个字节),然后是value(8192个字节),最后是’rn’(两个字节),一共是8212个字节。memcached在conn_read状态一共能读取2048+2048+4096+8196=16kb的数据,因此对于8kb的数据是完全可以在conn_read状态读完的。通过在conn_read状态处理的代码中增加下面的打印语句可以发现有些情况下,conn_read最后一次只读取了4个字节(正常情况应该是2048+2048+4096+20),剩下的16个字节放到conn_nread中读了。

res = read(c->sfd, c->rbuf + c->rbytes, avail); if (res > 0) { char buf[10240] = {0}; sprintf(buf, "%.*s", res, c->rbuf + c->rbytes); printf("avail=%d, read=%d, str=%sn", avail, res, buf);

未设置tcp_nodelay选项时,使用netstat可以看到客户端socket的send-q一直会维持在8214和8215之间。

tcp 0 8215 10.232.42.91:59836 10.232.42.91:11211 established 25800/t

设置tcp_nodelay选项时,客户端socket的send-q就一直为0了。

tcp 0 0 10.232.42.91:59890 10.232.42.91:11211 established 26554/t.quick

【说明】本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:)!