导语
随着公司的业务速度的提高,数据持久化的问题就凸显出来,很多的场景下使用的是缓存技术来解决请求数据库的压力,这种也是缓存技术使用最多的场景之一,当然在高并发、分布式Session场景下,也会使用缓存技术来提高系统的可用性。在工作中比较常用的是Redis,当然在有些场景下使用的是Memcache。这里首先来介绍一下关于Memcache 的使用
文章目录
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 安装
这里介绍的是在Ubuntu下的安装。
安装Memcache服务端
sudo apt-get install memcached
root@nihui-PC:~# apt-get install memcached
正在读取软件包列表... 完成
正在分析软件包的依赖关系树
正在读取状态信息... 完成
建议安装:
libcache-memcached-perl libmemcached libanyevent-perl libyaml-perl libterm-readkey-perl
下列【新】软件包将被安装:
memcached
升级了 0 个软件包,新安装了 1 个软件包,要卸载 0 个软件包,有 184 个软件包未被升级。
需要下载 122 kB 的归档。
解压缩后会消耗 295 kB 的额外空间。
获取:1 http://packages.deepin.com/deepin panda/main amd64 memcached amd64 1.5.6-1 [122 kB]
已下载 122 kB,耗时 0秒 (277 kB/s)
正在选中未选择的软件包 memcached。
(正在读取数据库 ... 系统当前共安装有 192272 个文件和目录。)
正准备解包 .../memcached_1.5.6-1_amd64.deb ...
正在解包 memcached (1.5.6-1) ...
正在设置 memcached (1.5.6-1) ...
Created symlink /etc/systemd/system/multi-user.target.wants/memcached.service → /lib/systemd/system/memcached.service.
正在处理用于 systemd (238-5) 的触发器 ...
正在处理用于 man-db (2.8.3-2) 的触发器 ...
安装完Memcache服务端以后,我们需要启动该服务:
memcached -d -m 128 -p 11111 -u root
这里需要说明一下memcached服务的启动参数:
-p 监听的端口
-l 连接的IP地址, 默认是本机
-d start 启动memcached服务
-d restart 重起memcached服务
-d stop|shutdown 关闭正在运行的memcached服务
-d install 安装memcached服务
-d uninstall 卸载memcached服务
-u 以的身份运行 (仅在以root运行的时候有效)
-m 最大内存使用,单位MB。默认64MB
-M 内存耗尽时返回错误,而不是删除项
-c 最大同时连接数,默认是1024
-f 块大小增长因子,默认是1.25-n 最小分配空间,key+value+flags默认是48
-h 显示帮助
root@nihui-PC:~# memcached -d -m 128 -p 11111 -u root
root@nihui-PC:~#
root@nihui-PC:~# ps -ef|grep memcache
memcache 5395 1 0 12:07 ? 00:00:00 /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1 -P /var/run/memcached/memcached.pid
root 6272 1 0 12:09 ? 00:00:00 memcached -d -m 128 -p 11111 -u root
root 6621 3648 0 12:11 pts/1 00:00:00 grep memcache
root@nihui-PC:~#
会发现其中启动了两个 Memcache实例,其中一个是使用上面的命令启动的,一个是默认启动的。
Memcache客户端
Memcache Clinet 目前支持3种。
- Memcached Client for Java停止更新
- SpyMemcached 停止更新
- 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 来实现的,所以在结构上相对清晰,分层明确。
快速开始
上的内容都是用来给大家做铺垫的,下面才是真正的干货。首先先来感受一下SpringBoot是怎么集成Memcache。
1. 增加依赖管理
添加关于memcache的依赖
<!-- https://mvnrepository.com/artifact/com.googlecode.xmemcached/xmemcached -->
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.4.5</version>
</dependency>
详细配置如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.nh.memcache</groupId>
<artifactId>memcache</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>memcache</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/com.googlecode.xmemcached/xmemcached -->
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.4.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.添加配置文件
当然在添加配置文件的时候,SpringBoot默认没有支持自动配置所以需要使用SpringBoot提供的配置文件机制来编写自己的配置文件。
首先编写一个配置文件的Properties对象用来与配置文件进行映射
/**
* @Classname XMemcachedProperties
* @Description TODO
* @Date 2019/9/21 12:41 PM
* @Created by nihui
*/
@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;
}
}
编写Memcache的配置类使用@Configration注解进行标注表明这个是一个配置类
/**
* @Classname MemcachedBuilder
* @Description TODO
* @Date 2019/9/21 12:44 PM
* @Created by nihui
*/
@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.注入组件
如上代码在配置类中注入一个MemcacheClient的Bean对象,并且设置了一些基本的参数,而这些参数都是由配置文件来提供
@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;
}
4.编写配置文件
根据上面配置类的内容,可以知道需要配置如下的三个参数,服务地址、线程池大小、超时时间,当然为了高可用的话还可以将服务地址设置成一个数组。这里是测试就先不用高可用。
memcached.servers=10.2.116.178:11111
memcached.poolSize=10
memcached.opTimeout=6000
5.编写测试类
这里使用默认的SpringBoot自带的测试类进行测试。测试缓存的get和set方法。
@RunWith(SpringRunner.class)
@SpringBootTest
public class MemcacheApplicationTests {
@Autowired
private MemcachedClient memcachedClient;
@Test
public void contextLoads() throws Exception {
memcachedClient.set("hello",0,"Hello,xmemcached");
String value = memcachedClient.get("hello");
System.out.println("hello = "+ value);
memcachedClient.delete("hello");
}
}
可以看到存储数据是通过set方法还有设置了其三个参数,第一个参数表示key,第一个参数表示expire时间单位是秒,超过这个时间memcached将这个数据替换出去,0表示永久存储,默认是一个月,第三个参数就是实际存储的数据,可以是任意的Java可序列化类型,当然也可以继承序列化接口Serializable,或者是可以序列化为指定类型,当然这里要满足Value的大小设定,超过大小将不会被缓存。
总结
上面简单的介绍了关于Memcache以及如何使用SpringBoot来整合Memcache,当然上面只是举例了一个简单的小例子。后面的博客中还会有更多的关于memcache 的使用在等着大家,希望大家可以多多支持。