最近一段时间,我们的线上 server 发生了一个很诡异的现象:在访问 memcached 的时候, 某些情况下可能会获取到旧的数据,从而导致我们的 server 不能正常地返回 response 。 我们代码库中的 libmemcahed 是一个很低的版本:0.26,我们便想通过升级 libmecached 到最新 1.0.28 版本来尝试解决这个问题。

在集成 libmemcachd 之前,我们需要先在本地把它编译出来。因为我们不需要 sasl 的功能, 便在 config 的时候把它禁用掉了:

cd libmemcached-1.0.18
./configure --disable-sasl
make

有两种方式可以把 libmemcachd 集成进去:

直接链接静态库的方式集成

这需要先把头文件添加到系统搜索路径中,同时把之前编译好的 library (libmemcached-1.0.18/libmemcached/.libs/libmemcached.a) 静态库添加到代码库, 并加入到链接库参数中:

AM_CPPFLAGS += -isystem $(top_srcdir)/3rd/libmemcached

ads_LDADD += $(root_path)/3rd/3rd/libmemcached.a

集成 libmemcachd 代码

集成 libmemcachd 静态库的方式更简单,能够让我们快速地进行一些测试。 更优雅的集成方式还是集成进 libmemcachd 的代码,让它每次和我们的代码一起 build 。

首先我们需要把 libmemcachd 的代码复制到我们的代买库中,在复制之前需要用 make clean 清理下编译生成的中间文件。 同时,如果是在非 windows 环境下编译,且把 libmemcachd 通过 -isystem 方式加到搜索路径时,我们需要删除掉 poll.h 文件。

cp libmemcached-1.0.18/libmemcached 3rd/libmemcached
cp libmemcached-1.0.18/libhashkit-1.0/ 3rd/libmemcached
cp libmemcached-1.0.18/libmemcached-1.0/ 3rd/libmemcached
cp libmemcached-1.0.18/libmemcachedprotocol-0.0/ 3rd/libmemcached
cp libmemcached-1.0.18/libhashkit 3rd/libmemcached

为了防止文件名同名,我们需要把 libhashkit 目录下的文件重命名,加上目录名:zmv -W '*.cc' 'libhashkit_*.cc'。 在 3rd/libmemcached 中加入 Makefile.am 文件:

AM_CFLAGS = --std=c99 -D_POSIX_C_SOURCE
LIBMEMCACHED_ROOT = $(top_srcdir)/3rd/libmemcached
AM_CPPFLAGS = -I$(LIBMEMCACHED_ROOT) -I$(LIBMEMCACHED_ROOT)/libmemcached

LIBMEMCACHED_SOURCES = \
$(LIBMEMCACHED_ROOT)/libmemcached/csl/context.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/csl/parser.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/csl/scanner.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/instance.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/allocators.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/allocators.hpp \
$(LIBMEMCACHED_ROOT)/libmemcached/analyze.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/array.c \
$(LIBMEMCACHED_ROOT)/libmemcached/auto.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/backtrace.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/byteorder.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/callback.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/connect.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/delete.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/do.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/dump.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/error.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/exist.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/fetch.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/flag.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/flush.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/behavior.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/flush_buffers.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/get.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/hash.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/hash.hpp \
$(LIBMEMCACHED_ROOT)/libmemcached/hosts.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/initialize_query.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/io.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/key.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/memcached.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/encoding_key.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/namespace.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/options.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/parse.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/poll.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/purge.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/quit.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/quit.hpp \
$(LIBMEMCACHED_ROOT)/libmemcached/response.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/result.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/server.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/server_list.hpp \
$(LIBMEMCACHED_ROOT)/libmemcached/server_list.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/stats.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/storage.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/strerror.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/string.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/touch.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/udp.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/verbosity.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/version.cc \
$(LIBMEMCACHED_ROOT)/libmemcached/virtual_bucket.c \
$(LIBMEMCACHED_ROOT)/libmemcached/sasl.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_aes.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_algorithm.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_behavior.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_crc32.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_digest.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_encrypt.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_fnv_32.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_fnv_64.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_function.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_has.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_hashkit.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_hsieh.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_jenkins.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_ketama.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_md5.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_murmur.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_murmur3.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_murmur3_api.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_nohsieh.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_one_at_a_time.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_rijndael.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_str_algorithm.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_strerror.cc \
$(LIBMEMCACHED_ROOT)/libhashkit/libhashkit_string.cc

noinst_LIBRARIES = libmemcached.a

libmemcached_a_SOURCES = $(LIBMEMCACHED_SOURCES)

CFLAGS += -Wno-pointer-bool-conversion -Wno-self-assign

同时把 libmemcachd 的 Makefile 加到 configure.ac 文件中:

AC_CONFIG_FILES([ 3rd/libmemcached/Makefile ])

遇到的一些坑

禁用 sasl 的问题

最开始编译的时候没有加 --disable-sasl,导致编译的时候一直提示 sasl 相关的库找不到。 加上这个编译参数之后会在文件 libmemcached-1.0.18/libmemcached-1.0/configure.h 里添加下面的宏:

#define LIBMEMCACHED_WITH_SASL_SUPPORT 0

注意一定要复制正确的 configure.h 文件到到代码库中!

poll.h 的问题

刚开始一直会提示 ‘POLLIN’ 之类的变量找不到的问题,检查 libmemcachd 里的 poll.h 文件中是有这个变量的定义的。 再仔细看才发现这个文件定义的变量只有在 windows 下才会生效。

而且因为我们用 -isystem 把 libmemcachd 目录加了进去,导致编译的时候会用 limcached 里的 poll.h 替换了系统中的这个文件, 但 libmemcachd 的 poll.h 文件在 linux 下又是无效的,从而会导致 ‘POLLIN’ 找不到之类的编译错误。我们把 poll.h 这个文件从 libmemcachd 中删除就可以解决这个问题。