1)EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。
2)Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。
3)Ehcache最初是由Greg Luck于2003年开始开发。2009年,该项目被Terracotta购买。软件仍然是开源,但一些新的主要功能(例如,快速可重启性之间的一致性的)只能在商业产品中使用,例如Enterprise EHCache and BigMemory。,维基媒体Foundationannounced目前使用的就是Ehcache技术。
4)Ehcache详见如下博客:
来源 |
作者 |
标题 |
网址 |
iteye |
RayChase |
Ehcache详细解读 |
http://raychase.iteye.com/blog/1545906 |
cnblogs |
hoojo |
整合Spring 使用页面、对象缓存 |
http://www.cnblogs.com/hoojo/archive/2012/07/12/2587556.html |
官网 |
|
|
http://www.ehcache.org/ |
2.2 Ehcache使用
这里以官网http://www.ehcache.org/documentation/3.0/getting-started.html 例子进行讲解
1)eclipse中新建maven普通工程,pom.xml配置如下:
4.0.0
com.test
ehcachetest
0.0.1-SNAPSHOT
ehcachetest
jar
3.0.1
org.ehcache
ehcache
${ehcache.version}
org.apache.maven.plugins
maven-resources-plugin
2.4.3
UTF-8
2)eclipse中windows-Preferences-Maven- Download Artifact Sources勾选上方便后续查看依赖包源代码
3)直接调用java API管理缓存cache
- 通过
CacheManagerBuilder
的静态方法newCacheManagerBuilder
实例化CacheManager对象
- 通过
CacheConfigurationBuilder
的静态方法newCacheManagerBuilder
来创建缓存Cache
的配置CacheConfiguration
,然后通过CacheManager的静态方法withCache
注册配置
- 通过CacheManager的静态方法getCache获取
Cache
对象
- 拿到
Cache
对象后,可调用put设置缓存值key-value,可调用get通过可以获取value
- 通过CacheManager的静态方法removeCache获取删除Cache对象
- 最后必须调用CacheManager的静态方法close关闭CacheManager,以便释放资源
package com.ehcache.test;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
public class ManagedCacheTest {
public static void main(String[] args) {
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
// 通过CacheManagerBuilder 的静态方法newCacheManagerBuilder 实例化CacheManager对象
.withCache(
"preConfigured",
//通过CacheConfigurationBuilder 的静态方法newCacheManagerBuilder 来创建缓存Cache 的配置CacheConfiguration ,
//然后通过CacheManager的静态方法withCache 注册配置
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(10))).build();
cacheManager.init();
//通过CacheManager的静态方法getCache获取Cache 对象
Cache preConfigured = cacheManager.getCache("preConfigured", Long.class, String.class);
//通过CacheManager的方法createCache创建另一个不同配置Cache对象
Cache myCache = cacheManager.createCache("myCache", CacheConfigurationBuilder
.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)).build());
//拿到Cache 对象后,可调用put设置缓存值key-value,可调用get通过可以获取value
//通过CacheManager的静态方法removeCache获取删除Cache对象
myCache.put(1L, "da one!");
String value = myCache.get(1L);
System.out.println("value=" + value);
cacheManager.removeCache("preConfigured");
//最后可通过CacheManager的静态方法close关闭CacheManager
cacheManager.close();
}
}
4)Ehcache3中引入的用户管理cache
- UserManagedCache是EhCACHE3中的新特性,UserManagedCache不受
CacheManager
管理
- 可以在build时候传入false先不初始化UserManagedCache
- 最后必须调用UserManagedCache.close()来释放资源
package com.ehcache.test;
import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.UserManagedCacheBuilder;
public class UserManagedCacheTest {
public static void main(String[] args) {
//UserManagedCache是EhCACHE3中的新特性,UserManagedCache不受CacheManager 管理
UserManagedCache userManagedCache = UserManagedCacheBuilder.newUserManagedCacheBuilder(
Long.class, String.class).build(false);//可以在build时候传入false先不初始化UserManagedCache
userManagedCache.init();
userManagedCache.put(1L, "da one!");
//最后必须调用UserManagedCache.close()来释放资源
userManagedCache.close();
}
}
5)EhCache中的存储分层
EhCache中数据默认是存储在内存(堆存储)中的,但内存(堆存储)这种资源是非常宝贵的,为了高效利用资源,尽量使得频繁使用的数据放置于内存(堆存储)中,那些使用频率低的数据可以放置在非堆存储中,甚至持久化到资源丰富的磁盘上。
非堆存储Off-heap
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder().withCache("tieredCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(10, EntryUnit.ENTRIES)
.offheap(10, MemoryUnit.MB))
)
.build(true);
cacheManager.close();
注意:上面的例子分配了一个只允许10个缓存大小的非堆内存;
使用非堆内存时候,你必须自己序列化对象和反序列化对象,这样速度肯定比堆内存慢;
使用非堆内存时候,一个优势是不必担心有类似堆内存存储时候的垃圾回收GC影响;
使用非堆内存时候,一定不要忘记了要去设置-XX:MaxDirectMemorySize
磁盘存储Disk persistence
PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.with(CacheManagerBuilder.persistence(getStoragePath() + File.separator + "myData"))
.withCache("persistent-cache", CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(10, EntryUnit.ENTRIES)
.disk(10, MemoryUnit.MB, true))
)
.build(true);
persistentCacheManager.close();
注意:使用磁盘存储,需要通过CacheManagerBuilder.persistence(String)设置存储位置;
使用磁盘存储,你必须自己去序列化和反序列化存储对象,速度上肯定是慢与非堆存储,更慢于堆存储;
使用磁盘存储,最大的优势是,在Ehcache关闭后,缓存数据是可以恢复的
三种存储混合使用Three tiers
PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.with(CacheManagerBuilder.persistence(getStoragePath() + File.separator + "myData"))
.withCache("threeTieredCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(10, EntryUnit.ENTRIES)
.offheap(1, MemoryUnit.MB)
.disk(20, MemoryUnit.MB)
)
).build(true);
persistentCacheManager.close();
注意:上面例子中混合使用三种存储;
其中内存heap中单位是10个,允许最多10个key-value值,单位也可以是KB MB等;
其中offheap容量为1MB ;
其中disk容量为20MB,注意这里仍然要通过CacheManagerBuilder.persistence(String)设置存储位置
关于资源池更新Update ResourcePools
ResourcePools pools = ResourcePoolsBuilder.newResourcePoolsBuilder().heap(20L, EntryUnit.ENTRIES).build();
cache.getRuntimeConfiguration().updateResourcePools(pools);
assertThat(cache.getRuntimeConfiguration().getResourcePools()
.getPoolForResource(ResourceType.Core.HEAP).getSize(), is(20L));
注意:这里意思是可以在线更新线上的已经存在的EhCache缓存配置信息
关于缓存数据有效时间设置Data freshness
CacheConfiguration cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(100))
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(20, TimeUnit.SECONDS)))
.build();
注意:这里意思是可以设置缓存数据有效时间
6)使用XML类配置EhCache
java.lang.String
2000
500
java.lang.Long
java.lang.String
200
java.lang.Number
上面的XML定义好后,可以通过如下java API进行调用
final URL myUrl = this.getClass().getResource("/ecache.xml");
Configuration xmlConfig = new XmlConfiguration(myUrl);
CacheManager myCacheManager = CacheManagerBuilder.newCacheManager(xmlConfig);
2.3 EhCache与spring集成
在controller中注入ehCacheCacheManager后,就可以拿到ehCacheCacheManager对象以获得你配置的cache对象进行操作。
2.4 EhCache在hibernate中的使用
参见http://blog.csdn.net/lpz283929516/article/details/8084664
2.5 EhCache三种缓存算法
- LRU 最近最少使用
- LFU 较少频率使用
- FIFO 先进先出
3.Memcached
3.1memcach和memcached的区别
这里引用杨鑫奇在cnblogs的一篇关于“小白谈memcache和memcached的区别”的博客,这两个是啥呢,博主说的很清楚了,memcache和memcached在php关于memcached客户端中有两个版本:
- memcache是pecl扩展库版本
- memcached是libmemcached版本
3.2memcached完全剖析
来源 |
作者 |
标题 |
网址 |
cnblogs |
作者:长野雅广 (Masahiro Nagano) 翻译:charlee |
memcached的基础 |
http://kb.cnblogs.com/page/42731/ |
cnblogs |
作者:长野雅广 (Masahiro Nagano) 翻译:charlee |
理解memcached的内存存储 |
http://kb.cnblogs.com/page/42732/ |
cnblogs |
作者:长野雅广 (Masahiro Nagano) 翻译:charlee |
memcached的删除机制和发展方向 |
http://kb.cnblogs.com/page/42733/ |
cnblogs |
作者:长野雅广 (Masahiro Nagano) 翻译:charlee |
memcached的分布式算法 |
http://kb.cnblogs.com/page/42734/ |
cnblogs |
作者:长野雅广 (Masahiro Nagano) 翻译:charlee |
memcached的应用和兼容程序 |
http://kb.cnblogs.com/page/42735/ |
3.2.1 memcached的基础
1) memcached 是以LiveJournal 旗下Danga Interactive 公司的Brad Fitzpatric 为首开发的一款软件。memcached是高性能的分布式内存缓存服务器。 一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、 提高可扩展性。
2) memcached的特征
- 协议简单:memcached的服务器客户端通信并不使用复杂的XML等格式, 而使用简单的基于文本行的协议。因此,通过telnet 也能在memcached上保存数据、取得数据。
- 基于libevent的事件处理:libevent是个程序库,它将Linux的epoll、BSD类操作系统的kqueue等事件处理功能 封装成统一的接口。
- 内置内存存储方式:为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。 由于数据仅存在于内存中,因此重启memcached、重启操作系统会导致全部数据消失。 另外,内容容量达到指定值之后,就基于LRU(Least Recently Used)算法自动删除不使用的缓存。
- memcached不互相通信的分布式:memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。 各个memcached不会互相通信以共享信息。那么,怎样进行分布式呢? 这完全取决于客户端的实现。
方法 |
说明 |
add |
仅当存储空间中不存在键相同的数据时才保存 |
replace |
仅当存储空间中存在键相同的数据时才保存 |
set |
与add和replace不同,无论何时都保存(set函数忽视该delete阻塞,照常保存数据) |
get |
获取数据 |
get_multi |
一次取得多条数据 |
delete |
删除数据,它有个独特的功能delete('键', '阻塞时间(秒)')删除第一个参数指定的键的数据。第二个参数指定一个时间值,可以禁止使用同样的键保存新数据。 |
3.2.2 理解memcached的内存存储
1) Slab Allocation机制:整理内存以便重复使用
Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块, 以完全解决内存碎片问题。Slab Allocation的原理相当简单。 将分配的内存分割成各种尺寸的块(chunk), 并把尺寸相同的块分成组(chunk的集合),如下图:
2) Slab Allocation的主要术语
- Page:分配给Slab的内存空间,默认是1MB。分配给Slab之后根据slab的大小切分成chunk。
- Chunk:用于缓存记录的内存空间。
- Slab Class:特定大小的chunk的组。
3) 使用Growth Factor进行调优
memcached在启动时指定 Growth Factor因子(通过-f选项), 就可以在某种程度上控制slab之间的差异。默认值为1.25。 但是,在该选项出现之前,这个因子曾经固定为2,称为“powers of 2”策略。
$ memcached -f 2 -vv
下面是启动后的verbose输出:
slab class 1: chunk size 128 perslab 8192
slab class 2: chunk size 256 perslab 4096
slab class 3: chunk size 512 perslab 2048
slab class 4: chunk size 1024 perslab 1024
slab class 5: chunk size 2048 perslab 512
slab class 6: chunk size 4096 perslab 256
slab class 7: chunk size 8192 perslab 128
slab class 8: chunk size 16384 perslab 64
slab class 9: chunk size 32768 perslab 32
slab class 10: chunk size 65536 perslab 16
slab class 11: chunk size 131072 perslab 8
slab class 12: chunk size 262144 perslab 4
slab class 13: chunk size 524288 perslab 2
可见,从128字节的组开始,组的大小依次增大为原来的2倍。 这样设置的问题是,slab之间的差别比较大,有些情况下就相当浪费内存。 因此,为尽量减少内存浪费,两年前追加了growth factor这个选项
默认设置(f=1.25)时的输出(篇幅所限,这里只写到第10组):
slab class 1: chunk size 88 perslab 11915
slab class 2: chunk size 112 perslab 9362
slab class 3: chunk size 144 perslab 7281
slab class 4: chunk size 184 perslab 5698
slab class 5: chunk size 232 perslab 4519
slab class 6: chunk size 296 perslab 3542
slab class 7: chunk size 376 perslab 2788
slab class 8: chunk size 472 perslab 2221
slab class 9: chunk size 592 perslab 1771
slab class 10: chunk size 744 perslab 1409
可见,组间差距比因子为2时小得多,更适合缓存几百字节的记录。 从上面的输出结果来看,可能会觉得有些计算误差, 这些误差是为了保持字节数的对齐而故意设置的
3.2.3 memcached的删除机制和发展方向
1) 数据不会真正从memcached中消失
memcached不会释放已分配的内存。记录超时后,客户端就无法再看见该记录(invisible,透明), 其存储空间即可重复使用。
memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。 这种技术被称为lazy(惰性)expiration。因此,memcached不会在过期监视上耗费CPU时间。
2) LRU:从缓存中有效删除数据的原理
memcached会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不足的情况, 此时就要使用名为 Least Recently Used(LRU)机制来分配空间。 顾名思义,这是删除“最近最少使用”的记录的机制。 因此,当memcached的内存空间不足时(无法从slab class 获取到新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。
#有些情况下LRU机制反倒会造成麻烦。memcached启动时通过“-M”参数可以禁止LRU,如下所示:
#小写的“-m”选项是用来指定最大内存大小的。不指定具体数值则使用默认值64MB。
#指定“-M”参数启动后,内存用尽时memcached会返回错误。
$ memcached -M -m 1024
3) memcached的最新发展方向
- 二进制协议的策划和实现:使用二进制协议的理由是它不需要文本协议的解析处理,使得原本高速的memcached的性能更上一层楼, 还能减少文本协议的漏洞
- 外部引擎支持:世界上有许多memcached的派生软件,其理由是希望永久保存数据、实现数据冗余等, 即使牺牲一些性能也在所不惜。我在开发memcached之前,在mixi的研发部也曾经 考虑过重新发明memcached。外部引擎的加载机制能封装memcached的网络功能、事件处理等复杂的处理。 因此,现阶段通过强制手段或重新设计等方式使memcached和存储引擎合作的困难 就会烟消云散,尝试各种引擎就会变得轻而易举了。
3.2.4 memcached的分布式算法
1) memcached的分布式
memcached虽然称为“分布式”缓存服务器,但服务器端并没有“分布式”功能。 服务器端仅包括 第2次、 第3次 前坂介绍的内存存储功能,其实现非常简单。 memcached的分布式,则是完全由客户端程序库实现的。 这种分布式是memcached的最大特点。
2)分布式算法
- 根据服务器台数的余数进行分散:求得键的整数哈希值,再除以服务器台数,根据其余数来选择服务器。余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。 那就是当添加或移除服务器时,缓存重组的代价相当巨大。 添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器, 从而影响缓存的命中率。
-
- Consistent Hashing:首先求出memcached服务器(节点)的哈希值, 并将其配置到0~2的32次方的圆(continuum)上。 然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。 如果超过2的32次方仍然找不到服务器,就会保存到第一台memcached服务器上。只有在continuum上增加服务器的地点逆时针方向的 第一台服务器上的键会受到影响。
-
3.3 memcached的安装
1)memcached依赖libevent,首先检查libevent是否已经安装
ls -al /usr/local/lib|grep libevent
2)在http://libevent.org/ 下载libevent-2.0.21-stable.tar.gz放置于/opt下
wget https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
3)解压libevent-2.0.21-stable.tar.gz
cd /opt
tar -zxvf libevent-2.0.21-stable.tar.gz
4)安装libevent,这里都是默认安装在目录/usr/local/lib
cd /opt/libevent-2.0.21-stable
./configure
make
make install
5)再次检查libevent是否已经安装
[root@master libevent-2.0.21-stable]# ls -al /usr/local/lib|grep libevent
lrwxrwxrwx 1 root root 21 May 14 17:47 libevent-2.0.so.5 -> libevent-2.0.so.5.1.9
-rwxr-xr-x 1 root root 968442 May 14 17:47 libevent-2.0.so.5.1.9
-rw-r--r-- 1 root root 1571130 May 14 17:47 libevent.a
lrwxrwxrwx 1 root root 26 May 14 17:47 libevent_core-2.0.so.5 -> libevent_core-2.0.so.5.1.9
-rwxr-xr-x 1 root root 585057 May 14 17:47 libevent_core-2.0.so.5.1.9
-rw-r--r-- 1 root root 977914 May 14 17:47 libevent_core.a
-rwxr-xr-x 1 root root 976 May 14 17:47 libevent_core.la
lrwxrwxrwx 1 root root 26 May 14 17:47 libevent_core.so -> libevent_core-2.0.so.5.1.9
lrwxrwxrwx 1 root root 27 May 14 17:47 libevent_extra-2.0.so.5 -> libevent_extra-2.0.so.5.1.9
-rwxr-xr-x 1 root root 404772 May 14 17:47 libevent_extra-2.0.so.5.1.9
-rw-r--r-- 1 root root 593288 May 14 17:47 libevent_extra.a
-rwxr-xr-x 1 root root 983 May 14 17:47 libevent_extra.la
lrwxrwxrwx 1 root root 27 May 14 17:47 libevent_extra.so -> libevent_extra-2.0.so.5.1.9
-rwxr-xr-x 1 root root 941 May 14 17:47 libevent.la
lrwxrwxrwx 1 root root 29 May 14 17:47 libevent_openssl-2.0.so.5 -> libevent_openssl-2.0.so.5.1.9
-rwxr-xr-x 1 root root 94209 May 14 17:47 libevent_openssl-2.0.so.5.1.9
-rw-r--r-- 1 root root 131836 May 14 17:47 libevent_openssl.a
-rwxr-xr-x 1 root root 1012 May 14 17:47 libevent_openssl.la
lrwxrwxrwx 1 root root 29 May 14 17:47 libevent_openssl.so -> libevent_openssl-2.0.so.5.1.9
lrwxrwxrwx 1 root root 30 May 14 17:47 libevent_pthreads-2.0.so.5 -> libevent_pthreads-2.0.so.5.1.9
-rwxr-xr-x 1 root root 18462 May 14 17:47 libevent_pthreads-2.0.so.5.1.9
-rw-r--r-- 1 root root 18702 May 14 17:47 libevent_pthreads.a
-rwxr-xr-x 1 root root 1004 May 14 17:47 libevent_pthreads.la
lrwxrwxrwx 1 root root 30 May 14 17:47 libevent_pthreads.so -> libevent_pthreads-2.0.so.5.1.9
lrwxrwxrwx 1 root root 21 May 14 17:47 libevent.so -> libevent-2.0.so.5.1.9
[root@master libevent-2.0.21-stable]#
6)下载memcached-1.4.25.tar.gz并放置于目录/opt下
wget http://memcached.org/files/memcached-1.4.25.tar.gz
7)解压memcached-1.4.25.tar.gz
cd /opt
tar -zxvf memcached-1.4.25.tar.gz
8)安装memcached-1.4.25.tar.gz,默认安装在/usr/local/bin/memcached
cd /opt/memcached-1.4.25
./configure
make
make test
make install
遇到错误:
./sizes
./sizes: error while loading shared libraries: libevent-2.0.so.5: cannot open shared object file: No such file or directory
make: *** [test] Error 127
需要制定libevent安装目录
cd /opt/memcached-1.4.25
./configure -with-libevent=/usr/local/lib
make
make test
make install
[root@master memcached-1.4.25]# make install
make install-recursive
make[1]: Entering directory `/opt/memcached-1.4.25'
Making install in doc
make[2]: Entering directory `/opt/memcached-1.4.25/doc'
make install-am
make[3]: Entering directory `/opt/memcached-1.4.25/doc'
make[4]: Entering directory `/opt/memcached-1.4.25/doc'
make[4]: Nothing to be done for `install-exec-am'.
/bin/mkdir -p '/usr/local/share/man/man1'
/usr/bin/install -c -m 644 memcached.1 '/usr/local/share/man/man1'
make[4]: Leaving directory `/opt/memcached-1.4.25/doc'
make[3]: Leaving directory `/opt/memcached-1.4.25/doc'
make[2]: Leaving directory `/opt/memcached-1.4.25/doc'
make[2]: Entering directory `/opt/memcached-1.4.25'
make[3]: Entering directory `/opt/memcached-1.4.25'
/bin/mkdir -p '/usr/local/bin'
/usr/bin/install -c memcached '/usr/local/bin'
/bin/mkdir -p '/usr/local/include/memcached'
/usr/bin/install -c -m 644 protocol_binary.h '/usr/local/include/memcached'
make[3]: Leaving directory `/opt/memcached-1.4.25'
make[2]: Leaving directory `/opt/memcached-1.4.25'
make[1]: Leaving directory `/opt/memcached-1.4.25'
[root@master memcached-1.4.25]#
9)检测memcached是否安装成功
[root@master bin]# ls -al /usr/local/bin/mem*
-rwxr-xr-x 1 root root 360338 May 14 18:04 /usr/local/bin/memcached
[root@master bin]#
10)启动Memcached服务
后台模式启动
/usr/local/bin/memcached -d -m 10 -u root -l 192.168.202.131 -p 12000 -c 256 -P /tmp/memcached.pid
调试模式启动
[root@master networksettings]# /usr/local/bin/memcached -vv -m 10 -u root -l 192.168.202.131 -p 12000 -c 256 -P /tmp/memcached.pid
slab class 1: chunk size 96 perslab 10922
slab class 2: chunk size 120 perslab 8738
slab class 3: chunk size 152 perslab 6898
slab class 4: chunk size 192 perslab 5461
slab class 5: chunk size 240 perslab 4369
slab class 6: chunk size 304 perslab 3449
slab class 7: chunk size 384 perslab 2730
slab class 8: chunk size 480 perslab 2184
slab class 9: chunk size 600 perslab 1747
slab class 10: chunk size 752 perslab 1394
slab class 11: chunk size 944 perslab 1110
slab class 12: chunk size 1184 perslab 885
slab class 13: chunk size 1480 perslab 708
slab class 14: chunk size 1856 perslab 564
slab class 15: chunk size 2320 perslab 451
slab class 16: chunk size 2904 perslab 361
slab class 17: chunk size 3632 perslab 288
slab class 18: chunk size 4544 perslab 230
slab class 19: chunk size 5680 perslab 184
slab class 20: chunk size 7104 perslab 147
slab class 21: chunk size 8880 perslab 118
slab class 22: chunk size 11104 perslab 94
slab class 23: chunk size 13880 perslab 75
slab class 24: chunk size 17352 perslab 60
slab class 25: chunk size 21696 perslab 48
slab class 26: chunk size 27120 perslab 38
slab class 27: chunk size 33904 perslab 30
slab class 28: chunk size 42384 perslab 24
slab class 29: chunk size 52984 perslab 19
slab class 30: chunk size 66232 perslab 15
slab class 31: chunk size 82792 perslab 12
slab class 32: chunk size 103496 perslab 10
slab class 33: chunk size 129376 perslab 8
slab class 34: chunk size 161720 perslab 6
slab class 35: chunk size 202152 perslab 5
slab class 36: chunk size 252696 perslab 4
slab class 37: chunk size 315872 perslab 3
slab class 38: chunk size 394840 perslab 2
slab class 39: chunk size 493552 perslab 2
slab class 40: chunk size 616944 perslab 1
slab class 41: chunk size 771184 perslab 1
slab class 42: chunk size 1048576 perslab 1
<26 server listening (auto-negotiate)
<27 send buffer was 229376, now 268435456
<27 server listening (udp)
<29 server listening (udp)
<30 server listening (udp)
<28 server listening (udp)
参数说明
-d 选项是启动一个守护进程;
-m 是分配给Memcache使用的内存数量,单位是MB,我这里是10MB;
-u 是运行Memcache的用户,我这里是root;
-l 是监听的服务器IP地址,如果有多个地址的话,我这里指定了服务器的IP地址192.168.0.200;
-p 是设置Memcache监听的端口,我这里设置了12000,最好是1024以上的端口;
-c 选项是最大运行的并发连接数,默认是1024,我这里设置了256,按照你服务器的负载量来设定;
-P 是设置保存Memcache的pid文件,我这里是保存在 /tmp/memcached.pid
-vv 用very vrebose模式启动,调试信息和错误输出到控制台
启动时如果遇到如下错误:
[root@master bin]# /usr/local/bin/memcached -d -m 10 -u root -l 192.168.202.131 -p 12000 -c 256 -P /tmp/memcached.pid
/usr/local/bin/memcached: error while loading shared libraries: libevent-2.0.so.5: cannot open shared object file: No such file or directory
[root@master bin]#
解决办法如下:
#首先查下memcached的加载库位置
LD_DEBUG=libs memcached -v
#针对缺失的库在加载目录建立个软连接
mkdir -p /usr/local/lib/lib/tls/x86_64
cd /usr/local/lib/lib/tls/x86_64
ln -s /usr/local/lib/libevent-2.0.so.5 /usr/local/lib/lib/tls/x86_64/libevent-2.0.so.5
再次启动就可以了
11)关闭memcached
方法一:
cat /tmp/memcached.pid|xargs kill -9
方法二:
#先查进程号
ps -ef|grep memcached
#然后杀掉进程
kill -9 进程号
12)测试memcached
telnet在centos下的安装http://blog.csdn.net/jiguang0455/article/details/8670142
telnet 192.168.202.131 12000
Trying 192.168.202.131...
Connected to 192.168.202.131 (192.168.202.131).
Escape character is '^]'.
set key1 0 60 4
zhou
STORED
get key1
VALUE key1 0 4
zhou
END
3.4 memcached java API使用
3.4.1 通过Memcached-Java-Client客户端连接memcached
Memcached-Java-Client源代码地址:https://github.com/gwhalin/Memcached-Java-Client
Memcached-Java-Client维基文档地址: https://github.com/gwhalin/Memcached-Java-Client/wiki
1)Memcached-Java-Client相关maven地址,在https://github.com/gwhalin/Memcached-Java-Client/wiki中
HOWTO中写道
3.0.x released, features = 2.6.x, but you can now get it from maven central, please notice:
since the domain danga.com is no more under our control(according to maven’s policy, the domain should be under authors’ control), the package name was replaced with “whalin.com”. If you don’t intend to rebuild your app, please use 2.6.×.
search “com.whalin” or “memcached java client” in search.maven.org, and you will find 3.0.×.
在maven中央仓库http://search.maven.org/查询结果如下:
2)eclipse中新建maven工程,然后在pom.xml中配置如下:
4.0.0
com.test
ehcachetest
0.0.1-SNAPSHOT
ehcachetest
jar
3.0.1
3.0.2
org.ehcache
ehcache
${ehcache.version}
com.whalin
Memcached-Java-Client
${memcached.version}
org.apache.maven.plugins
maven-resources-plugin
2.4.3
UTF-8
这里我需要现在我的虚拟机中启动三个memcached节点
脚本如下:
/usr/local/bin/memcached -d -m 10 -u root -l 192.168.202.131 -p 12000 -c 64 -P /tmp/memcached1.pid
/usr/local/bin/memcached -d -m 10 -u root -l 192.168.202.131 -p 12001 -c 64 -P /tmp/memcached2.pid
/usr/local/bin/memcached -d -m 10 -u root -l 192.168.202.131 -p 12002 -c 64 -P /tmp/memcached3.pid
package com.memcached.test;
import com.whalin.MemCached.MemCachedClient;
import com.whalin.MemCached.SockIOPool;
public class MyClass {
//创建单例
protected static MemCachedClient mcc = new MemCachedClient();
//初始化连接池
static {
//memcached服务器列表和各服务器权重
String[] servers =
{
"192.168.202.131:12000",
"192.168.202.131:12001",
"192.168.202.131:12002"
};
Integer[] weights = { 3, 3, 2 };
//获取连接池
SockIOPool pool = SockIOPool.getInstance();
//设置服务列表和权重
pool.setServers( servers );
pool.setWeights( weights );
// 设置连接池配置信息
// 初始化5连接,最小5连接,最大250连接
// 设置最大超时时间为6小时
pool.setInitConn( 5 );
pool.setMinConn( 5 );
pool.setMaxConn( 250 );
pool.setMaxIdle( 1000 * 60 * 60 * 6 );
// 设置连接池主线程休眠时间为30秒
pool.setMaintSleep( 30 );
// 设置TCP连接信息set some TCP settings
// 禁用nagle
// 设置读超时时间为3秒
// 禁用连接超时
pool.setNagle( false );
pool.setSocketTO( 3000 );
pool.setSocketConnectTO( 0 );
// 这里开始初始化连接池
pool.initialize();
// 这里是一些压缩方面设置,不过在2.0.2版本中已经抛弃不再使用
// compress anything larger than 64k
// mcc.setCompressEnable( true );
// mcc.setCompressThreshold( 64 * 1024 );
}
// 只要上面设置OK后,就能根据MemCachedClient调用memcached API
public static void main(String[] args) {
mcc.set( "foo", "This is a test String" );
String bar = (String) mcc.get( "foo" );
System.out.println(bar);
}
}
如果你需要让你的memcached服务器对Java, PHP, Perl等等客户端提供服务,你需要配置如下设置:
// 设置HASH算法,默认是SockIOPool.NATIVE_HASH
pool.setHashingAlg( SockIOPool.NEW_COMPAT_HASH );
// 是否将基本类型Boolean,Byte,String,Character,StringBuffer,StringBuilder,Short,Long,Double,Float,Date,Integer转换为String存储,默认是不转换的,设置转换的目的是节省空间和资源
// 对于非基本类型,这个参数设置是不起作用的
mcc.setPrimitiveAsString( true );
// 设置是否对key进行URL ENCODE,默认java客户端是进行URL ENCODE的
// 其他客户端是默认不进行URL ENCODE的
mcc.setSanitizeKeys( false );
关于memcached集群时候的故障转移参数设置
//集群中设置池的故障转移的标志
//当一个memcached服务器失效的时候客户端默认会failover另一个服务去
//如果失效的服务器恢复运行,客户端会failback到原来连接的服务器
//一般不要使用该功能
pool.setFailover( false );
pool.setFailback( false );
3.4.2 通过alisoft-xplatform-asf-cache客户端连接memcached
alisoft-xplatform-asf-cache是阿里软件的架构师岑文初进行封装的里面的注释都是中文的。目前没找到阿里正式发布该开源项目,也没在maven中央仓库找到相关信息,只在网上找到关于alisoft-xplatform-asf-cache的源代码,这里自己建了个maven工程,maven工程源代码详见附件alisoft-xplatform-asf-cache-src.zip(注意文件是GBK编码的,eclipse中自己设置下,无意冒犯阿里,这里实在是找不到其相关URL连接)
1)先自己下载alisoft-xplatform-asf-cache-src.zip将其install到本地maven仓库,然后pom.xml配置如下:
4.0.0
com.test
ehcachetest
0.0.1-SNAPSHOT
ehcachetest
jar
3.0.1
3.0.2
2.5.1
org.ehcache
ehcache
${ehcache.version}
com.whalin
Memcached-Java-Client
${memcached.version}
com.alisoft
alisoft-xplatform-asf-cache
${alisoft.memcached.version}
org.apache.maven.plugins
maven-resources-plugin
2.4.3
UTF-8
2)配置alisoft-xplatform-asf-cache需要的XML文件alisoft-memcached.xml
3)测试java代码如下:
package com.memcached.test;
import com.alisoft.xplatform.asf.cache.ICacheManager;
import com.alisoft.xplatform.asf.cache.IMemcachedCache;
import com.alisoft.xplatform.asf.cache.memcached.CacheUtil;
import com.alisoft.xplatform.asf.cache.memcached.MemcachedCacheManager;
public class AlisoftMemcachedTest {
public static void main(String[] args) {
ICacheManager manager;
manager = CacheUtil.getCacheManager(IMemcachedCache.class, MemcachedCacheManager.class.getName());
manager.setConfigFile("alisoft-memcached.xml");
manager.start();
try {
IMemcachedCache cache = manager.getCache("client_test_name");
cache.put("key", "value");
System.out.println(cache.get("key"));
} finally {
manager.stop();
}
}
}
3.5 利用magent搭建memcached集群
之前例子中使用memcached时缓存数据分布图如下:
上面的问题是如果中间一台机器宕机,那么缓存的部分数据就会丢失了,如下
magent的出现正是为了解决这个问题,
3.5.1 magent介绍
magent是一款开源的Memcached代理服务器软件。
magent项目网址为:http://code.google.com/p/memagent/
magent下载地址:https://code.google.com/archive/p/memagent/downloads
magent代理memcached实现主从备份来保证缓存数据完好无损,而且magent还可以作为从继续使用。
3.5.2 magent安装
这里完全参考http://www.php-note.com/article/detail/820,比较详细,这里说下自己真实安装遇到的问题。
1)主要安装步骤
#这里安装版本为magent-0.6,先创建个目录放置下载的安装文件
mkdir -p /opt/magent-0.6
cd /opt/magent-0.6
#下载
wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/memagent/magent-0.6.tar.gz
#解压
tar -zxvf magent-0.6.tar.gz
#安装
/sbin/ldconfig
sed -i "s#LIBS = -levent#LIBS = -levent -lm#g" Makefile
cd /opt/magent-0.6
make
#安装完后拷贝
cp /opt/magent-0.6/magent /usr/bin/magent
2)执行make是报错1
gcc -Wall -g -O2 -I/usr/local/include -m64 -c -o magent.o magent.c
magent.c: In function 'writev_list':
magent.c:729: error: 'SSIZE_MAX' undeclared (first use in this function)
magent.c:729: error: (Each undeclared identifier is reported only once
magent.c:729: error: for each function it appears in.)
make: *** [magent.o] Error 1
解决办法:编辑文件/opt/magent-0.6/ketama.h,在开头添加如下内容:
#ifndef SSIZE_MAX
#define SSIZE_MAX 32767
#endif
3)执行make遇到的错误2
gcc -Wall -g -O2 -I/usr/local/include -m64 -c -o magent.o magent.c
gcc -Wall -g -O2 -I/usr/local/include -m64 -c -o ketama.o ketama.c
gcc -Wall -g -O2 -I/usr/local/include -m64 -o magent magent.o ketama.o /usr/lib64/libevent.a /usr/lib64/libm.a
gcc: /usr/lib64/libevent.a: No such file or directory
gcc: /usr/lib64/libm.a: No such file or directory
解决办法:
因为我之前libevent是安装在/usr/local/lib,所以缺文件的话就执行下面命令建立了个软连接
ln -s /usr/local/lib/libevent* /usr/lib64/
4)执行make报错3
gcc -Wall -g -O2 -I/usr/local/include -m64 -o magent magent.o ketama.o /usr/lib64/libevent.a /usr/lib64/libm.a
gcc: /usr/lib64/libm.a: No such file or directory
make: *** [magent] Error 1
文章中说是要重新安装glibc glibc-devel,需要执行yum install -y glibc glibc-devel ,但我的不是这个问题
,最后是通过如下方式解决的
cp /usr/lib64/libm.so /usr/lib64/libm.a
5)执行make报错4
gcc -Wall -g -O2 -I/usr/local/include -m64 -o magent magent.o ketama.o /usr/lib64/libevent.a /usr/lib64/libm.a
/usr/lib64/libevent.a(event.o): In function `detect_monotonic':
event.c:(.text+0xc79): undefined reference to `clock_gettime'
/usr/lib64/libevent.a(event.o): In function `gettime':
event.c:(.text+0xd60): undefined reference to `clock_gettime'
collect2: ld returned 1 exit status
make: *** [magent] Error 1
解决办法,编辑文件/opt/magent-0.6/Makefile,修改前内容如下:
ARCH := $(shell uname -m)
X64 = x86_64
CC = gcc
PROGS = magent
ifeq ($(ARCH), $(X64))
M64 = -m64
LIBS = /usr/lib64/libevent.a /usr/lib64/libm.a
else
LIBS = -levent -lm -lm -L/usr/local/lib
endif
CFLAGS = -Wall -g -O2 -I/usr/local/include $(M64)
all: $(PROGS)
STPROG = magent.o ketama.o
ketama.o: ketama.c ketama.h
$(CC) $(CFLAGS) -c -o $@ ketama.c
magent.o: magent.c ketama.h
$(CC) $(CFLAGS) -c -o $@ magent.c
magent: $(STPROG)
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
clean:
rm -f *.o *~ $(PROGS)
编辑文件/opt/magent-0.6/Makefile,修改后内容如下:
ARCH := $(shell uname -m)
X64 = x86_64
CC = gcc
PROGS = magent
ifeq ($(ARCH), $(X64))
M64 = -m64
LIBS = /usr/lib64/libevent.a /usr/lib64/libm.a
else
LIBS = -levent -lm -lm -L/usr/local/lib
endif
CFLAGS = -lrt -Wall -g -O2 -I/usr/local/include $(M64)
all: $(PROGS)
STPROG = magent.o ketama.o
ketama.o: ketama.c ketama.h
$(CC) $(CFLAGS) -c -o $@ ketama.c
magent.o: magent.c ketama.h
$(CC) $(CFLAGS) -c -o $@ magent.c
magent: $(STPROG)
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
clean:
rm -f *.o *~ $(PROGS)
6)最后执行make成功,记录如下:
[root@master magent-0.6]# make
gcc -lrt -Wall -g -O2 -I/usr/local/include -m64 -o magent magent.o ketama.o /usr/lib64/libevent.a /usr/lib64/libm.a
[root@master magent-0.6]# pwd
/opt/magent-0.6
[root@master magent-0.6]# ll
total 624
-rw-rw-r-- 1 hadoop mysql 12822 Apr 10 2010 ketama.c
-rw-rw-r-- 1 hadoop mysql 393 May 15 21:08 ketama.h
-rw-r--r-- 1 root root 23616 May 15 21:08 ketama.o
-rwxr-xr-x 1 root root 394126 May 15 21:24 magent
-rw-r--r-- 1 root root 17257 May 15 20:52 magent-0.6.tar.gz
-rw-rw-r-- 1 hadoop mysql 54813 Apr 15 2010 magent.c
-rw-r--r-- 1 root root 112200 May 15 21:08 magent.o
-rw-rw-r-- 1 hadoop mysql 510 May 15 21:24 Makefile
[root@master magent-0.6]#
7)magent命令
magent命令详解
-h this message
-u uid
-g gid
-p port, default is 11211. (0 to disable tcp support)
-s ip:port, set memcached server ip and port
-b ip:port, set backup memcached server ip and port
-l ip, local bind ip address, default is 0.0.0.0
-n number, set max connections, default is 4096
-D do not go to background
-k use ketama key allocation algorithm
-f file, unix socket path to listen on. default is off
-i number, max keep alive connections for one memcached server, default is 20
-v verbose
3.5.3 magent搭建的memcached集群实例
这里参见的文章为:http://www.2cto.com/os/201506/406932.html
工作流程:
1.magent1,magent2接受写请求,将key分别写入mecached1-mecached4中,同时也将key写入从memcached上,也就是magent3上,magent3再分别写入mecached5,mecached6中;主和从都是用的同一个分配算法
2.magent1,magent2接受读请求,将分别向主memcached中进行读取,而不想从memcached中读取;
3.一旦mecached1-mecached4中有一个memcached宕掉,此时magent1和magent2将向从memcached,也就是magent3中读取数据,达到缓存数据不丢失的效果;
4.当主中的memcache恢复后,将再次加入主memcached中,此时magent1和magent2将不会向从memcached中读数据了,但是写仍正常进行
启动脚本
#memcached1-memcached6节点服务启动
memcached -d -m 10 -u root -l 192.168.202.131 -p 12001 -c 102400 -P /tmp/memcached1.pid
memcached -d -m 10 -u root -l 192.168.202.131 -p 12002 -c 102400 -P /tmp/memcached2.pid
memcached -d -m 10 -u root -l 192.168.202.131 -p 12003 -c 102400 -P /tmp/memcached3.pid
memcached -d -m 10 -u root -l 192.168.202.131 -p 12004 -c 102400 -P /tmp/memcached4.pid
memcached -d -m 10 -u root -l 192.168.202.131 -p 12005 -c 102400 -P /tmp/memcached5.pid
memcached -d -m 10 -u root -l 192.168.202.131 -p 12006 -c 102400 -P /tmp/memcached6.pid
#magent3代理服务启动
/usr/bin/magent -u root -n 102400 -l 192.168.202.131 -p 13003 -s 192.168.202.131:12005 -s 192.168.202.131:12006
#magent1代理服务启动
/usr/bin/magent -u root -n 102400 -l 192.168.202.131 -p 13001 -s 192.168.202.131:12001 -s 192.168.202.131:12002 -s 192.168.202.131:12003 -s 192.168.202.131:12004 -b 192.168.202.131:13003
#magent2代理服务启动
/usr/bin/magent -u root -n 102400 -l 192.168.202.131 -p 13002 -s 192.168.202.131:12001 -s 192.168.202.131:12002 -s 192.168.202.131:12003 -s 192.168.202.131:12004 -b 192.168.202.131:13003
启动后查看memcached服务如下:
启动后查看magent服务如下:
3.5.4 java API调用magent搭建的memcached集群服务
与之前不使用magent的区别
程序上的主要区别就是,以前提供的是memcached服务器的地址列表,现在只需提供magent服务器的地址列表就行了
java代码如下:
package com.memcached.test;
import com.whalin.MemCached.MemCachedClient;
import com.whalin.MemCached.SockIOPool;
public class MagentMemCachedClientTest {
//创建单例
protected static MemCachedClient mcc = new MemCachedClient();
//初始化连接池
static {
//memcached服务器列表和各服务器权重 ,这里现在配置magent代理服务器地址列表
String[] servers =
{
"192.168.202.131:13001",
"192.168.202.131:13002"
};
Integer[] weights = { 5, 5};
//获取连接池
SockIOPool pool = SockIOPool.getInstance();
//设置服务列表和权重
pool.setServers( servers );
pool.setWeights( weights );
// 设置连接池配置信息
// 初始化5连接,最小5连接,最大250连接
// 设置最大超时时间为6小时
pool.setInitConn( 5 );
pool.setMinConn( 5 );
pool.setMaxConn( 250 );
pool.setMaxIdle( 1000 * 60 * 60 * 6 );
// 设置连接池主线程休眠时间为30秒
pool.setMaintSleep( 30 );
// 设置TCP连接信息set some TCP settings
// 禁用nagle
// 设置读超时时间为3秒
// 禁用连接超时
pool.setNagle( false );
pool.setSocketTO( 3000 );
pool.setSocketConnectTO( 0 );
// 这里开始初始化连接池
pool.initialize();
/*
alg=0,SockIOPool.NATIVE_HASH 使用String.hashCode()获得hash code,该方法依赖JDK,可能和其他客户端不兼容,建议不使用
alg=1,SockIOPool.OLD_COMPAT_HASH 使用original 兼容hash算法,兼容其他客户端
alg=2,SockIOPool.NEW_COMPAT_HASH 使用CRC32兼容hash算法,兼容其他客户端,性能优于original算法
alg=3,SockIOPool.CONSISTENT_HASH 使用MD5 hash算法
采用前三种hash算法的时候,查找cache服务器使用余数方法。采用最后一种hash算法查找cache服务时使用consistent方法。
*/
pool.setHashingAlg( SockIOPool.NEW_COMPAT_HASH );
// 这里是一些压缩方面设置,不过在2.0.2版本中已经抛弃不再使用
// compress anything larger than 64k
// mcc.setCompressEnable( true );
// mcc.setCompressThreshold( 64 * 1024 );
}
// 只要上面设置OK后,就能根据MemCachedClient调用memcached API
public static void main(String[] args) {
mcc.set( "foo", "This is a test String" );
String bar = (String) mcc.get( "foo" );
System.out.println(bar);
}
}
4.redis
4.1 redis介绍
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。[1]
Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。
redis的官网地址,非常好记,是redis.io。(特意查了一下,域名后缀io属于国家域名,是british Indian Ocean territory,即英属印度洋领地)
目前,Vmware在资助着redis项目的开发和维护。
4.2 redis集群安装
1)下载、解压并编译redis
cd /opt
wget http://download.redis.io/releases/redis-3.2.0.tar.gz
tar -zxvf redis-3.2.0.tar.gz
cd /opt/redis-3.2.0
make
make install
在centos 7下遇到无法正常编译问题,主要是gcc和tcl未安装导致,报错是“/bin/sh: cc: command not found”和“You need tcl 8.5 or newer in order to run the Redis test”,解决方法是安装一下gcc和tcl,如下: