Iawen's Blog

我喜欢这样自由的随手涂鸦,因为我喜欢风......

Memcache与Redis操作

一. Memcached

1. 安装

yum install libevent-devel
wget http://memcached.org/latest
tar -zxvf memcached-1.x.x.tar.gz
cd memcached-1.x.x
./configure --prefix=/usr/local/memcached
make && make test && sudo make install

/usr/local/memcached/bin/memcached -d -m 10 -u root -l 127.0.0.1 -p 11211 -c 256 -P /tmp/memcached.pid

2. 参数说明

A. 运行参数:
  • -d:以守护进程方式启动
  • -u root:运行Memcached的用户
  • -P/tmp/a.pid:保存Memcached进程的pid文件
B. 内存设置:
  • -m 1024:数据内在数量,不包含Memcached本身,单位MB,(默认是64MB)
  • -M:内存不够时禁止LRU,报错(是在Slab范围内,而不是全局)
  • -n 48:初始chunk = key + suffix + value +32 结构体,默认48字节
  • -f 1.25:增长因子,默认1.25
  • -L:启用大内存, 可以降低内存浪费,改进性能
C. 连接设置:
  • -l 127.0.0.1:监听的IP地址,本机可以不设置此参数
  • -p 11211:TCP端口,可以不设置
  • -U 11211:UDP端口,0为关闭
D. 并发设置:
  • -c 1024:最大同时连接数,默认1024
  • -t 4:线程数,默认4,由于Memcached采用NIO,并非线程越多越好,一般线程数和CPU核数一致。
  • -R 20:每个event连接最大并发数,默认20
  • -C:禁用CAS命令(可以禁止版本计数,减少开销)

3. 操作

标准命令结构: command <key> <flags> <expiration time> <bytes> <value>

  • command:set/add/replace/get/delete
  • key:内部限制不能大于250个字符:#define KEY_MAX_LENGTH 250
  • flags:客户端用来标识数据格式,如JSON、XML、是否压缩等,即数据序列化格式
  • expiration time:存活时间,单位为s, 0为不过期
  • bytes:存储的字节数,比如value为1234, 则bytes便为4
  • value:存储的值
A. cmd上登录memcache

telnet 127.0.0.1 11211

B. 列出所有keys
stats items // 这条是命令
STAT items:7:number 1 
STAT items:7:age 188
END
C. 通过itemid获取key

接下来基于列出的items id,本例中为7,第2个参数为列出的长度,0为全部列出

stats cachedump 7 0 // 这条是命令
ITEM Sess_sidsvpc1473t1np08qnkvhf6j2 [183 b; 1394527347 s]
END
D. 通过get获取key值

上面的stats cachedump命令列出了我的session key,接下来就用get命令查找对应的session值

get Sess_sidsvpc1473t1np08qnkvhf6j2 //这条是命令
VALUE
Sess_sidsvpc1473t1np08qnkvhf6j2 1440 1
83
Sess_|a:5:{s:6:"verify";s:32:"e70981fd305170c41a5632b2a24bbcaa";s:3:"uid";s:1:"1
";s:8:"username";s:5:"admin";s:9:"logintime";s:19:"2014-03-11 16:24:25";s:7:"log
inip";s:9:"127.0.0.1";}
4. 性能分析

命中率=get_hits / (get_hits + get_misses)

二. Redis

1. 安装

wget http://download.redis.io/releases/redis-4.0.1.tar.gz
make install 
cd utils 
./install_server
#设置redis的密码:
#找到# requirepass foobared 改为 requirepass 我的密码 ,本机测试可不设置。
redis-server --service-install redis.windows.conf --loglevel verbose
Selected config:
Port : 6379
Config file : /etc/redis/6379.conf
Log file : /var/log/redis_6379.log
Data dir : /data/redis/6379
Executable : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli

2. twemproxy (nutcracker)

git clone git@github.com:twitter/twemproxy.git
cd twemproxy
autoreconf -fvi
./configure --enable-debug=full
make
src/nutcracker -h

三. 选redis还是memcache,源码怎么说?

memcache和redis是互联网分层架构中,最常用的KV缓存。不少同学在选型的时候会纠结,到底是选择memcache还是redis。 画外音:不鼓励粗暴的实践,例如“memcache提供的功能是redis提供的功能的子集,不用想太多,选redis准没错”。

虽然redis比memcache更晚出来,且功能确实也更丰富,但对于一个技术人,了解“所以然”恐怕比“选择谁”更重要一些。

1. 什么时候倾向于选择redis?

业务需求决定技术选型,当业务有这样一些特点的时候,选择redis会更加适合。

A. 复杂数据结构

value是哈希,列表,集合,有序集合这类复杂的数据结构时,会选择redis,因为mc无法满足这些需求。 最典型的场景,用户订单列表,用户消息,帖子评论列表等。

B. 持久化

mc无法满足持久化的需求,只得选择redis。 但是,这里要提醒的是,真的使用对了redis的持久化功能么?

千万不要把redis当作数据库用: redis的定期快照不能保证数据不丢失 redis的AOF会降低效率,并且不能支持太大的数据量 不要期望redis做固化存储会比mysql做得好,不同的工具做各自擅长的事情,把redis当作数据库用,这样的设计八成是错误的。

C. 缓存场景,开启固化功能,有什么利弊?

如果只是缓存场景,数据存放在数据库,缓存在redis,此时如果开启固化功能: 优点是,redis挂了再重启,内存里能够快速恢复热数据,不会瞬时将压力压到数据库上,没有一个cache预热的过程。 缺点是,在redis挂了的过程中,如果数据库中有数据的修改,可能导致redis重启后,数据库与redis的数据不一致。

因此,只读场景,或者允许一些不一致的业务场景,可以尝试开启redis的固化功能。

D. 天然高可用

redis天然支持集群功能,可以实现主动复制,读写分离。 redis官方也提供了sentinel集群管理工具,能够实现主从服务监控,故障自动转移,这一切,对于客户端都是透明的,无需程序改动,也无需人工介入。

而memcache,要想要实现高可用,需要进行二次开发,例如客户端的双读双写,或者服务端的集群同步。

但是,这里要提醒的是,大部分业务场景,缓存真的需要高可用么? 缓存场景,很多时候,是允许cache miss 缓存挂了,很多时候可以通过DB读取数据 所以,需要认真剖析业务场景,高可用,是否真的是对缓存的主要需求? 画外音:即时通讯业务中,用户的在线状态,就有高可用需求。

E. 存储的内容比较大

memcache的value存储,最大为1M,如果存储的value很大,只能使用redis。

2. 什么时候倾向于memcache?

纯KV,数据量非常大,并发量非常大的业务,使用memcache或许更适合。 这要从mc与redis的底层实现机制差异说起。

A. 内存分配

memcache使用预分配内存池的方式管理内存,能够省去内存分配时间。 redis则是临时申请空间,可能导致碎片。 从这一点上,mc会更快一些。

B. 虚拟内存使用

memcache把所有的数据存储在物理内存里。 redis有自己的VM机制,理论上能够存储比物理内存更多的数据,当数据超量时,会引发swap,把冷数据刷到磁盘上。 从这一点上,数据量大时,mc会更快一些。

C. 网络模型

memcache使用非阻塞IO复用模型,redis也是使用非阻塞IO复用模型。 但由于redis还提供一些非KV存储之外的排序,聚合功能,在执行这些功能时,复杂的CPU计算,会阻塞整个IO调度。 从这一点上,由于redis提供的功能较多,mc会更快一些。

D. 线程模型

memcache使用多线程,主线程监听,worker子线程接受请求,执行读写,这个过程中,可能存在锁冲突。 redis使用单线程,虽无锁冲突,但难以利用多核的特性提升整体吞吐量。 从这一点上,mc会快一些。

3. 最后说两点

A. 代码可读性,代码质量

看过mc和redis的代码,从可读性上说,redis是我见过代码最清爽的软件,甚至没有之一,或许简单是redis设计的初衷,编译redis甚至不需要configure,不需要依赖第三方库,一个make就搞定了。

而memcache,可能是考虑了太多的扩展性,多系统的兼容性,代码不清爽,看起来费劲。 例如网络IO的部分,redis源码1-2个文件就搞定了,mc使用了libevent,一个fd传过来传过去,又pipe又线程传递的,特别容易把人绕晕。 画外音:理论上,mc只支持kv,而redis支持了这么多功能,mc性能应该高非常多非常多,但实际并非如此,真的可能和代码质量有关。

B. 水平扩展的支持

不管是mc和redis,服务端集群没有天然支持水平扩展,需要在客户端进行分片,这其实对调用方并不友好。如果能服务端集群能够支持水平扩展,会更完美一些。

4. 其他

mc的核心就是内存管理,因为mc不会产生内存碎片,所以会极其稳定,除非机器故障mc几乎不会崩溃。因此作者就没有考虑过主从或反序列化。但是mc还是要做分片的。redis很取巧的使用单线程的IO复用模型,因此不用考虑多线程的各种问题,所以才会很轻松的支持各种数据类型。带来的问题就是cpu无法用满,如果计算复杂的话,redis性能会降低。redis用的jemalloc理念和mc管理内存的方式类似,但毕竟是通用内存管理器,还是会产生内存碎片。长时间运行的redis实际使用的内存会超过最大内存,从而导致系统不稳定,甚至崩溃。所以redis才设计的高可用方案。但总的来讲,两种缓存都是非常可靠的,只要对其足够了解,都可以满足日常的需求