memcached

memcached是一个高性能的分布式内存对象缓存系统:前端

Memcached简介

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它经过在内存中缓存数据和对象来减小读取数据库的次数,从而提升动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,可是客户端能够用任何语言来编写,并经过memcached协议与守护进程通讯。node

为何用Memcached

网站的高并发读写需求,传统的数据库开始出现瓶颈python

单机Mysql时代

在90年代,一个网站的访问量通常都不大,用单个数据库彻底能够轻松应付。在那个时候,更多的都是静态网页,动态交互类型的网站很少。mysql

90年代的架构遇到的问题程序员

1.数据量的总大小 一个机器放不下时
2.数据的索引(B+ Tree)一个机器的内存放不下时
3.访问量(读写混合)一个实例不能承受web

Memcached(缓存)+MySQL+垂直拆分面试

随着访问量的上升,几乎大部分使用MySQL架构的网站在数据库上都开始出现了性能问题,web程序再也不仅仅专一在功能上,同时也在追求性能。程序员们开始大量的使用缓存技术来缓解数据库的压力,优化数据库的结构和索引。开始比较流行的是经过文件缓存来缓解数据库压力,可是当访问量继续增大的时候,多台web机器经过文件缓存不能共享,大量的小文件缓存也带了了比较高的IO压力。在这个时候,Memcached出现了。算法

Memcached做为一个独立的分布式的缓存服务器,为多个web服务器提供了一个共享的高性能缓存服务,在Memcached服务器上,又发展了根据hash算法来进行多台Memcached缓存服务的扩展,而后又出现了一致性hash来解决增长或减小缓存服务器致使从新hash带来的大量缓存失效的弊端sql

Mysql主从读写分离数据库

因为数据库的写入压力增长,Memcached只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提升读写性能和读库的可扩展性。Mysql的master-slave模式成为这个时候的网站标配了。

分表分库+水平拆分+mysql集群

在Memcached的高速缓存,MySQL的主从复制,读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,因为MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。

同时,开始流行使用分表分库来缓解写压力和数据增加的扩展问题。这个时候,分表分库成了一个热门技术,是面试的热门问题也是业界讨论的热门技术问题。也就在这个时候,MySQL推出了还不太稳定的表分区,这也给技术实力通常的公司带来了但愿。虽然MySQL推出了MySQL Cluster集群,但性能也不能很好知足互联网的要求,只是在高可靠性上提供了很是大的保证。

Mysql的拓展性能

MySQL数据库也常常存储一些大文本字段,致使数据库表很是的大,在作数据库恢复的时候就致使很是的慢,不容易快速恢复数据库。好比1000万4KB大小的文本就接近40GB的大小,若是能把这些数据从MySQL省去,MySQL将变得很是的小。关系数据库很强大,可是它并不能很好的应付全部的应用场景。MySQL的扩展性差(须要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySQL的开发人员面临的问题。

今天的架构

解答

多数的Web数据应用都保存到了关系型数据库中,如Mysq,Web服务器从中读取数据并在浏览器中显示.可是随着数据量的增大,访问的集中,关系型数据库性能出现瓶颈,响应速度慢致使网站打开延迟等问题,因此Memcached的主要的目的是经过自身内存中缓存关系型数据库查询的查询结果,减小数据库自身被访问的次数,以提升动态Web应用速度,提升网站架构的并发能力和拓展属性

经过事先规划好的系统内存空间中临时缓存数据库中的各类数据,已达到减小前端业务服务对关系型数据库的直接高并发访问,从而达到提高大规模数据集群中动态服务的并发访问能力.

Web服务器读取数据时先读Memcached服务器,若是Memcached没有.则向数据库请求数据.而后Web再报请求到的数据发送到Memcached.

Memcached 特征

协议简单

所以,经过telnet也能在memcached上保存数据、取得数据。下面是例子。

$ telnet localhost 11211
Trying 127.0.0.1
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
set foo 0 0 3 (保存命令)
bar (数据)
STORED (结果)
get foo (取得命令)
VALUE foo 0 3 (数据)
bar (数据)

 事件处理

libevent是个程序库,它将Linux的epoll、BSD类操做系统的kqueue等事件处理功能封装成统一的接口。即便对服务器的链接数增长,也能发挥O(1)的性能。memcached使用这个libevent库,
所以能在Linux、BSD、Solaris等操做系统上发挥其高性能。关于事件处理,能够参考Dan Kegel的The C10K Problem。

 内存存储方式

为了提升性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。因为数据仅存在于内存中,所以重启memcached、重启操做系统会致使所有数据消失。
另外,内容容量达到指定值以后,就基于LRU(Least Recently Used)算法自动删除不使用的缓存。memcached自己是为缓存而设计的服务器,所以并无过多考虑数据的永久性问题。

 Memcached 不互通讯的分布式

memcached尽管是“分布式”缓存服务器,但服务器端并无分布式功能。各个memcached不会互相通讯以共享信息。那么,怎样进行分布式呢?这彻底取决于客户端的实现。本文也将介绍memcached的分布式。

 

memcached的分布式

memcached的内存存储

最近的memcached默认的状况下采用了名为Slab Allocation的机制分配,在该机制出现以前,内存的分配经过对全部记录进行简单的malloc和free来进行的.可是这种方式会致使内存碎片,家中操做系统内存管理的负担,在最坏的状况下会致使操做系统memcached进程,Slab Allocation就是为了解决这个问题的

原理

将分配的内存分割成各类尺寸的块(chunk), 并把尺寸相同的块分红组(chunk的集合),每一个chunk集合被称为slab。

Slab Allocation能够重复使用已分配的内存的目的.分配到的内存不会被释放,而是被重复利用.

主要术语

Page

分配给Slab的内存空间,默认是1MB.会分配给Slab以后跟库slab的大小切分红chunk.

Chunk

用于缓存记录的内存空间

Slab Class

特定大小的chunk的组

选择存储记录的组的方法

缺点

因为分配的时特定长度的内存,所以没法又想利用分配的内存.好比将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费掉了

对于该问题目前尚未完美的解决方案,但在文档中记载了比较有效的解决方案。

The most efficient way to reduce the waste is to use a list of size classes that closely matches (if that’s at all possible) common sizes of objects that the clients of this particular installation of memcached are likely to store.

就是说,若是预先知道客户端发送的数据的公用大小,或者仅缓存大小相同的数据的状况下, 只要使用适合数据大小的组的列表,就能够减小浪费。

可是很遗憾,如今还不能进行任何调优,只能期待之后的版本了。 可是,咱们能够调节slab class的大小的差异。 接下来讲明growth factor选项。

使用Growth Factor进行调优

memcached在启动时指定 Growth Factor因子(经过-f选项), 就能够在某种程度上控制slab之间的差别。默认值为1.25。 可是,在该选项出现以前,这个因子曾经固定为2,称为“powers of 2”策略。

能够看到从从1字节开始组的大小增大为原来的2倍,这样设置的问题是slab之间的差异比较大,有些状况下就比较浪费内存,所以,为了减小内存浪费,两年前追加了growth facthor这个选项

从图中可见,组间的差距比2时小的多,更合适缓存几百字节的记录,从上面的输出结果来看,可能会有些计算偏差.这些偏差是为了保持字节数的对齐故意设置的.

将memcached引入产品,或是直接使用默认值进行部署时,最好是从新计算一下数据的预期平均长度,调整growth factor以得到恰当的长度,避免内存的浪费.

查看memcached的内部状态

首先开启memcached服务

其次链接服务

详细的信息能够参考memcached软件包内的protocol.txt

查看slabs的使用情况

参数的含义

含义
# slab class编号
Item_Size Chunk大小
Max_age LRU内最旧的记录生存时间
Pages 分配给Slab的页数
Count Slab内的记录数
Full? Slab内是否含有空闲chunk
Evicted 从LRU中移除未过时item的次数
Evict_Time 最后被移除缓存的时间,0表示当前就有被移除
OOM M参数

memcached的分布式

下面假设memcached有三台服务器node1-node3,保存的键名是”tokyo”,“kanagawa”,“chiba”,“saitma”,“gunma”

首先向memcached中添加“tokyo”,将“tokyo”传给客户端程序库后,客户端实现的算法就会根据”键”来决定保存数据的memcached服务器,服务器选定以后,命令他保存”totyo”及其值.一样的”kanagawa”,“chiba”,“saitma”,“gunma”都是先选择服务器再保存的.

接下来获取保存的数据,获取时也要获取的键”tokyo”传递给函数库.函数库经过与数据库保存相同的算法,根据”键”选择服务器.使用的算法相同,就能选中与保存相同的服务器,而后发送get命令.只要数据没有由于某些缘由被删除,就能得到保存的值.

这样不一样的键保存到不一样的不一样的不一样的服务器上,就实现memcached的分布式,memcached服务器增多后,键就会分散,即便一台memcached服务器发生故障没法连接,也不会影响其余的缓存,系统依旧可以继续运行.

算法实现

​ 首先求的字符串的CRC根据该值处于服务器节点数目获得的余数决定服务器,当选择的服务器没法链接的时候,Cache:Memcached将会连接次数添加到键以后,再次计算哈希值并尝试连接.这个动做叫作rehash.

use strict;
use warnings;
use String::CRC32;
my @nodes = @ARGV;
my @keys = (’a’..’z');
my %nodes;
foreach my $key ( @keys ) {
my $hash = crc32($key);
my $mod = $hash % ( $#nodes + 1 );
my $server = $nodes[ $mod ];
push @{ $nodes{ $server } }, $key;
}
foreach my $node ( sort keys %nodes ) {
printf “%s: %s\n”, $node, join “,”, @{ $nodes{$node} };

 

执行结果
tokyo       => node2
kanagawa => node3
chiba       => node2
saitama   =>node1
gunma     =>node1

 

求余算法缺点

添加或移除服务器时,缓存重组的代价至关巨大。 添加服务器后,余数就会产生巨变,这样就没法获取与保存时相同的服务器, 从而影响缓存的命中率。

Consistent Hashing算法

1)  首先求出memcached服务器(节点)的哈希值,并将其配置到0~232的圆(continuum)上。

 2)  而后用一样的方法求出存储数据的键的哈希值,并映射到圆上。 

 3)  而后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。若是超过232仍然找不到服务器,就会保存到第一台memcached服务器上。

 

Consistent Hashing:添加服务器

相关文章
相关标签/搜索