Memcached是一个自由开源的,高性能,分布式内存对象缓存系统。
Memcached是以LiveJournal旗下Danga Interactive公司的Brad Fitzpatric为首开发的一款软件。现在已成为mixi、hatena、Facebook、Vox、LiveJournal等众多服务中提高Web应用扩展性的重要因素。
Memcached是一种基于内存的key-value存储,用来存储小块的任意数据(字符串、对象)。这些数据可以是数据库调用、API调用或者是页面渲染的结果。
Memcached简洁而强大。它的简洁设计便于快速开发,减轻开发难度,解决了大数据量缓存的很多问题。它的API兼容大部分流行的开发语言。
本质上,它是一个简洁的key-value存储系统。
一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。
Memcached 官网:https://memcached.org/
我们都知道,把一些热数据存到缓存中可以极大的提高速度,那么问题来了,是用Redis好还是 Memcached好呢,以下是它们两者之间一些简单的区别与比较:
RDB是一个非常紧凑(compact)的文件,它保存了redis 在某个时间点上的数据集。这种文件 非常适合用于进 行备份和灾难恢复。 RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创 建子进程,属于 重量级操作(内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑),频繁 执行成本过高(影响性能) RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版 本Redis服务无 法兼容新版RDB格式的问题(版本不兼容) 在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所 有修改(数据有 丢失)
AOF 文件的格式可读性较强,这也为使用者提供了更灵活的处理方式。
对于具有相同数据的的 Redis,AOF 文件通常会比 RDF 文件体积更大。 虽然 AOF 提供了多种同步的频率,默认情况下,每秒同步一次的频率也具有较高的性能。但 在 Redis 的负载 较高时,RDB 比 AOF 具好更好的性能保证。 RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF 文件中,因此从 理论上说,RDB 比 AOF 方式更健壮。官方文档也指出,AOF 的确也存在一 些 BUG,这些 BUG 在 RDB 没有 存在。
- AOF持久化开启且存在AOF文件时,优先加载AOF文件
- AOF关闭或者AOF文件不存在时,加载RDB文件
- 加载AOF/RDB文件成功后,Redis启动成功。
- AOF/RDB文件存在错误时,Redis启动失败并打印错误信息。
守护进程(daemon)是一类在后台运行的特殊进程,用于执行特定的系统任务。很多守护进程在系统引导的时候启动,并且一直运行直到系统关闭。另一些只在需要的时候才启动,完成任务后就自动结束。
会随着主进程的结束而结束
主进程创建守护进程
# 下载相关依赖软件包
[root@server1 ~]# yum install libevent libevent-devel -y
# 下载memcached
[root@server1 ~]# yum install memcached -y
使用memcached命令管理服务,相关参数介绍
启动memcached服务
[root@server1 ~]# memcached -d -m 1024 -u memcached -l 127.0.0.1 -p 11211 -c
1024 -P /tmp/memcached.pid
[root@server1 ~]# yum install telnet -y
[root@server1 ~]# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
set name 0 0 8 #保存命令
zhangsan #数据
STORED
get name #查询数据
VALUE foo 0 8
zhangsan
END
quit 退出
Connection closed by foreign host.
[root@server1 ~]# pkill memcached
[root@server1 ~]# ss -tuan | grep 11211
item数据存储节点主要用于存储数据
typedef struct _stritem {
/* Protected by LRU locks */
//一个item的地址, 主要用于LRU链和freelist链
struct _stritem *next;
//下一个item的地址,主要用于LRU链和freelist链
struct _stritem *prev;
/* Rest are protected by an item lock */
//用于记录哈希表槽中下一个item节点的地址
struct _stritem *h_next; /* hash chain next */
//最近访问时间
rel_time_t time; /* least recent access */
//缓存过期时间
rel_time_t exptime; /* expire time */
int nbytes; /* size of data */
//当前item被引用的次数,用于判断item是否被其它的线程在操作中
//refcount == 1的情况下该节点才可以被删除
unsigned short refcount;
uint8_t nsuffix; /* length of flags-and-length string */
uint8_t it_flags; /* ITEM_* above */
//记录该item节点位于哪个slabclass_t中
uint8_t slabs_clsid;/* which slab class we're in */
uint8_t nkey; /* key length, w/terminating null and padding */
/* this odd type prevents type-punning issues when we do
* the little shuffle to save space when not using CAS. */
union {
uint64_t cas;
char end;
} data[];
/* if it_flags & ITEM_CAS we have 8 bytes CAS */
/* then null-terminated key */
/* then " flags length\r\n" (no terminating null) */
/* then data with terminating \r\n (no terminating null; it's binary!) */
} item;
slab是一块内存空间,默认大小为1M,memcached会把一个slab分割成一个个chunk, 这些被切割的小的内存块,主要用来存储item
每个item的大小都可能不一样,item存储于chunk,如果chunk大小不够,则不足以分配给item使用,如果chunk过大,则太过于浪费内存空间。因此memcached采取的做法是,将slab切割成不同大小的chunk,这样就满足了不同大小item的存储。被划分不同大小chunk的slab的内存在memcached就是用slabclass这个结构体来表现的
typedef struct {
//chunk大小
unsigned int size; /* sizes of items */
//1M内存大小被分割为多少个chunck
unsigned int perslab; /* how many items per slab */
//空闲chunk链表
void *slots; /* list of item ptrs */
//空闲chunk的个数
unsigned int sl_curr; /* total free items in list */
//当前slabclass已经分配了所少个1M空间的slab
unsigned int slabs; /* how many slabs were allocated for this class */
//slab指针数组
void **slab_list; /* array of slab pointers */
//slab指针数组的大小
unsigned int list_size; /* size of prev array */
size_t requested; /* The number of requested bytes */
} slabclass_t;
slab_class结构示意图
- slabclass数组初始化的时候,每个slabclass_t都会分配一个1M大小的slab,slab会被切分为N个小的内存块,这个小的内存块的大小取决于slabclass_t结构上的size的大小
- 每个slabclass_t都只存储一定大小范围的数据,并且下一个slabclass切割的chunk块大于前一个slabclass切割的chunk块大小
- memcached中slabclass数组默认大小为64,slabclass切割块大小的增长因子默认是1.25
例如:slabclass[1]切割的chunk块大小为100字节,slabclass[2]为125,如果需要存储一个110字节的缓存,那么就需要到slabclass[2] 的空闲链表中获取一个空闲节点进行存储
释放一个item节点,并不会free内存空间,而是将item节点归还到slabclass的空闲列表中
set key flags exptime bytes [noreply]
value
参数说明如下:
示例:
set name 0 900 8
zhangsan
STORED
get name
VALUE name 0 8
zhangsan
END
Memcached add 命令用于将 value(数据值) 存储在不存在的 key(键) 中。 如果 add 的 key 已经存在,则不会更新数据(过期的 key 会更新),之前的值将仍然保持相同,并且您将获得响应 NOT_STORED。
add key flags exptime bytes [noreply]
value
Memcached replace 命令用于替换已存在的 key(键) 的 value(数据值)。 如果 key 不存在,则替换失败,并且您将获得响应 NOT_STORED。
replace key flags exptime bytes [noreply]
value
Memcached append 命令用于向已存在 key(键) 的 value(数据值) 后面追加数据 。
append key flags exptime bytes [noreply]
value
示例
set key1 0 900 9
memcached
STORED
get key1
VALUE key1 0 9
memcached
END
append key1 0 900 5
redis
STORED
get key1
VALUE key1 0 14
memcachedredis
END
Memcached prepend 命令用于向已存在 key(键) 的 value(数据值) 前面追加数据 。
Memcached CAS(Check-And-Set 或 Compare-And-Swap) 命令用于执行一个"检查并设置"的操作
它仅在当前客户端最后一次取值后,该key 对应的值没有被其他客户端修改的情况下, 才能够将值写 入。
检查是通过cas_token参数进行的, 这个参数是Memcach指定给已经存在的元素的一个唯一的64位值。
cas key flags exptime bytes unique_cas_token [noreply]
value
# unique_cas_token:通过 gets 命令获取的一个唯一的64位值。
示例
gets tp
VALUE tp 0 9 1
memcached
END
cas tp 0 900 5 1
redis
STORED
get tp
VALUE tp 0 5
redis
END
输出信息说明:
get key
get key1 key2 key3
Memcached gets 命令获取带有 CAS 令牌存 的 value(数据值) ,如果 key 不存在,则返回空。
gets 命令的基本语法格式如下:
gets key
gets key1 key2 key3
Memcached delete 命令用于删除已存在的 key(键)。
delete key [noreply]
Memcached incr 与 decr 命令用于对已存在的 key(键) 的数字值进行自增或自减操作。
incr 与 decr 命令操作的数据必须是十进制的32位无符号整数。
如果 key 不存在返回 NOT_FOUND,如果键的值不为数字,则返回 CLIENT_ERROR,其他错误返回 ERROR。
incr 命令的基本语法格式如下:
incr key increment_value # 自增
decr key decrement_value # 自减
# increment_value: 增加的数值。
Memcached stats 命令用于返回统计信息例如 PID(进程号)、版本号、连接数等。
stats
stats
STAT pid 1162
STAT uptime 5022
STAT time 1415208270
STAT version 1.4.14
STAT libevent 2.0.19-stable
STAT pointer_size 64
STAT rusage_user 0.096006
STAT rusage_system 0.152009
STAT curr_connections 5
STAT total_connections 6
STAT connection_structures 6
STAT reserved_fds 20
STAT cmd_get 6
STAT cmd_set 4
STAT cmd_flush 0
STAT cmd_touch 0
STAT get_hits 4
STAT get_misses 2
STAT delete_misses 1
STAT delete_hits 1
STAT incr_misses 2
STAT incr_hits 1
STAT decr_misses 0
STAT decr_hits 1
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT touch_hits 0
STAT touch_misses 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 262
STAT bytes_written 313
STAT limit_maxbytes 67108864
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT threads 4
STAT conn_yields 0
STAT hash_power_level 16
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT expired_unfetched 1
STAT evicted_unfetched 0
STAT bytes 142
STAT curr_items 2
STAT total_items 6
STAT evictions 0
STAT reclaimed 1
END
这里显示了很多状态信息,下边详细解释每个状态项:
Memcached stats items 命令用于显示各个 slab 中 item 的数目和存储时长(最后一次访问距离现在的秒数)。
语法
stats items
STAT items:1:number 1
STAT items:1:age 7
STAT items:1:evicted 0
STAT items:1:evicted_nonzero 0
STAT items:1:evicted_time 0
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0
STAT items:1:reclaimed 0
STAT items:1:expired_unfetched 0
STAT items:1:evicted_unfetched 0
END
Memcached stats slabs 命令用于显示各个slab的信息,包括chunk的大小、数目、使用情况等。
语法
stats slabs
STAT 1:chunk_size 96
STAT 1:chunks_per_page 10922
STAT 1:total_pages 1
STAT 1:total_chunks 10922
STAT 1:used_chunks 1
STAT 1:free_chunks 10921
STAT 1:free_chunks_end 0
STAT 1:mem_requested 71
STAT 1:get_hits 0
STAT 1:cmd_set 1
STAT 1:delete_hits 0
STAT 1:incr_hits 0
STAT 1:decr_hits 0
STAT 1:cas_hits 0
STAT 1:cas_badval 0
STAT 1:touch_hits 0
STAT active_slabs 1
STAT total_malloced 1048512
END
Memcached stats sizes 命令用于显示所有item的大小和个数。
该信息返回两列,第一列是 item 的大小,第二列是 item 的个数。
语法:
stats sizes
STAT 96 1
END
Memcached flush_all 命令用于清理缓存中的所有 key=>value(键=>值) 对。
该命令提供了一个可选参数 time,用于在制定的时间后执行清理缓存操作。
语法:
flush_all [time] [noreply]
示例:
set runoob 0 900 9
memcached
STORED
get runoob
VALUE runoob 0 9
memcached
END
flush_all
OK
get runoob
END