zoukankan      html  css  js  c++  java
  • NoSQL之Memcached

    一、Memcached概念

    MemcachedNoSQL产品之中的一个,是一个暂时性键值存储NoSQL数据库,过去被大量使用在互联网站点中,作为应用和数据库之间的缓存层,大大提高查询和訪问速度。

    Memcached有下面特点:

    1、全内存运转:数据从来不保存在硬盘中。机器一重新启动,数据就所有没有了,所有又称暂时性数据库;

    2、哈希方式存储:

    3、简单文本协议进行数据通信:不须要特定二进制代码,仅仅须要用telnet连通memcached的监听port,打入简单浅显的代码就能操作;

    4、仅仅操作字符型数据:不管往memcached放入什么。都是以字节的方式来处理。

    还原成数组、哈希表、字符串和数值等都交给应用层来解释。应用读写memcached的数据时,进行序列化和反序列化。把其解释成应用所能理解的数据类型。

    5、集群也由应用进行控制,採用一致性散列(哈希)算法。

    二、安装Memcached

    1、在linux上搭建yum环境

    2、使用yum命令进行安装Memcachedrpm

    [root@nn init.d]# yum install memcached

     

    3、启动Memcached

    首先要cd到对应文件夹

    [root@nn ~]# cd /etc/rc.d/init.d/

    执行memcached安装脚本

    [root@nn init.d]# ./memcached start

     

    4、查看Memcached是否启动

    [root@nn init.d]# pstree

     

    表示Memcached进程被启动了,以下开了5个线程

    或者使用[root@nn init.d]# ps aux命令

     

    memcached -d -p 11211 -u memcached -m 64 -c 1024 -P /var/run/memcached/memcached.pid

    -d表示程序要后台化执行,-p指定port。-u表示用memcached这个身份来执行,后面的都是memcached的控制參数

    5、连接Memcached

    [root@nn init.d]# telnet localhost 11211

     

    三、Memcached经常使用命令

    命令格式:

    <command name> <key> <flags> <exptime> <bytes>

    <data block>

    參数说明例如以下:

    <command name>

    set/add/replace

    <key>

    查找keyword

    <flags>

    客户机使用它存储关于键值对的额外信息。用于指定是否压缩,0不压缩,1压缩

    <exptime>

    该数据的存活时间,0表示永远

    <bytes>

    存储字节数

    <data block>

    存储的数据块(可直接理解为key-value结构中的value

    1、添加:setaddcas

    2、获取:getgets、 

    3、追加:appendprepend

    4、删除:delete

    5、清除全部:flush_all

    6、加减:incrdecr

    7、退出:quit

     

    三、用java连接Memcached

    眼下java提供了三种API供我们实现与Memcached的连接和存取

    1memcached client for java

    较早推出的memcached JAVAclientAPI,应用广泛,执行比較稳定。

    2pymemcached

    A simple, asynchronous, single-threaded memcached client written in java. 支持异步。单线程的memcached客户端,用到了java1.5版本号的concurrentnio,存取速度会高于前者,可是稳定性不好,測试中常报timeOut等相关异常。

    3xmemcached

    XMemcached相同是基于java nio的client。java nio相比于传统堵塞io模型来说,有效率高(特别在高并发下)和资源耗费相对较少的长处。传统堵塞IO为了提高效率,须要创建一定数量的连接形成连接池。而nio仅须要一个连接就可以(当然,nio也是能够做池化处理),相对来说降低了线程创建和切换的开销,这一点在高并发下特别明显。因此XMemcachedSpymemcached在性能都很优秀,在某些方面(存储的数据比較小的情况下)XmemcachedSpymemcached的表现更为优秀,详细能够看这个Java Memcached Clients Benchmark

    本文章使用memcached client for java为例

    在使用java连接远程的PC机的Memcached时。记得保证两台机都开启telnet服务。而且本机能telnet通远程机,远程机必须关闭防火墙。

    实例代码1:(java连接Memcached并实现数据的存取)

    import com.danga.MemCached.MemCachedClient;

    import com.danga.MemCached.SockIOPool;

    public class memcachedTest {

    public static void main(String[] args) {

    //初始化SockIOPool,管理Memcached的连接池

    String[] servers = {"192.183.3.230:11211"};

    SockIOPool pool = SockIOPool.getInstance();

    pool.setServers(servers);

    pool.setFailover(true);

    pool.setInitConn(10);

    pool.setMinConn(5);

    pool.setMaxConn(250);

    pool.setMaintSleep(30);

    pool.setNagle(false);

    pool.setSocketTO(3000);

    pool.setAliveCheck(true);

    pool.initialize();

    //建立MemcachedClient实例

    MemCachedClient memCachedClient = new MemCachedClient();

    for(int i = 0;i < 100000;i++){

    //将对象增加到memcached缓存

    boolean success = memCachedClient.set(""+i, "hello!");

    }

    for(int i = 0;i < 100000;i++){

    //从memcached缓存中按key值取对象

    String result = (String)memCachedClient.get(""+i);

    System.out.println(String.format("get(%d):%s", i,result+i));

    }

    }

    }

    四、測试Memcached性能

    为性能对照測试准备数据

    1、插入数据到oracle

    /**

     * 插入測试数据到oracle数据库

     * @param count插入记录数

     * @return

     */

    public static boolean insertIntoOracle(int count){

    try {

    con = dbConn("feng","feng");

    if(con == null){

    System.out.println("连接失败");

    System.exit(0);

    }

    System.out.println("truncate table memcached_test......");

    sql = "truncate table memcached_test";

    pstmt = con.prepareStatement(sql);

    rs = pstmt.executeQuery();

    System.out.println("truncate table memcached_test finish.");

    System.out.println("insert "+count+" values");

    sql = "insert into memcached_test (memcachedId,memcachedvalues) values (?,?

    )";

    pstmt = con.prepareStatement(sql);

    for(int i = 1;i <= count;i++){

    pstmt.setInt(1, i);

    pstmt.setString(2, "Memcached is a good thing.I like it very much !-----------"+i);

    pstmt.executeUpdate();

    }

    System.out.println("insert "+count+" values finish.");

    rs.close();

    pstmt.close();

    con.close();

    catch (ClassNotFoundException e) {

    e.printStackTrace();

    catch (SQLException e) {

    e.printStackTrace();

    }

    return true;

    }

    public static Connection dbConn(String name,String pass) throws ClassNotFoundException, SQLException{

    Connection conn = null;

    Class.forName("oracle.jdbc.driver.OracleDriver");

    conn = DriverManager.getConnection("jdbc:oracle:thin:@192.183.3.230:1522:myorcl",name,pass);

    return conn;

    }

    2、插入数据到Memcached

    /**

     * 插入測试数据到Memcached

     * @param count插入记录数

     * @return

     */

    public static boolean insertIntoMemcached(int count){

    //初始化SockIOPool。管理Memcached的连接池

    String[] servers = {"192.183.3.230:11211"};

    SockIOPool pool = SockIOPool.getInstance();

    pool.setServers(servers);

    pool.setFailover(true);

    pool.setInitConn(10);

    pool.setMinConn(5);

    pool.setMaxConn(250);

    pool.setMaintSleep(30);

    pool.setNagle(false);

    pool.setSocketTO(3000);

    pool.setAliveCheck(true);

    pool.initialize();

    //建立MemcachedClient实例

    MemCachedClient memCachedClient = new MemCachedClient();

    System.out.println("insert "+count+" values into memcached......");

    for(int i = 1;i < count;i++){

    //将对象增加到memcached缓存

    boolean success = memCachedClient.set("testData"+i, insertStr+i);

    }

    System.out.println("insert "+count+" values into memcached finish.");

    return true;

    }

    Main函数调用这两个方法后,会将count条记录,值为insertData,插入到Oracle数据和set进Memcached中。

    1、比較同一时候插入100000条数据的时间

     

    从执行结果能够看出,插入10万条数据到Memcached比插10万条数据入Oracle所用时间有一个质的降低。

    2、比較查询时间

    下面是连接oracle数据并查找10000条数据的方法

    /**

     * oracle数据库查找

     * @param count记录数

     * @return

     * @throws ParseException 

     */

    public static long searchOracle(int count) throws ParseException{

    long useTime = 0;

    try {

    con = dbConn("feng","feng");

    if(con == null){

    System.out.println("连接失败");

    System.exit(0);

    }

    StringBuffer sql =new StringBuffer("select memcachedid,memcachedvalues from memcached_test where memcachedid = ?");

    pstmt = con.prepareStatement(sql.toString());

    String memcachedvalues = "";

    System.out.println("search table memcached_test......");

    String beginTime = d.format(new Date());

    for(int i = 1;i <= count;i++){

    if(i%10 == 0){

    pstmt.setInt(1, i);

    rs = pstmt.executeQuery();

    while(rs.next()){

    memcachedvalues = rs.getString(2);

    }

    }

    }

    System.out.println("search table memcached_test finish.");

    String endTime = d.format(new Date());

    useTime = d.parse(endTime).getTime() - d.parse(beginTime).getTime();

    long ss = (useTime/1000)%60;//秒

    long MM = useTime/60000;//分

    System.out.println("Oracle中查找10000条记录的開始时间:"+beginTime);

    System.out.println("Oracle中查找10000条记录的结束时间:"+endTime);

    System.out.println("Oracle中查找10000条记录的所用时间:  "+MM+"分"+ss+"秒");

    rs.close();

    pstmt.close();

    con.close();

    catch (ClassNotFoundException e) {

    e.printStackTrace();

    catch (SQLException e) {

    e.printStackTrace();

    }

    return useTime;

    }

    下面是连接Memcached并查找10000条数据的方法

    /**

     * Memcached查找

     * @param count

     * @return

     * @throws ParseException

     */

    public static long searchMemcached(int count) throws ParseException{

    //初始化SockIOPool。管理Memcached的连接池

    String[] servers = {"192.183.3.230:11211"};

    SockIOPool pool = SockIOPool.getInstance();

    pool.setServers(servers);

    pool.setFailover(true);

    pool.setInitConn(10);

    pool.setMinConn(5);

    pool.setMaxConn(250);

    pool.setMaintSleep(30);

    pool.setNagle(false);

    pool.setSocketTO(3000);

    pool.setAliveCheck(true);

    pool.initialize();

    //建立MemcachedClient实例

    MemCachedClient memCachedClient = new MemCachedClient();

    System.out.println("search 10000 data in Memcached......");

    String memcachedvalues = "";

    String beginTime = d.format(new Date());

    for(int i = 1;i <= count;i++){

    //从memcached缓存中按key值取对象

    if(i%10 == 0){

    memcachedvalues = (String)memCachedClient.get("testData"+i);

    }

    }

    System.out.println("search 10000 data in Memcached finish.");

    String endTime = d.format(new Date());

    long useTime = d.parse(endTime).getTime() - d.parse(beginTime).getTime();

    long ss = (useTime/1000)%60;//秒

    long MM = useTime/60000;//分

    System.out.println("从Memcached查找10000条记录的開始时间:"+beginTime);

    System.out.println("从Memcached查找10000条记录的结束时间:"+endTime);

    System.out.println("从Memcached查找10000条记录的所用时间:  "+MM+"分"+ss+"秒");

    return useTime;

    }

    执行结果例如以下:

     

    从执行结果能够看出,同一时候查找10000条数据,Memcached所用时间比1Oracle所用时间降低了29

    四、启动多个节点的Memcached

    因为实验器材有限,如今在同一台pc机中启动多个Memcached,仅仅要设定port不一样,这些Memcached之间互相不会干扰。

    启动命令例如以下:

    [root@nn init.d]# memcached -d -p 11212 -u memcached -m 64 -c 1024

    [root@nn init.d]# memcached -d -p 11213 -u memcached -m 64 -c 1024

    当中-d表示在后台执行,-p表示port号,-u表示用户

    启动之后用pstree查看

    [root@nn init.d]# pstree

     

    3*[memcached───5*[{memcached}]]表示有3Memcached的进程。

    或者用ps aux命令

    [root@nn init.d]# ps aux

     

    往多节点的Memcached中插入数据的java代码

    /**

     * 往节点Memcached插入数据

     * @param count

     */

    public static void testManyNode(int count){

    //初始化SockIOPool,管理Memcached的连接池

    String[] servers = {"192.183.3.230:11211","192.183.3.230:11212","192.183.3.230:11213"};

    SockIOPool pool = SockIOPool.getInstance();

    pool.setServers(servers);

    pool.setFailover(true);

    pool.setInitConn(10);

    pool.setMinConn(5);

    pool.setMaxConn(250);

    pool.setMaintSleep(30);

    pool.setNagle(false);

    pool.setSocketTO(3000);

    pool.setAliveCheck(true);

    pool.initialize();

    //建立MemcachedClient实例

    MemCachedClient memCachedClient = new MemCachedClient();

    String beginTime = d.format(new Date());

    for(int i = 1;i <= count;i++){

    //将对象增加到memcached缓存

    boolean success = memCachedClient.set("node"+i, insertStr+i);

    }

    }

    Memcached的查询结果:

     

    从结果中能够看出,数据分布到Memcached的不同节点上。

    五、高可用方案repcached

    假如Memcached中有一个节点失效了,这个节点所管辖的数据都没有,我们必须又一次去数据库中获取数据放入新的节点中。这样会引发数据库性能的波动。这里就须要我们做一个高可用的Memcached,使得Memcached中的每个节点都有另外一个节点与之中的一个一相应。这两个一一相应的节点中的数据是一模一样的。这样当当中一个节点失效了,另外一个节点就能立即接管缓存的工作,这样就不须要又一次从数据库中获取数据库。

    以下我们使用repcached来实现Memcached的高可用

    1、下载repcached

    [root@nn ~]# wget http://downloads.sourceforge.net/repcached/memcached-1.2.8-repcached-2.2.tar.gz

     

    2、杀死本机上的全部Memcached

    [root@nn ~]# killall memcached

    3、解压下载的repcached

    [root@nn ~]# tar zxvf memcached-1.2.8-repcached-2.2.tar.gz

     

    4、进入所解压的文件夹

    [root@nn ~]# cd memcached-1.2.8-repcached-2.2

     

    5、安装依赖包,执行编译repcached所须要的

    [root@nn memcached-1.2.8-repcached-2.2]# yum install libevent-devel

    6、開始安装repcached

    [root@nn memcached-1.2.8-repcached-2.2]# ./config --enable-replication --program-transform-name=s/memcached/repcached/

     

     

    安装好之后就会产生一个Makefile文件

     

    7、能够使用Makefile来编译

    [root@nn memcached-1.2.8-repcached-2.2]# make

    [root@nn memcached-1.2.8-repcached-2.2]# make install

     

    能够看到主要安装的程序有repcachedrepcached-debug

    8、启动Memcached的高可用集群(注意不能用root用户来启动)

    [oracle@nn ~]$ /usr/local/bin/repcached -p 11211 -v -d

    [oracle@nn ~]$ /usr/local/bin/repcached -p 11212 -x localhost -v -d

     

    当中-x表示要监听高可用机器,假设是其它port要写上“:port号”,假设是默认port(11211)。就不须要写。

    9、測试:从11211port插入数据,到11212port去查找;从11212port插入数据,到11211port去查找

     

    从測试结果能够看出。这个高可用复制是双向的。不管在哪一个节点插入数据,都能够在另外一个节点中查到。

    六、Memcached的一致性

    假设有两个不同终端连接同一Memcached服务,对同一key值进行改动,结果会怎样呢?

    以下来做实验

    1、A终端连接Memcachedsetkeycounter的一个值1

     

    gets命令看出。比用get命令多最后一个数字,这个数字表示这个key的版本

    2、B终端连接Memcachedsetkeycounter的一个值2

     

    3、用set命令去改会改变一致性,这里改用cas命令

     

    我们用gets查看当前的版本是3

     

    用cas最后一个參数表示版本,假设版本不一样。不能改动。会有EXISTS提示。表示改动失败;假设版本一致,就能改动成功。

    Memcached的缺点

    1、纯内存操作的数据库。关机或者关闭Memcached进程后数据所有丢失;

    2、保存字节数,数据类型贫乏,其它数据类型都要通过应用程序来解释,这样应用端要做的事情会非常多,server端要做的事情就非常好非常好了;

    3、兼容性差。不同编程语言之间不能相互调用;

    4、LRU算法导致数据不可控的丢失。

    5、一致性处理简单。

    6、应用场景有限,难以被看成是完整的数据库产品,只用来做数据库和应用之间的缓存层。

  • 相关阅读:
    支持向量机SVM知识点概括
    决策树知识点概括
    HDU 3081 Marriage Match II
    HDU 3572 Task Schedule
    HDU 4888 Redraw Beautiful Drawings
    Poj 2728 Desert King
    HDU 3926 Hand in Hand
    HDU 1598 find the most comfortable road
    HDU 4393 Throw nails
    POJ 1486 Sorting Slides
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/6873535.html
Copyright © 2011-2022 走看看