NoSQL之Memcached

一、Memcached概念

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

Memcached有以下特点:

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

2、哈希方式存储:

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

4、只操作字符型数据:无论往memcached放入什么,都是以字节的方式来处理。还原成数组、哈希表、字符串和数值等都交给应用层来解释。应用读写memcached的数据时,进行序列化和反序列化,把其解释成应用所能理解的数据类型;

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

二、安装Memcached

1、在linux上搭建yum环境

2、使用yum命令进行安装Memcached的rpm包

[[email protected] init.d]# yum install memcached

3、启动Memcached,

首先要cd到相应目录

[[email protected] ~]# cd /etc/rc.d/init.d/

运行memcached安装脚本

[[email protected] init.d]# ./memcached start

4、查看Memcached是否启动

[[email protected] init.d]# pstree

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

或者使用[[email protected] init.d]# ps aux命令

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

-d表示程序要后台化运行,-p指定端口,-u表示用memcached这个身份来运行,后面的都是memcached的控制参数

5、连接Memcached

[[email protected] init.d]# telnet localhost 11211

三、Memcached常用命令

命令格式:

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

<data block>

参数说明如下:


<command name>


set/add/replace


<key>


查找关键字


<flags>


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


<exptime>


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


<bytes>


存储字节数


<data block>


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

1、增加:set、add、cas

2、获取:get、gets、

3、追加:append、prepend

4、删除:delete

5、清除所有:flush_all

6、加减:incr、decr

7、退出:quit

三、用java连接Memcached

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

1、memcached client for java

较早推出的memcached JAVA客户端API,应用广泛,运行比较稳定。

2、pymemcached

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

3、xmemcached

XMemcached同样是基于java nio的客户端,java nio相比于传统阻塞io模型来说,有效率高(特别在高并发下)和资源耗费相对较少的优点。传统阻塞IO为了提高效率,需要创建一定数量的连接形成连接池,而nio仅需要一个连接即可(当然,nio也是可以做池化处理),相对来说减少了线程创建和切换的开销,这一点在高并发下特别明显。因此XMemcached与Spymemcached在性能都非常优秀,在某些方面(存储的数据比较小的情况下)Xmemcached比Spymemcached的表现更为优秀,具体可以看这个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,只要设定端口不一样,这些Memcached之间互相不会干扰。

启动命令如下:

[[email protected] init.d]# memcached -d -p 11212 -u memcached -m 64 -c 1024

[[email protected] init.d]# memcached -d -p 11213 -u memcached -m 64 -c 1024

其中-d表示在后台运行,-p表示端口号,-u表示用户

启动之后用pstree查看

[[email protected] init.d]# pstree

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

或者用ps aux命令

[[email protected] 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

[[email protected] ~]# wget http://downloads.sourceforge.net/repcached/memcached-1.2.8-repcached-2.2.tar.gz

2、杀死本机上的所有Memcached

[[email protected] ~]# killall memcached

3、解压下载的repcached

[[email protected] ~]# tar zxvf memcached-1.2.8-repcached-2.2.tar.gz

4、进入所解压的目录

[[email protected] ~]# cd memcached-1.2.8-repcached-2.2

5、安装依赖包,运行编译repcached所需要的

[[email protected] memcached-1.2.8-repcached-2.2]# yum install libevent-devel

6、开始安装repcached

[[email protected] memcached-1.2.8-repcached-2.2]# ./config --enable-replication --program-transform-name=s/memcached/repcached/

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

7、可以使用Makefile来编译

[[email protected] memcached-1.2.8-repcached-2.2]# make

[[email protected] memcached-1.2.8-repcached-2.2]# make install

可以看到主要安装的程序有repcached和repcached-debug

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

[[email protected] ~]$ /usr/local/bin/repcached -p 11211 -v -d

[[email protected] ~]$ /usr/local/bin/repcached -p 11212 -x localhost -v -d

其中-x表示要监听高可用机器,如果是其他端口要写上“:端口号”,如果是默认端口(11211),就不需要写。

9、测试:从11211端口插入数据,到11212端口去查找;从11212端口插入数据,到11211端口去查找

从测试结果可以看出,这个高可用复制是双向的。无论在哪一个节点插入数据,都可以在另外一个节点中查到。

六、Memcached的一致性

如果有两个不同终端连接同一Memcached服务,对同一key值进行修改,结果会如何呢?

下面来做实验

1、A终端连接Memcached并set入key为counter的一个值1

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

2、B终端连接Memcached并set入key为counter的一个值2

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

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

用cas最后一个参数表示版本号,如果版本号不一样,不能修改,会有EXISTS提示,表示修改失败;如果版本号一致,就能修改成功。

Memcached的缺点

1、纯内存操作的数据库,关机或者关闭Memcached进程后数据全部丢失;

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

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

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

5、一致性处理简单;

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

NoSQL之Memcached,布布扣,bubuko.com

时间: 2024-10-19 12:11:20

NoSQL之Memcached的相关文章

NoSQL与Memcached、Redis、MongoDB概述

一.NoSQL介绍 非关系型数据库(而mysql.oracle.sqlserver都是关系型数据库) 1. 特点 数据之间无关系,随意扩展 数据存储简单,可以存在内存中,读写速度快 不需要建表.字段.自定义格式 2. 分类 A. 键值(Key-Value)数据库:redis.memcached.riak redis/memcached 适合存储用户信息,比如会话.配置文件.参数.购物车等,这些信息一般和ID(键)挂钩 B. 面向文档(Document-Oriented)数据库:MongoDB.C

二、NOSQL之Memcached缓存服务实战精讲第一部

1.Memcached是一套数据缓存系统或软件. 用于在动态应用系统中缓存数据库的数据,减少数据库的访问压力,达到提升网站系统性能的目的:Memcached在企业应用场景中一般是用来作为数据库的cache服务使用:(但不是专门干这个,还可以干别的,主要是干这个,知道就好) 1)linux有特性,系统内存没有用完,利用这些内存就会缓存起来,所以剩余的内存为881 2)cache读缓存,磁盘数据读到缓存中:buffers写缓存,将数据写到缓存中,等到一定量的时候就写入磁盘中. 3)buffers同步

memcached 缓存数据库应用实践

1.1 数据库对比 缓存: 将数据存储到内存中,只有当磁盘胜任不了的时候,才会启用缓存   缺点:断电数据丢失(双电),用缓存存储数据的目的只是为了应付大并发的业务. 数据库: mysql(关系型数据库,能够保证数据一致性,保证数据不丢失,当因为功能太多,导致性能不高) ===数据参考 缓存数据库:  memcache redis(非关系型数据库,性能极高,但不保证数据完整性) === 业务的数据提供者           memcachedb 会将内存的数据写入到磁盘中   redis 主要工

数据存储方案评估标准RDBMS or KV

作者:zhanhailiang 日期:2014-12-11 本文主要介绍常见的数据存储方案及相应选型的评估标准的介绍. Guideline:针对不同应用场景,针对性选择存储方式. 1. 数据存储方案 SQL: MySQL 5.5/5.6/MariaDB(对于Dev绝大多数场景下透明): Oracle|MS SQL暂不考虑: NoSQL: Memcached 1.4.21: Redis 2.8: MongoDB 2.6.6: Hbase 0.96/0.98: 2. 评估标准 RDBMS:(MySQ

Redis数据类型之HASH类型

Web程序猿博客:http://blog.csdn.net/thinkercode HASH类型-特点 Redis hash 是一个 string 类型的 field 和 value 的映射表.它的添加. 删除操作都是 O(1) (平均) . hash 特别适合用于存储对象. 相较于将对象的每个字段存成单个 string 类型. 将一个对象存储在 hash 类型中会占用更少的内存,并且可以更方便的存取整个对象.省内存的原因是新建一个 hash 对象时开始是用 zipmap(又称为 small h

MySQL Innodb Memcahed Introduction & Examples

I give the brief introduction on NoSQL & Innodb/memcached plugin. Also, 2 application examples with C++ and Python provided. Please take the attached file to see detail description. MySQL Innodb Memcahed Introduction & Examples

php高级研发或架构师必了解---很多问题面试中常问到!

版权声明:本文为博主原创文章,未经博主允许不得转载. 最近接连面试了几家公司,有些重要问题记录一下,督促自己学习提高,同时希望给朋友们一些帮助. 内容很多,一点点完善,一步步学习.. 有些是面试被问,有些是招聘要求,有些是自己整理加的. 一.MySQL相关知识 1. mysql优化方式 MYSQL 优化常用方法 mysql 性能优化方案 2.如何分库分表 参考: http://blog.sina.com.cn/s/blog_6e322ce70100zs9a.html http://www.jb5

目前常用的开源服务器端技术

OS CentOS 6/7 最小安装 (3.10内核 Oracle/taobao) --- Debian 虚拟化 Xen Server ---KVM – Docker ? www Nginx(Tengine 3.10内核)--  Apache Lighttpd database- MySQL(Percona MariaDB) – MHA,Percona Xtrabackup nosql – Redis Memcached – MongoDB Hbase 语言 Python (Tornado) P

开发人员学Linux之终结篇:大型系统开发经验谈

1.前言这篇文章来源于我的一个ppt,而这个ppt是源于一个朋友的一次邀请,朋友邀请我为一个公司做一堂大约2小时的技术讲座,我选定的方向是如何开发一个大型系统,在这里我对大型系统的定义为日均PV在千万级以上,而京东和淘宝这类则属于巨型系统了.因此在本篇中讲述的都是基于一些开源免费的技术实现,至于那些通过F5硬件加速.DNS来实现负载均衡.CDN加速等需要花钱购买的技术或者服务则不再本篇介绍范围之类.本来此篇是作为<开发人员学Linux>系列的终结篇最后出现的,但是考虑到在此过程中我可能会由于时