基本操作及路由算法

作者: 数据库信息  发布:2019-10-09

1. 什么是Memcached

    要了解Memcached首先要到官网上去看官方对它的描述。Memcached的官网网站是:,官方对Memcached的描述如下图:

图片 1

    从官方的描述中可以总结出,Memcached是一个高性能分布式的内存对象缓存系统。它将数据以key-value形式存储的存储在内存中,极大的提高了效率。但是Memcached的缺点在于不支持持久化(不支持写入磁盘),所以一旦断电,内存中的全部数据都会丢失。而Redis弥补了这个缺点,既在内存中存取数据,又支持持久化,所以Memcached可以理解为是Redis的前身,关于Redis的技术,后续会发新的文章论述,这里不展开讨论。

注:本篇博客参考于两本书。

2. Memcached基本原理和体系架构

 

  • 《memcached全面剖析》,该书籍市面上应该没有,我传到了百度云盘,链接如下:
  • 《大型网站技术架构:核心原理与案例分析》
    实际上,Memcached是在内存中维护一张巨大的Hash表。这张Hash表的结构是由多个slab组成,每个slab的大小是1M;每个slab中存在多个chunk,chunk是数据最终存储的单位。chunk采用预分配的方式提高性能,在保存数据之前,需要制定chunk的大小来分配内存。如add key *** 3

 

图片 2

图片 3

前提:

3. Memcached 集群

  • 本文是基于memcached1.4版本的,之前的版本与该版本在一些地方是不一样的(eg.《memcached全面剖析》的memcached1.2的内存管理方式就与1.4不同)
  • 在看本文之前,最好先看一下memcached在实际开发中怎么进行操作的,链接《第八章 企业项目开发--分布式缓存memcached》

 3.1 背景

    Memcached官方版本不支持集群搭建,Memcached彼此之间不进行通信,也就是把一个数据存到一个Memcached上,一旦这个Memcached宕掉了,不能从其它Memcached上读取这些数据,会造成数据丢失。

    但是,一个日本工程师改写了官方Memcached,使它能够支持集群。此时,Memcached之间可以进行通信,数据存储到一个Memcached实例上,可以同步到其它Memcached实例,防止数据丢失。

1、memcached特征

 

  • 协议简单(文本协议、二进制协议)
  • 基于libevent的事件处理,libevent封装了Linux的epoll模型的时间处理功能。
  • slab存储模型
  • 集群中服务器间互不通信(在大集群的情况下,其性能远超其他同步更新缓存的缓存器,当然小集群下,memcached的性能也十分优秀)

3.2 基本操作

 

 3.2.1 命令行

2、memcached访问模型

 

图片 4

(1) 启动并连接memcached

    图片 5

说明:

(2) 添加数据:set、add(当存在相同key值时,set会覆盖value,add会报错);获取数据:get

    图片 6

 

Xmemcached的具体使用代码查看"Java企业项目开发实践"系列博客的《第八章 企业项目开发--分布式缓存memcached》,下面的解释会依据该代码进行。

(2) 查看slab信息

在上图中,memcached客户端假设使用XMemcached

    图片 7
  • 服务器列表:在根pom.xml文件中进行了配置
  • 路由算法有两种:(可以在程序中指定)
    • 一致性hash算法(推荐)
    • 简单求余法
  • 通信模块:
    • 通信协议:TCP协议
    • 序列化协议:二进制协议(推荐)、文本协议
  • Memcached API(缓存的增删改查):在程序中编写
 3.2.2 JavaAPI

    1. 首先创建一个Java项目,然后添加memcached的jar包,如果网上找不到jar包的话可以在这个链接下载:

       2. 创建一个简单的Person信息类,用于存储到Memcached。

package com.nova;

import java.io.Serializable;
/**
 * 
 * @author Supernova
 * @date 2018/06/16
 * 
 */
public class Person implements Serializable{
    private String name;    //姓名
    private String sex;        //性别

    public Person() {

    }
    public Person(String name, String sex) {
        super();
        this.name = name;
        this.sex = sex;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }

}

 

        3. 添加、获取

package com.nova;

import java.net.InetSocketAddress;
import java.util.concurrent.Future;

import org.junit.Test;

import net.spy.memcached.MemcachedClient;
/**
 * 
 * @author Supernova
 * @date 2018/06/16
 *
 */
public class MemcachedOperation {
    /*
     * 向memcached添加数据
     */
    @Test
    public void addData() throws Exception {
        // 创建Memcached客户端
        MemcachedClient client = new MemcachedClient(new InetSocketAddress("192.168.243.11", 11211));
        // 插入数据
        Future<Boolean> future= client.set("name", 0, "Supernova");
        //判断执行操作后返回的Boolean值
        if(future.get().booleanValue()) {
            //插入成功

            client.shutdown();
        }
    }

    /*
     * 获取memcached数据
     */
    @Test
    public void getData() throws Exception{
        // 创建Memcached客户端
        MemcachedClient client = new MemcachedClient(new InetSocketAddress("192.168.243.11",11211));
        // 获取对应key值的value
        String name = client.get("name").toString();
        System.out.println(name);
    }
    /*
     * 向memcached存储一个对象
     */
    @Test
    public void insertObject() throws Exception{
        // 创建Memcached客户端
        MemcachedClient client = new MemcachedClient(new InetSocketAddress("192.168.243.11",11211));

        Person person = new Person("Supernova","man");
        // 插入对象
        Future<Boolean> future = client.set("person", 0, person);

        if(future.get().booleanValue()) {
            //插入成功

            client.shutdown();
        }
    }

}

 

整个流程:

3.2 路由算法

    既然Memcached实例可以有多个,那么当客户端发送一条数据的时候,这条数据要存储到哪个Memcached实例中?所以这就涉及到了Memcached路由算法,由它来决定数据最终存储在哪个Memcached上。注意:Memcached路由算法是由客户端实现的。在Memcached中有两种路由算法

应用程序(AdminService)调用Memcached API(假设为add操作),向memcached服务器添加缓存,这时候,程序会首先根据配置的路由算法(假设是一致性hash算法)在服务器列表中选出一台服务器(假设是node1),之后该API通过序列化协议序列化对象(当然,这个是可无的,eg.value是一个String),并通过TCP协议将将要存储的key-value对存入相应的服务器。在get时,只要采用的是与add时相同的hash算法,就会选中add时的那一台服务器。

 3.2.1 求余数

     【基本原理】将key做hash运算,对memcached数量进行求余数,根据余数来决定存储到哪个Memcached实例。

    如:有 4 台Memached,将对4进行求余数

        8%4 = 0

        7%4 = 3

        6%4 = 2

        5%4 = 1

        ……

      这样根据余数路由的优点在于,能够使数据均匀分布在每个Memcached上,但是也有很大的缺点,一旦某个Memcached宕机,或有新的memcached加入就会找不到数据,出现严重的数据丢失

    【数据丢失的原因】:

          比如原先有3个Memcached:1%3=1, 2%3=2, 3%3=0, 4%3=1,……

          新增之后为4个Memcached:1%4=1, 2%4=2, 3%4=2, 4%4=0,……

           原先3存在0号,4存在1号,但是新增后,3变成2号,4变成0号。导致了存取的目标位置不一样,在0号存,去2号取就会找不到数据。

看完这一段,流程明白了。但是有几点疑问:

3.2.2 一致性Hash

    一致性hash能够将丢失的数据减小到最小,但不能完全解决宕机造成的数据丢失。

    【基本原理】:

    如下图所示,数据分段在Memcached上存储,当扩容的时候,1~6666的数据将不受影响。同理,当有机器宕机的时候也一样。

        图片 8

 

  • 两种路由算法是怎样实现的?为什么使用一致性hash算法
  • 缓存到达服务器的时候究竟怎么存储?(slab内存模型)
  • 当缓存超过一定的容量后,缓存的自动删除是采用什么策略,怎样删除的?(LRU)
  • 两种序列化协议有什么优缺点?

 

3、hash算法

3.1、简单求余法

原理步骤:求得key的整数hash值(对于Java对象而言,直接使用其hashCode()方法就好),再除以服务器台数,获取余数,根据该余数选择服务器。

注意:如果选择的服务器无法连接时,会进行rehash,即:将连接次数添加到键中,重新计算hash值后,再重新连接。当然可以禁止rehash。

优点:

  • 简单
  • hash分散性好(因为hashCode()的值具有随机性)

缺点:

  • 添加或删除服务器的时候,缓存的获取就会出问题了(因为服务器台数变了,求余的时候分母变了,余数也就可能变了),假设在99台memcached服务器中又新添加而一台,则缓存的不命中率是99%,即n/(n 1),n表示原有的服务器。

注意:

  • 在XMemcached中仍保留了该算法
  • 适用于不需要考虑集群伸缩性的时候(即机器总数不变)

3.2、一致性hash算法

对于绝大部分系统,集群的伸缩性是五个非功能需求中比较重要的一个,也就是说必须克服"简单求余法"的缺点。

图片 9

  • 原理:先构造一个长度为0~232的整数环(使用二叉树构造),根据节点(memcached服务器)名称的hash值将缓存服务器节点放置在这个hash环上,然后根据需要缓存的数据的key来计算其hash值,然后在hash环上顺时针查找距离这个key的hash值最近的缓存服务器节点,完成key到服务器的hash映射查找。
    • 如果超过232还找不到,则存在第一台memcached上(依旧是顺时针)
  • 存在的问题:当服务器数量比较少的情况下,有可能造成负载不均衡的情况,为了防止这种情况的发生,使用将物理服务器先虚拟化成多台虚拟服务器,然后将这些虚拟服务器的hash值放在环上,当客户端路由到某台虚拟服务器上时,找到该虚拟服务器所对应的物理服务器即可。
    • 一般而言,一台物理服务器虚拟化为150台虚拟服务器最合适,太少会造成负载不均,太多会影响性能
  • Memcached采用这样的算法,在我们新加入服务器或集群中的某台服务器宕机时,都不会有太大的影响,只会影响一小段(见下图),确保了集群的可用性与伸缩性

图片 10

注意:

  • hash环是一个二叉树,最后边叶子与最左边相连成环
  • 整个缓存的查找过程就是找一个刚刚大于等于查找数的最小值

疑问:(这一点没查到资料)

  • 服务器的hash算法是怎样的
  • 计算缓存key的hash算法是否要与服务器的一致,还能不能使用原来的hashCode()

本文由金沙澳门官网发布于数据库信息,转载请注明出处:基本操作及路由算法

关键词: 金沙澳门官网