传统关系型数据:Oracle 、 Mysql 指标
缓存类型:
1.本地缓存
2.客户端缓存
3.分布式缓存
缓存的设计指标:
常用缓存技术:
ehcache oscache memcached redis tair
Memcached 是一款开源、免费、高性能的分布式内存对象缓存系统
Memcached是一种基于内存的key-value存储,用于存储小块
的任意数据(字符串、对象)
Memcached简洁且强大。它的简洁设计便于快捷开发、减轻开发难度,解决了大数据缓存的很多问题。它的api兼容大部分流行的开发语言。
老牌的、轻量级、高性能、key-value类型的分布式缓存系统,主要用于分布式Web应用中去减轻数据库的负载(压力),提高了访问速度。
将缓存的功能剥离出去,存在于其他的服务器中称之为分布式缓存。
本地缓存,缓存本身存在于本地的机器中,类似mybatis的缓存
tomcat集群对session的管理方式
上述两种方式都有缺陷:(1)内存告急(2)单点故障
从宏观上来说应用服务器进行了无状态化的处理。
思考:为什么需要进行无状态化处理?
http://memcached.org/downloads
在此下载页面中下载tar包解压即可
安装
yum install libevent-devel
yum install gcc
解压
tar -zxvf memcached-1.4.31.tar.gz
cd memcached-1.4.31
# 指定memcached安装⽬目录
./configure --prefix=/usr/local/memcached
make && make install
// 注意 以下 latest memcached-1.x.x.tar.gz 都是模糊链接(想要下载需要输入正确版本号)
wget http://memcached.org/latest
tar -zxvf memcached-1.x.x.tar.gz
cd memcached-1.x.x
./configure && make && make test && sudo make install
cd /usr/local/memcached/bin (这里指的是memcached的安装路径下载bin目录)
# 帮助命令
./memcached -h
# ---------------------参数说明----------------------
-p <num> TCP端⼝口,默认为11211,可以不不设置
-l <addr> 监听的 IP 地址,本机可以不不设置此参数
-d 以守护程序(daemon)⽅方式运⾏行行
-u 指定⽤用户,如果当前为 root ,需要使⽤用此参数指定⽤用户
-m <num> 最⼤大内存使⽤用,单位MB。默认64MB
-M 禁⽌止LRU策略略,内存耗尽时返回错误,⽽而不不是删除项
-c <num> 最⼤大同时连接数,默认是1024
-t <num> 线程数,默认4。由于memcached采⽤用NIO,所以更更多线程没有太多作⽤用
-v ⽇日志(错误和警告)
-vv ⽇日志(错误、警告、客户端命令和响应)
-vvv ⾮非常详细的⽇日志
cd /usr/local/memcached/bin
./memcached -m 128mb -vv -u root
Memcached可以通过 telnet 命令并指定主机ip和端⼝口来连接 Memcached 服务
例如:telnet HOST PORT
telnet localhodt 11211
# 存值语法
set key flags exptime bytes
value
key:键值 key-value 结构中的 key,⽤用于查找缓存值。
flags:可以包括键值对的整型参数,客户机使⽤用它存储关于键值对的额外信息 。
exptime:在缓存中保存键值对的时间⻓长度(以秒为单位,0 表示永远)
bytes:在缓存中存储的字节数
# 取值语法
get key
# stats 命令⽤用于返回统计信息例例如 PID(进程号)、版本号、连接数等
stats
XMemcached是基于Java NIO的Memcached客户端,Java NIO相⽐比于传统阻塞io模型来说,有效率 ⾼高(特别在
高并发下)和资源耗费相对较少的优点。
高性能
支持完整协议
支持客户端分布
动态增删节点
允许设置节点权重
<!--
https://mvnrepository.com/artifact/com.googlecode.xmemcached/xmemcached -->
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.2</version>
</dependency>
package com.baizhi;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.exception.MemcachedException;
import net.rubyeye.xmemcached.utils.AddrUtil;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* Unit test for simple App.
*/
public class AppTest {
public static void main(String[] args) throws IOException {
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("192.168.21.143:11211"));
MemcachedClient memcachedClient = builder.build();
try {
// 存储数据 参数⼀一:key名 参数⼆二:expire时间(单位秒)表示永久存储(默认是⼀一个⽉月)
// 参数三:value值
memcachedClient.set("hello",0,"hello baby");
// 获取数据
String value = memcachedClient.get("hello");
System.out.println("hello=" + value);
// 删除数据
memcachedClient.delete("hello");
// 获取数据
String value2 = memcachedClient.get("hello");
System.out.println("hello=" + value2);
} catch (TimeoutException e) {
System.err.println("******MemcachedClient operation timeout");
e.printStackTrace();
} catch (InterruptedException e) {
System.err.println("******MemcachedClient operation ignore");
e.printStackTrace();
} catch (MemcachedException e) {
System.err.println("******MemcachedClient operation fail");
e.printStackTrace();
} finally {
memcachedClient.shutdown();
}
}
}
Memcached的分布是通过客户端实现的,客户端根据key的哈希值得到将要存储的memcached节点,并将对应的value存储到相应的节点。
原理可以参考:https://www.cnblogs.com/lpfuture/p/5796398.html
首先求出memcached服务器(节点)的哈希值,并将其配置到0-2的32次方的圆(continuum)上。
然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。
然后从数据映射到位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器码,就会保存到第一台memcached服务器上
添加一台memcached服务器。余数分布式算法由于保存键的服务器会发生巨大变化而影响缓存的命中率,但
Consistent Hashing 中,只有在圆(continuum)上增加服务器的地点逆时针方向的第一台服务器上键会受到
影响,如下图所示:
参考资料:https://blog.csdn.net/qq_34337272/article/details/81072874
Memcached是通过CAS协议实现原子更新,所谓原子更新就是compare and set,原理类似乐观锁,每次请求存储
某个数据同时要附带一个CAS值,memcached比对这个CAS值与当前存储数据的CAS值是否相等,如果相等就让新的
数据覆盖老的数据,如果不相等就认为更新失败,这在并发环境下特别有用。
GetsResponse<Integer> result = client.gets("a");
long cas = result.getCas();
//尝试将a的值更新为2
if (!client.cas("a", 0, 2, cas)) {
System.err.println("cas error");
}
从1.4.2开始xmemcached提供了memcached命名空间的封装使用,你可以将一组缓存项放到同一个命名空间下,
可以让整个命名空间所有的缓存项同时失效
String ns = "namespace" ;
this.memcachedClient.withNamespace(ns,new MemcachedClientCallable<Void>() {
public Void call(MemcachedClientclient)throwsMemcachedException,InterruptedException,
TimeoutException {
//a,b,c都在namespace下
client.set("a",0,1);
client.set("b",0,1);
client.set("c",0,1);
return null;
}
});
//获取命名空间内的a的对应值
Integer aValue = this.memcachedClient.withNamespace(ns,
new MemcachedClientCallable<Integer>() {
public Integer call(MemcachedClientclient)throwsMemcachedException, InterruptedException,TimeoutException {
return client.get("a");
}
});
//使得命名空间失效
this.memcachedClient.invalidateNamespace(ns);
注意:更全面的例子、迭代所有的key、Incr/Decr、查看统计信息、Spring框架继承等可参阅Xmemcached用户指南。
Memcached的分布是通过客户端实现的(具体可参阅:章节三值客户端分布)
如:使用Memcached管理MyBatis二级缓存,构建分布式缓存
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-memcached</artifactId>
<version>1.0.0</version>
</dependency>
配置Mapper文件
<mapper namespace="org.acme.FooMapper">
<cache type="org.mybatis.caches.memcached.MemcachedCache" />
...
</mapper>
4.需要日志缓存操作
<mapper namespace="org.acme.FooMapper">
<cache type="org.mybatis.caches.memcached.LoggingMemcachedCache" />
...
</mapper>
5.测试缓存
如:服务器session集中式管理
参考资料:https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration
导入jar包到服务器tomcat\lib目录
memcached-session-manager-${version}.jar
memcached-session-manager-tc7-1.9.7.jar
spymemcached-2.11.1.jar
选择序列化方案所有相关的jar包(这里使用kyro)
修改配置文件
vi ~/tomcat1/conf/context.xml
<Manager
className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:192.168.128.137:11211,n2:192.168.128.137:11311"
sticky="false"
sessionBackupAsync="false"
lockingMode="uriPattern:/path1|/path2"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>
vi ~/tomcat2/conf/context.xml
<Manager
className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="n1:192.168.128.137:11211,n2:192.168.128.137:11311"
sticky="false"
sessionBackupAsync="false"
lockingMode="uriPattern:/path1|/path2"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/>
3.分别启动tomcat1和tomcat2测试