Memcache介绍
首先来说Memcache是一个开源高性能的分布式内存对象key-value缓存系统,用于加速动态的Web应用,从而减轻数据库的负载能力,在工作场景中很多人把它当做一个内存式的数据库在使用。那么内存式到底是什么呢?我们都知道,在计算机主要靠CPU来进行计算,内存用来存储CPU操作的数据。在计算机硬件中还有一个叫做硬盘的东西。那么这三者之间是怎么交互的。首先要知道计算机内存式有限的,这个是不可否认的,其次CPU的计算速度与内存以及外部存储之间是存在一定的差距的,所以就使用了一种高速缓存Cache的技术。来匹配内存与CPU之间的速度不匹配的问题。也就是说在计算机中能跟内存挂钩的都是速度比较搞的。Memcache被称为是内存式的缓存,那么它的效率一定是毋庸置疑。
它可以应对任意多个连接,使用非阻塞的网络IO,由于它的工作机制就是跟上面说的一样是直接操作内存,在内存中开辟的空间,然后建立Hash表,并且有Memcache自己来管理这些Hash表,这样的方式来进行缓存操作,再加上非阻塞的IO。执行的效率上要比一般的缓冲设计结构更高效。
Memcache 特点
协议简单
Memcache在服务端和客户端之间的通信中采用的是最为简单的文本协议,可以通过Telnet就可以在Memcache上存取数据。
基于Libevent的事件处理机制
Libevent是一套跨平台的事件处理接口的封装。首先要知道在不同操作系统中对于事件的操作是不一样的,例如在不同的Linux版本中操作IO事件有poll、epoll。在Windows中的select。当然在低版本的Linux中也有使用select的。那么这些在不同平台上的IO事件处理,在Memcache中都得到了解决,使用Libevent进行网络并发连接的处理,能够保证在高并发的情况下,任然可以保持快速响应的能力。
内置的内存存储方式
之前提到的Memcache中保存的数据都存储在Memcache内置的内存空间中,由于数据存储在内存中,所以当出现宕机或者是出现重启的时候就会导致内存中的数据丢失,都知道内存中的数据并不是持久化存储的。Memcache LRU(Least Recently Used)算法自动删除不使用的缓存,不过这个功能是可以进行配置的,Memcache通过启动“-M”参数可以禁止LRU,当是为了高效实用建议不要禁用。
不适用场景列举
缓存对象不能大于1MB,毕竟操作的是内存太大的话会导致内存消耗加速
key 的长度大于250字符,还是上面的原因
Memcache 未提供任何的安全策略,也就是说有些数据可以这里获取
不支持持久化,因为操作的是内存。
Memcache 安装
linux可参考材料教程,十分详细:https://www.runoob.com/memcached/memcached-install.html
windows:https://www.runoob.com/memcached/window-install-memcached.html
连接操作:https://www.runoob.com/memcached/memcached-connection.html
memcache 整合springboot
环境准备好后,我们开始来整合springboot ;以下整合的是这两种客户端
- SpyMemcached 停止更新
- XMemcached 主流
方式一:整合SpyMemcached
1、导入mvn坐标
<!--memcache SpyMemcached -->
<dependency>
<groupId>net.spy</groupId>
<artifactId>spymemcached</artifactId>
<version>2.12.2</version>
</dependency>
2、添加配置文件
通过@ConfigurationProperties(prefix = "springboot.memcache") 读取配置文件中以springboot.memcache为前缀的信息
package com.asiainfo.group.index.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author panghl
* @Date 2021/7/4 17:05
* @Description memcache 读取配置信息
**/
@Component
@ConfigurationProperties(prefix = "springboot.memcache")
public class MemcacheSource {
private String ip;
private int port;
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
编写配置类,连接memcached 将MemcachedClient 实例 注入ioc容器
package com.asiainfo.group.index.config;
import net.spy.memcached.MemcachedClient;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.net.InetSocketAddress;
/**
* @Author panghl
* @Date 2021/7/4 17:08
* @Description TODO
**/
@Component
public class MemcacheRunner implements CommandLineRunner {
@Resource
private MemcacheSource memcacheSource;
private MemcachedClient client = null;
@Override
public void run(String... args) throws Exception {
try {
client = new MemcachedClient(new InetSocketAddress(memcacheSource.getIp(),memcacheSource.getPort()));
}catch (IOException e){
e.printStackTrace();
}
}
public MemcachedClient getClient(){
return client;
}
}
3、编写配置文件
springboot:
memcache:
ip: 47.108.14.XXX //memcached 的ip
port: 11211 //端口
4、编写测试类
@Resource
private MemcacheRunner memcacheRunner;
@GetMapping("/set")
public BaseResponse set(String key ,String value) {
memcacheRunner.getClient().set(key,10,value);
return BaseResponse.sendResponse(RetCode.SUCCESS,value);
}
@GetMapping("/get")
public BaseResponse get(String key) {
String val = (String)memcacheRunner.getClient().get(key);
if (val ==null){
return BaseResponse.sendResponse(RetCode.SUCCESS,"缓存到期了");
}
return BaseResponse.sendResponse(RetCode.SUCCESS,val);
}
方式二:整合XMemcached
XMemcached介绍
是使用最为广泛的Memcache Java客户端,是一个全新的 Java Memcache Client。Memcache 通过它自定义协议与客户端交互,而XMemcached就是它的Java客户端实现,相比较于其他客户端来说XMemcached 的优点如下
XMemcached主要特性
XMemcached 支持设置连接池、宕机报警、使用二进制文件、一致性Hash、进行数据压缩等操作,总结下来有以下一些点
- 性能优势,使用的NIO
- 协议支持广泛
- 支持客户端分布,提供了一致性Hash 实现
- 允许设置节点权重,XMemcached允许通过设置节点的权重来调节Memcached的负载,设置的权重越高,该Memcached节点存储的数据就越多,所要承受的负载越大
- 动态的增删节点,Memcached允许通过JMX或者代码编程来实现节点的动态的添加或者删除操作。方便扩展或者替换节点。
- XMemcached 通过 JMX 暴露的一些接口,支持Client本身的监控和调整,允许动态设置调优参数、查看统计数据、动态增删节点等;
- 支持链接池操作。
- 可扩展性强,XMemcached是基于Java NIO框架 Yanf4j 来实现的,所以在结构上相对清晰,分层明确。
1、导入mvn坐标
<!-- XMemcached-->
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.5.6</version>
</dependency>
2、添加配置文件
通过@ConfigurationProperties(prefix = "memcached") 读取配置文件中以springboot.memcache为前缀的信息
package com.asiainfo.group.index.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @Author panghl
* @Date 2021/7/4 17:08
* @Description 读取配置信息
**/
@Component
@ConfigurationProperties(prefix = "memcached")
public class XMemcachedProperties {
private String servers;
private int poolSize;
private long opTimeout;
public String getServers() {
return servers;
}
public void setServers(String servers) {
this.servers = servers;
}
public int getPoolSize() {
return poolSize;
}
public void setPoolSize(int poolSize) {
this.poolSize = poolSize;
}
public long getOpTimeout() {
return opTimeout;
}
public void setOpTimeout(long opTimeout) {
this.opTimeout = opTimeout;
}
}
编写配置类,连接memcached 将MemcachedClient 实例 注入ioc容器
package com.asiainfo.group.index.config;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.utils.AddrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.io.IOException;
/**
* @Author panghl
* @Date 2021/7/4 17:31
* @Description MemcachedBuilder
**/
@Configuration
public class MemcachedBuilder {
protected static Logger logger = LoggerFactory.getLogger(MemcachedBuilder.class);
@Resource
private XMemcachedProperties xMemcachedProperties;
@Bean
public MemcachedClient getMemcachedClinet(){
MemcachedClient memcachedClient = null;
try {
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses(xMemcachedProperties.getServers()));
builder.setConnectionPoolSize(xMemcachedProperties.getPoolSize());
builder.setOpTimeout(xMemcachedProperties.getOpTimeout());
memcachedClient = builder.build();
}catch (IOException e){
logger.error("init MemcachedClient failed"+e);
}
return memcachedClient;
}
}
3、编写配置信息
memcached:
servers: 47.108.14.XXX:11211 //ip:端口
poolSize: 10 //连接池大小
opTimeout: 6000 //超时时间
4、编写测试类
@Resource
private MemcachedClient memcachedClient;
@GetMapping("/set")
public BaseResponse set(String key ,String value) {
try {
memcachedClient.set(key,10,value);
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (MemcachedException e) {
e.printStackTrace();
}
return BaseResponse.sendResponse(RetCode.SUCCESS,value);
}
@GetMapping("/get")
public BaseResponse get(String key) {
String val = null;
try {
val = (String)memcachedClient.get(key);
if (val ==null){
return BaseResponse.sendResponse(RetCode.SUCCESS,"缓存到期了");
}
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (MemcachedException e) {
e.printStackTrace();
}
return BaseResponse.sendResponse(RetCode.SUCCESS,val);
}