分布式基于内存的缓存服务Memcached

一: memcached介绍

memcached是一个分布式的基于内存的缓存服务器,我们一般用memcached来减轻数据库的负载,提高程序的响应速度。

memcahched采用key-value存储数据,将对象序列化成二进制,以便在网络中进行传输。

二: Linux安装

memcached是基于libevent库的,所以要先安装libevent,然后在安装memcached,主要的几步操作如下:

tar -zxvf  memcached-1.4.25.tar.gz

cd

./configure

make

make install

安装好后,启动memcached服务 ./memcached -d -m 1024 -p 10000 -u root -P /tmp/memcached.pid

查看服务是否启动:ps -ef | grep 10000

分布式基于内存的缓存服务Memcached

三:memached的工作机制

3.1 memcached的内存存储

memcached是一个基于内存的高性能的缓存服务器,为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启服务器、重启操作系统等都会导致数据丢失。

memcached目前采用的是Slab Allocator来管理内存,它的原理非常简单,根据我们约定好的块大小,预先将分配的内存分成各个块,并将大小一样的块分成各个组。

当客户端有一个add或者set操作往缓存里存数据的时候,memcached根据添加的数据大小选择合适的某个slab。

分布式基于内存的缓存服务Memcached

1、memcached将内存空间分为一组slab

2、每个page里面包含一组chunk,chunk是真正存放数据的地方,同一个slab里面的chunk的大小是固定的。如果key不和chunk相 匹配,会有一定的内存浪费。但是不会存在内存碎片,我们可以通过在启动服务时-f来减低每个chunk之间的大小差,以便更合理的利用内存

3、相同大小chunk的slab被组织在一起,称为slab_class.

3.2 memcached的缓存过期

在往缓存里面添加数据的时候,可以指定一个expire,表示该数据的过期时间,单位是s,但是由于memecached不会释放已经分配的内存,当我们往缓存里面添加数据的时候,可能会内存空间不足,这个时候memecached就需要择优选择一块可用的内存来存储我们的数据。

memcached使用的是LRU的方式来释放内存,即最近最少使用的内存将优先被用来存新的数据。

memcached采用的是偷懒机制,当某个key过期后,并不会马上释放内存,而是等待下次有get请求到来时,如果发现该key已经过期了才会删除,而且其实memcached内部在很多情况下都会判断某个key是否失效,比如当我们重新set一个新的数据时,这个时候memcached需要重新申请一个item来存储咱们的数据,它会首先判断咱们请求的大小然后选择相应的slab放到里面,在这个地方,它在循环slab里面的item的时候实际上已经对每个item进行了判断是否过期,如果过期了,那么就直接使用这个item了。

3.3 memcahced如何实现分布式

一般的分布式系统,都是在服务器端实现的分布式,但是memcached却不是,由于各个memcached服务器之间不存在主备关系,也没有互相通信,所以memcached的分布式是在客户端实现的。

当我们缓存一个key,value的数据时,客户端首先根据一致性hash算法根据key来决定哪个服务器保存该数据。这个地方的原理很简单,将各个服务器节点的哈希值映射到一个圆上,然后将算出的key的哈希值也映射到圆上,然后顺时针查找第一台服务器,找到了就将该key对应的value存到这台服务器上,如果顺时针查找完还没有找到对应的服务器,则选择第一台服务器保存value值。

当我们下次有get请求来的时候,采用同样算法计算key对应的哈希值,就能找到存储该value的服务器了。

3.4 memcached的二阶段Hash

当我们往缓存里面写入一个数据的时候,memecached会首先根据key算出对应的hash值,找到对应的服务器编号,这是第一个hash,当我们确定好对应的服务器编号之后,memcached通过socket在memcached集群里面找到对应的memcached服务器,将我们的数据写入到服务器chunk中,这是第二个hash。同理,当我们get数据的时候,第一个hash采用相同的算法算出key对应的hash值,自然能找到对应的服务器获取缓存的数据

这个地方需要注意的是memecached采用的是一致性hash算法,而不是传统的余数hash。

一致性Hash算法通过一个叫做一致性Hash环的数据结构实现Key到缓存服务器的Hash映射:下面是一个草图

分布式基于内存的缓存服务Memcached

根据各个服务器节点名称的Hash值将缓存服务器节点放置在这个Hash环上,然后根据需要缓存的数据的Key值计算得到其Hash值,然后在Hash环上顺时针查找这个Key值的Hash值最近的服务器节点,完成Key到服务器的映射,然后保存value即可。

四:Java客户端简单操作实现

工具类:

package com.memcached.util;

import java.util.Date;
import java.util.Map;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;

/**
 * memcached的基本操作类的封装
 *
 * @author tanjie
 *
 */
public class MemcachedUtil {

private MemcachedUtil() {

}

private static MemCachedClient memCachedClient = new MemCachedClient();

private static MemcachedUtil memcachedUtil = new MemcachedUtil();
 

/**
  * 设置与缓存服务器的连接池
  */
 static {

String[] servers = { "192.168.8.88:10000" };// Ip地址和端口号
  // 权重
  Integer[] weights = { 3 };

// 获取socket连接池的实例对象
  SockIOPool pool = SockIOPool.getInstance();

pool.setServers(servers);
 
  //设置连接池可用cache服务器的权重,和server数组的位置一一对应
  pool.setWeights(weights);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/2e38b793fc0289a2bbad548e1d57083c.html