一、概述
传统关系型数据:Oracle 、 Mysql 指标
- 容量 2000W
- tps 1500个
- 响应时间:10MS
缓存类型:
1.本地缓存
2.客户端缓存
3.分布式缓存
缓存的设计指标:
- 容量 key-value
- tps 12W
- 成本 (64G 128G )
- 响应时间
常用缓存技术:
ehcache oscache memcached redis tair
二、Memcached 基本介绍
Memcached 是一款开源、免费、高性能的分布式内存对象缓存系统
Memcached是一种基于内存的key-value存储,用于存储小块
的任意数据(字符串、对象)
Memcached简洁且强大。它的简洁设计便于快捷开发、减轻开发难度,解决了大数据缓存的很多问题。它的api兼容大部分流行的开发语言。
- 感性认知
老牌的、轻量级、高性能、key-value类型的分布式缓存系统,主要用于分布式Web应用中去减轻数据库的负载(压力),提高了访问速度。
- Memcached
- key-value
- 不支持持久化
- 不支持服务端集群
- 255字符 1mB
- 最大存储时长 30day
三、使用场景
1.分布式缓存
将缓存的功能剥离出去,存在于其他的服务器中称之为分布式缓存。
本地缓存,缓存本身存在于本地的机器中,类似mybatis的缓存
- 优点
- 减少缓存给应用服务器带来压力
- 本地缓存变为分布式缓存,缓存命中率高、节省内存
- 缺点
- 服务集中化(单点故障)-成本的提高
- 带来额外的网络io开销-缓存服务器在同一局域网(同一机房/机架/城市/地区)
2.会话Session管理
tomcat集群对session的管理方式
- tomcat之间进行session的复制
- 通过nginx锁定用户,用户所有的访问都在一台机器当中
上述两种方式都有缺陷:(1)内存告急(2)单点故障
从宏观上来说应用服务器进行了无状态化的处理。
思考:为什么需要进行无状态化处理?
四、环境搭建
安装
- 本地上传安装
http://memcached.org/downloads
在此下载页面中下载tar包解压即可
yum install libevent-devel
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 ⾮非常详细的⽇日志
启动
./memcached -m 128mb -vv -u root
命令
Memcached可以通过 telnet 命令并指定主机ip和端⼝口来连接 Memcached 服务
例如:telnet HOST PORT
# 存值语法
set key flags exptime bytes
value
key:键值 key-value 结构中的 key,⽤用于查找缓存值。
flags:可以包括键值对的整型参数,客户机使⽤用它存储关于键值对的额外信息 。
exptime:在缓存中保存键值对的时间⻓长度(以秒为单位,0 表示永远)
bytes:在缓存中存储的字节数
# 取值语法
get key
# stats 命令⽤用于返回统计信息例例如 PID(进程号)、版本号、连接数等
stats
:可以包括键值对的整型参数,客户机使⽤用它存储关于键值对的额外信息 。
exptime:在缓存中保存键值对的时间⻓长度(以秒为单位,0 表示永远)
bytes:在缓存中存储的字节数
# 取值语法
get key
# stats 命令⽤用于返回统计信息例例如 PID(进程号)、版本号、连接数等
stats
[root@HadoopNode00 ~]# telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
set key 0 0
ERROR
set baizhi 0 0 5
set baizhi 0 0 6
CLIENT_ERROR bad data chunk
ERROR
set bai 0 0 3
mby
STORED
get bai
VALUE bai 0 3
mby
END
set bai 0 0 3
12
set zhi 0 0 3
CLIENT_ERROR bad data chunk
ERROR
set zhi 0 0 3
maby
CLIENT_ERROR bad data chunk
ERROR
set zhi 0 0 3
weq
STORED
get zhi
VALUE zhi 0 3
weq
END
<36 new auto-negotiating client connection
36: Client using the ascii protocol
<36 set key 0 0
>36 ERROR
<36 set baizhi 0 0 5
>36 CLIENT_ERROR bad data chunk
<36 zhi 0 0 6
>36 ERROR
<36 set bai 0 0 3
>36 STORED
<36 get bai
>36 sending key bai
>36 END
<36 set bai 0 0 3
>36 CLIENT_ERROR bad data chunk
<36 et zhi 0 0 3
>36 ERROR
<36 set zhi 0 0 3
>36 CLIENT_ERROR bad data chunk
<36
>36 ERROR
<36 set zhi 0 0 3
>36 STORED
<36 get zhi
>36 sending key zhi
>36 END
Memcached
一、概述
传统关系型数据的指标:
- 容量 2000W条 2. tps 1500个 3. 响应时间 10ms
缓存类型: - 本地缓存
- 客户端缓存
- 分布式缓存
缓存设计指标: - 容量
key–value - tps 12W
- 成本
- 响应时间
常用的缓存技术:
ehcache、oscache、memcached、redis、tair
二、Memcached基本介绍
Memcached是一款开源免费,高性能的分布式内存对象缓存系统。
Memcached是一种基于内存的key-value存储,用来存储小块的任意数据(字符串、对象)
Memcached简洁且强大。它的简洁设计便于快捷开发,减轻开发难度,解决了大数据缓存的很多问题。它的api兼容
大部分流行的开发语言。
感性认知
老牌的、轻量级的、高性能的、key-value类型的分布式缓存系统,主要用于分布式的Web应用中去减轻数据库
的负载(压力),提高数据访问速度。
Memcached 特点
key-value
不支持持久化
不支持服务集群
255字符 1MB
最大存储时长30 day
三、使用场景 - 分布式缓存
将缓存的功能剥离出去,存在于其他的服务器中称之为分布式缓存。
与分布式缓存对应的就是本地缓存,缓存本身就存在本地中,类似之前学习到mybatis二级缓存。
Memcached作为分布式缓存的角色存在。
优点
减少缓存给应用服务器带来压力
本地缓存不使用与分布式环境,缓存命中率低/内存浪费
缺点
服务集中化通病(单点故障)-需要满足高可用、主从等需求,随之而来就是成本的提升
带来额外的网络IO开销-缓存服务器需要和应用服务器在用一个局域网内里 - 会话Session管理
Tomcat集群中对Session管理方式:
tomcat 之间进行session的复制
通过nginx锁定用户,用户所有的访问几种在一台机器中
上述两种方式都有缺陷,第一种虽然保证了Session所有的用户都可以用,但是内存告急!第二种如果tomcat出
现故障用户则丢失了Session,用户体验就变得糟糕。
这个时候可以将会话Session交给缓存服务器集中管理。
从宏观上来说就是应用服务器进行无状态化处理。
思考:为什么应用服务器进行无状态处理?
四、环境搭建
安装
本地上传安装
云端下载安装
参数说明
http://memcached.org/downloads 在此下载页面中下载tar包解压即可
yum install libevent-devel
tar -zxvf memcached-1.4.31.tar.gz
cd memcached-1.4.31
#指定memcached安装⽬目录
./configure --prefix=/usr/local/memcached
make && make instal
// 注意 以下 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
---------------------参数说明----------------------
启动
命令
例如: telnet HOST PORT
五、Java客户端
XMemcached是基于Java NIO的Memcached客户端,Java NIO相⽐比于传统阻塞io模型来说,有效率 ⾼高(特别在
高并发下)和资源耗费相对较少的优点。
特性
高性能
支持完整协议
支持客户端分布
动态增删节点
允许设置节点权重
Maven坐标
-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 非常详细的日志
./memcached -m 128mb -vv -u root Memcached
可以通过 telnet 命令并指定主机ip和端⼝口来连接 Memcached 服务
存值语法
set key flags exptime bytes value
key:键值 key-value 结构中的 key,⽤用于查找缓存值。 flags:可以包括键值对的整型参数,客户机使⽤用它存储关于键值对的额外信息 。
exptime:在缓存中保存键值对的时间⻓长度(以秒为单位,0 表示永远)
bytes:在缓存中存储的字节数
# 取值语法
get key
# stats 命令⽤用于返回统计信息例例如 PID(进程号)、版本号、连接数等 stats
简单示例
`<!-- 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 io.gjf; 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; /*** Create by GuoJF on 2019/2/19 */ public class Main { public static void main(String[] args) throws Exception { MemcachedClientBuilder builder = new XMemcachedClientBuilder( // 多个Memcached Server:host1:port1 // host2:port2 AddrUtil.getAddresses("192.168.134.140:11211")); MemcachedClient memcachedClient = builder.build(); try {// 存储数据 参数⼀一:key名 参数⼆二:expire时间(单位秒)表示永久存储(默认是⼀一个⽉月) //参数三:value值 memcachedClient.set("hello", 0, "Hello,xmemcached"); // 获取数据 String value = memcachedClient.get("hello"); System.out.println("hello=" + value); // 删除数据 memcachedClient.delete("hello"); value = memcachedClient.get("hello"); System.out.println("hello=" + value); } catch (MemcachedException e) { System.err.println("MemcachedClient operation fail"); e.printStackTrace(); } catch (TimeoutException e) {
```java
## 客户端分布
Memcached的分布是通过客户端实现的,客户端根据key的哈希值得到将要存储的memcached节点,并将对应的
value存储到相应的节点。
System.err.println("MemcachedClient operation timeout"); e.printStackTrace();
}
catch (InterruptedException e)
{ // ignore
}try {//close memcached client memcachedClient.shutdown(); } catch (IOException e)
{ System.err.println("Shutdown MemcachedClient fail"); e.printStackTrace();
} } }
1.余数算法(默认)
按照key的哈希值模以连接数得到的余数,对应的连接就是将要存储的节点
key.hashCode() % nodeCount = nodeIndex
缺点:如果服务器数量发生变化,所有的服务器的缓存在同一时间失效,会导致所有压力都在一个时间集中到数据库服务器上
2.一致性哈希
原理可以参考:https://www.cnblogs.com/lpfuture/p/5796398.html
首先求出memcached服务器(节点)的哈希值,并将其配置到0-2的32次方的圆(continuum)上。
然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。
然后从数据映射到位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器
码,就会保存到第一台memcached服务器上
添加一台memcached服务器。余数分布式算法由于保存键的服务器会发生巨大变化而影响缓存的命中率,但
Consistent Hashing 中,只有在圆(continuum)上增加服务器的地点逆时针方向的第一台服务器上键会受到
影响,如下图所示:
CAS操作
参考资料:https://blog.csdn.net/qq_34337272/article/details/81072874
Memcached是通过CAS协议实现原子更新,所谓原子更新就是compare and set,原理类似乐观锁,每次请求存储
某个数据同时要附带一个CAS值,memcached比对这个CAS值与当前存储数据的CAS值是否相等,如果相等就让新的
数据覆盖老的数据,如果不相等就认为更新失败,这在并发环境下特别有用。
CAS协议其实是分为两个步骤:获取CAS值和尝试更新
命名空间
从1.4.2开始xmemcached提供了memcached命名空间的封装使用,你可以将一组缓存项放到同一个命名空间下,
可以让整个命名空间所有的缓存项同时失效
GetsResponse result = client.gets(“a”); long cas = result.getCas(); //尝试将a的值更新为2 if (!client.cas(“a”, 0, 2, cas)) { System.err.println(“cas error”); }String ns = “namespace” ; this.memcachedClient.withNamespace(ns,
注意:更全面的例子、迭代所有的key、Incr/Decr、查看统计信息、Spring框架继承等可参阅Xmemcached用户指
南。
六、应用
分布式集群
Memcached的分布是通过客户端实现的(具体可参阅:章节三值客户端分布)
数据库缓存
如:使用Memcached管理MyBatis二级缓存,构建分布式缓存
参考资料:
- Maven坐标
- 配置Mapper文件
new MemcachedClientCallable() { public Void call(MemcachedClient client) throws MemcachedException, 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() { public Integer call(MemcachedClient client) throws MemcachedException, InterruptedException, TimeoutException { return client.get(“a”); }}); //使得命名空间失效 this.memcachedClient.invalidateNamespace(ns); org.mybatis.caches mybatis-memcached 1.0.0
Property Default Description org.mybatis.caches.memcached.keyprefix mybatis any string identifier org.mybatis.caches.memcached.servers localhost:11211 space separated list of h o s t : {host}: host:{port} org.mybatis.caches.memcached.connectionfactory net.spy.memcached.DefaultConnectionFactory Any class that implements net.spy.memcached.ConnectionFactory org.mybatis.caches.memcached.expiration the number of seconds in 30 days the expiration time (in seconds) org.mybatis.caches.memcached.asyncget false flag to enable/disable the async get org.mybatis.caches.memcached.timeout 5 the timeout when using async get org.mybatis.caches.memcached.timeoutunit java.util.concurrent.TimeUnit.SECONDS the timeout unit when using async get org.mybatis.caches.memcached.compression false if true, objects will be GZIP compressed before putting them to Memcached - 准备配置文件(memcached.properties)并放置在src/main/resources/下,
- 如果未提供
将使用默认配置
4.需要日志缓存操作
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 ---------------------------------------------------------------------- vi ~/tomcat2/conf/context.xml 3. 分别启动tomcat1和tomcat2测试
package io.gjf;
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;
/*** Create by GuoJF on 2019/2/19 */
public class Test {
public static void main(String[] args) throws Exception {
// 多个Memcached Server:host1:port1 // host2:port2
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("192.168.89.101:11211"));
MemcachedClient memcachedClient = builder.build();
try {// 存储数据 参数⼀一:key名 参数⼆二:expire时间(单位秒)表示永久存储(默认是⼀一个⽉月) //参数三:value值
memcachedClient.set("hello", 0, "Hello,xmemcached");
// 获取数据
String value = memcachedClient.get("hello");
System.out.println("hello=" + value); // hello=Hello,xmemcached
// 删除数据
memcachedClient.delete("hello");
value = memcachedClient.get("hello");
System.out.println("hello=" + value); // hello=null
} catch (MemcachedException e) {
System.err.println("MemcachedClient operation fail");
e.printStackTrace();
} catch (TimeoutException e) {
/**客户端分布
Memcached的分布是通过客户端实现的,客户端根据key的哈希值得到将要存储的memcached节点,并将对应的
value存储到相应的节点。*/
System.err.println("MemcachedClient operation timeout");
e.printStackTrace();
} catch (InterruptedException e) {
// ignore
}
try {
//close memcached client
memcachedClient.shutdown();
} catch (IOException e) {
System.err.println("Shutdown MemcachedClient fail");
e.printStackTrace();
}
}
}
package io.gjf;
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;
/*** Create by GuoJF on 2019/2/19 */
public class ObjectTest {
public static void main(String[] args) throws Exception {
// 多个Memcached Server:host1:port1 // host2:port2
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("192.168.89.101:11211"));
MemcachedClient memcachedClient = builder.build();
try {// 存储数据 参数⼀一:key名 参数⼆二:expire时间(单位秒)表示永久存储(默认是⼀一个⽉月) //参数三:value值
Person person = new Person("001","maby1",1);
memcachedClient.set("hello", 0, person);
// 获取数据
Person value = memcachedClient.get("hello");
System.out.println("hello=" + value); // hello=Person{id='001', name='maby1', age=1}
// 删除数据
memcachedClient.delete("hello");
value = memcachedClient.get("hello");
System.out.println("hello=" + value); // hello=null
} catch (MemcachedException e) {
System.err.println("MemcachedClient operation fail");
e.printStackTrace();
} catch (TimeoutException e) {
/**客户端分布
Memcached的分布是通过客户端实现的,客户端根据key的哈希值得到将要存储的memcached节点,并将对应的
value存储到相应的节点。*/
System.err.println("MemcachedClient operation timeout");
e.printStackTrace();
} catch (InterruptedException e) {
// ignore
}
try {
//close memcached client
memcachedClient.shutdown();
} catch (IOException e) {
System.err.println("Shutdown MemcachedClient fail");
e.printStackTrace();
}
}
}