Memcached簡介
Memcached 是一個高性能的分佈式內存對象緩存系統,用於動態Web應用以減輕數據庫負載。它通過在內存中緩存數據和對象來減少讀取數據庫的次數,從而提高動態、數據庫驅動網站的速度。Memcached基於一個存儲鍵/值對的hashmap。其守護進程(daemon )是用C寫的,但是客戶端可以用任何語言來編寫,並通過memcached協議與守護進程通信。
爲了提高性能,memcached中保存的數據都存儲在memcached內置的內存存儲空間中。由於數據僅存在於內存中,因此重啓memcached、重啓操作系統會導致全部數據消失。另外,內容容量達到指定值之後,就基於LRU(Least Recently Used)算法自動刪除不使用的緩存。memcached本身是爲緩存而設計的服務器,因此並沒有過多考慮數據的永久性問題。
Memcached安裝
我是參考這個安裝的:https://www.runoob.com/memcached/window-install-memcached.html
Java客戶端選型
根據閱讀這篇文章,最後選擇使用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
依賴
Maven依賴:
<!--memcache-->
<!-- https://mvnrepository.com/artifact/com.googlecode.xmemcached/xmemcached -->
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.4.5</version>
</dependency>
<!--使用註解處理器來生成自己的元數據:參考:https://www.jianshu.com/p/57fec884c017-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
配置
當然在添加配置文件的時候,SpringBoot默認沒有支持自動配置所以需要使用SpringBoot提供的配置文件機制來編寫自己的配置文件。
1、application.yml添加配置:
# ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ memcache 配置 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ #
spring:
memcache:
# memcached服務器節點
servers: 127.0.0.1:11211
# nio連接池的數量
poolSize: 10
# 設置默認操作超時
opTimeout: 3000
# 是否啓用url encode機制
sanitizeKeys: false
2、新建 XMemcachedProperties 類,用於保存yml中的配置
package com.blog.www.config.memcache;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* XMemcached 配置屬性,讀取的是 yml 文件中 spring.memcached 開頭的屬性
*/
@ConfigurationProperties(prefix = "spring.memcached")
@PropertySource("classpath:application.yml")
@Configuration
@Data
public class XMemcachedProperties {
/**
* memcached服務器節點
*/
private String servers;
/**
* nio連接池的數量
*/
private Integer poolSize;
/**
* 設置默認操作超時
*/
private Long opTimeout;
/**
* 是否啓用url encode機制
*/
private Boolean sanitizeKeys;
}
3、新建 MemcachedConfig 初始化配置
package com.blog.www.config.memcache;
import lombok.extern.slf4j.Slf4j;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.command.BinaryCommandFactory;
import net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator;
import net.rubyeye.xmemcached.utils.AddrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
/**
* Memcached 配置
*/
@Configuration
@Slf4j
public class MemcachedConfig {
@Autowired
private XMemcachedProperties xMemcachedProperties;
@Bean
public MemcachedClient getMemcachedClinet(){
MemcachedClient memcachedClient = null;
try {
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses(xMemcachedProperties.getServers()));
builder.setFailureMode(false);
builder.setSanitizeKeys(xMemcachedProperties.getSanitizeKeys());
builder.setConnectionPoolSize(xMemcachedProperties.getPoolSize());
builder.setOpTimeout(xMemcachedProperties.getOpTimeout());
builder.setSessionLocator(new KetamaMemcachedSessionLocator());
builder.setCommandFactory(new BinaryCommandFactory());
memcachedClient = builder.build();
}catch (IOException e){
log.error("init MemcachedClient failed:", e);
}
return memcachedClient;
}
}
使用
package com.blog.www.base;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* 測試基類,其他類繼承此類
* <br/>
* @author :leigq
* @date :2019/8/13 17:17
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public abstract class BaseApplicationTests {
protected Logger log = LoggerFactory.getLogger(this.getClass());
private Long time;
@Before
public void setUp() {
this.time = System.currentTimeMillis();
log.info("==> 測試開始執行 <==");
}
@After
public void tearDown() {
log.info("==> 測試執行完成,耗時:{} ms <==", System.currentTimeMillis() - this.time);
}
}
package com.blog.www;
import com.blog.www.base.BaseApplicationTests;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.exception.MemcachedException;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.concurrent.TimeoutException;
/**
* Memcached 測試
*/
public class MemcachedTest extends BaseApplicationTests {
@Autowired
private MemcachedClient memcachedClient;
@Test
public void test() throws InterruptedException, TimeoutException, MemcachedException {
// 放入緩存
boolean flag = memcachedClient.set("a", 0, 1);
// 取出緩存
Object a = memcachedClient.get("a");
log.warn("a is [{}]", a);
// 3s後過期
memcachedClient.set("b", 3, 2);
Object b = memcachedClient.get("b");
log.warn("b is [{}]", b);
Thread.sleep(3000);
b = memcachedClient.get("b");
log.warn("b is [{}]", b);
}
}
執行結果如下:
其它
- 參考:https://blog.csdn.net/nihui123/article/details/101101222
- xmemcached Github:https://github.com/killme2008/xmemcached
- 深入使用XMemcached:http://www.imooc.com/article/256593
- memcache及使用場景:https://blog.csdn.net/weixin_43101391/article/details/82937849