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才设计的高可用方案。但总的来讲, 两种缓存都是非常可靠的, 只要对其足够了解, 都可以满足日常的需求