设为首页 加入收藏

TOP

深入学习Memcached
2015-11-21 01:37:16 来源: 作者: 【 】 浏览:0
Tags:深入 学习 Memcached

由于实验室在一个项目中用到了Memcached分布式缓存,自己这段时间也对分布式缓存深入学习了一下,本文就总结一下自己的收获,还是从Memcached是什么谈起吧。

Memcached是什么

Memcached是一款高性能的分布式内存对象缓存系统,使用它可以减少应用系统对数据库的直接访问,减轻了数据库负载,并且提升了应用程序的响应速度。可以将Memcached比作一个巨大的、存储了很多

LRU算法

操作系统的页面置换算法中也包括该算法,这种算法非常适合于缓存系统。它基于一种假设:过去一段时间使用频率最低的数据,将来也会很少使用。下面是我自己实现的一个基于LRU算法的缓存,它实现了基本的缓存功能,不过需要改进的一点是该缓存应该是单例的。

package colin.cache;

/**
 * 
 * @author Colin Wang
 * Created on Apr 18, 2015
 */
public class LRUCache {
    private static final int DEFAULT_MAX_SIZE = 10;
    private Object[] elements;
    private int size;

    public LRUCache(int maxSize) {
        elements = new Object[maxSize];
    }

    public LRUCache() {
        this(DEFAULT_MAX_SIZE);
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public int size() {
        return size;
    }

    public boolean isFull() {
        return size == elements.length;
    }

    /**
     * 返回元素在数组中的位置
     * 
     * @param element
     * @return
     */
    public int indexOf(Object element) {
        for (int i = 0; i < size; i++) {
            if (element.equals(elements[i])) {
                return i;
            }
        }
        return -1;
    }

    public Object push(Object element) {
        int index = -1;
        if (!isFull() && indexOf(element) == -1) {
            // 缓存未满,并且其中不含有待插入的元素
            elements[size++] = element;
        } else if (isFull() && indexOf(element) == -1) {
            // 缓存已满,并且其中不含有待插入的元素
            for (int i = 0; i < size - 1; i++) {
                elements[i] = elements[i + 1];
            }
            elements[size - 1] = element;
        } else {
            index = indexOf(element);
            for (int i = index; i < size - 1; i++) {
                elements[i] = elements[i + 1];
            }
            elements[size - 1] = element;
        }
        return index == -1 ? null : elements[index];
    }

    public void show() {
        for (int i = 0; i < size; i++) {
            System.out.print(elements[i].toString() + " ");
        }
    }
}

一致性哈希算法

该算法在分布式缓存系统中应用十分广泛,它的关键之处在于使用环形的哈希空间。首先我们先考虑一下JDK中HashMap的实现,我们知道,HashMap有一个初始容量和装载因子,当HashMap中元素的数量达到了初始容量*装载因子这么多时,HashMap就会进行扩容(变为原来的2倍)然后再哈希,当元素很多时,这种再哈希操作实际上是很消耗资源的。尽管HashMap使用了一种比较优化的方式,比如HashMap的大小总是为2的n次幂(默认大小为16),这样既减少了哈希碰撞的几率(因为2的n次幂-1转化为二进制时所有位均为1,这样就避免了某些位不能发挥作用),又增加了HashMap在定位元素时的效率,比如方法:

static int indexFor(int h, int length) {
    return h & (length-1);
}

当length总是2的n次方时,h & (length - 1)运算等价于对length取模。但是这些仍然不能完全弥补所有元素必须全部重新哈希的弱点。比如我们拥有N台缓存服务器,所有的热数据已经通过Hash算法映射到了这N台服务器上,这时候当其中一台缓存服务器挂掉,或者我们又新添了几台缓存服务器进来时,所有已经映射好的数据都将失效,而我们的后端数据库将会承受这一切!所以,一致性Hash算法就派上用场了,上面已经提到,一致性哈希算法使用的是环形的哈希空间,如下图所示:

环形哈希空间vcq9o6y1scbk1tDSu7j2u7q05rf+zvHG973htePKp9CnyrGjrLK7u+G1vNbCy/nT0LXEu7q05sr9vt22vMqn0KejrNKyvfa99tDo0qqw0dStwLSxu7u6tOa1vbjDveG148nPtcTK/b7dvMzQ+Lu6tOa1vc/C0ru49suzyrHV67e9z/LA68v81+69/LXEveG148nPvLS/yaGjtbHQwtT20ru49r3htePKsaOszazR+dKy1rvQ6NKqttS63MnZtcTSu7K/t9bK/b7dvfjQ0NTZuf7Po7Ki07PJ5LW90MK1xL3htePJz7y0v8mho86qwcux3MPis/bP1sr9vt231sXksru++dTItcTH6b/2o6yxyMjnvvi087bgyv21xMr9vt22vLG7u7q05rW9wcvSu7j2veG148nPo6y2+Mbky/u1xL3htePU8ru6tOa63MnZtcTK/b7do6zSu9bC0NS5/s+jy+O3qLu5zOGz9sHLPHN0cm9uZz7Q6cTiveG14zwvc3Ryb25nPrXEuMXE7qGjyOfPws28y/nKvqO6PC9wPgoKPHA+PGltZyBzcmM9"https://www.cppentry.com/upload_files/article/57/1_0qlto__.jpg" alt="加入虚拟结点" title="">

A1和A2为结点A的虚拟结点,虚拟结点的hash值计算可以采用对应结点的IP地址加数字后缀的方式,如“192.168.1.1#1”。这样就可以将被散列到A1和A2的数据都缓存进结点A中,从而避免了数据分布不平衡的现象。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇select from update row的实现 下一篇Spring集成Mybatis

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: