爲什麼要用到結果緩存,主要是用於加速熱門數據的訪問速度,Dubbo提供聲明式緩存,以減少用戶加緩存的工作量。
下面我們將通過一個例子來對結果緩存進行一個接觸.
1、客戶端和服務提供端共用接口類
packagecom.alibaba.dubbo.demo;
public interfaceCacheService {
String findCache(String id);
}
2、服務提供端接口實現類
packagecom.alibaba.dubbo.demo.provider;
importjava.util.concurrent.atomic.AtomicInteger;
importcom.alibaba.dubbo.demo.CacheService;
public classCacheServiceImpl implements CacheService {
//AtomicInteger通過一種線程安全的加減操作接口
private final AtomicInteger i = newAtomicInteger();
@Override
public String findCache(String id) {
String result = "request: " +id + ", response: " + i.getAndIncrement();
System.out.println(result);
return result;
}
}
3、服務提供端配置文件
<?xmlversion="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 提供方應用信息,用於計算依賴關係 -->
<dubbo:applicationname="hello-world" />
<!-- 使用zookeeper註冊中心暴露發現服務地址 -->
<dubbo:registryaddress="zookeeper://127.0.0.1:2181" />
<!-- 用dubbo協議在20880端口暴露服務 -->
<dubbo:protocol name="dubbo"port="20880" />
<!-- 聲明需要暴露的服務接口 -->
<dubbo:serviceinterface="com.alibaba.dubbo.demo.DemoService"ref="demoService" />
<!-- 和本地bean一樣實現服務 -->
<bean id="demoService"class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />
<!-- 聲明需要暴露的服務接口 -->
<dubbo:serviceinterface="com.alibaba.dubbo.demo.ValidationService"ref="validationService" />
<!-- 和本地bean一樣實現服務 -->
<bean id="validationService"class="com.alibaba.dubbo.demo.provider.ValidationServiceImpl" />
<bean id="cacheService"class="com.alibaba.dubbo.demo.provider.CacheServiceImpl" />
<dubbo:serviceinterface="com.alibaba.dubbo.demo.CacheService"ref="cacheService" />
</beans>
4、客戶端配置文件
<?xmlversion="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方一樣-->
<dubbo:applicationname="consumer-of-helloworld-app" />
<!-- 使用zookeeper註冊中心暴露發現服務地址 -->
<dubbo:registryaddress="zookeeper://127.0.0.1:2181" />
<!-- 生成遠程服務代理 -->
<dubbo:referenceid="demoService"interface="com.alibaba.dubbo.demo.DemoService"
retries="2"
/>
<!-- 生成遠程服務代理 -->
<dubbo:referenceid="validationService"interface="com.alibaba.dubbo.demo.ValidationService"
retries="2"validation="true"
/>
<!-- 生成遠程服務代理 -->
<dubbo:referenceid="cacheService"interface="com.alibaba.dubbo.demo.CacheService"cache="true" />
</beans>
5、客戶端主類
importorg.springframework.context.support.ClassPathXmlApplicationContext;
importcom.alibaba.dubbo.demo.CacheService;
public class Consumer {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args)throws Exception {
ClassPathXmlApplicationContext context= new ClassPathXmlApplicationContext(
new String[] {"classpath:consumer.xml" });
context.start();
CacheService cacheService =(CacheService) context.getBean("cacheService");
// 測試緩存生效,多次調用返回同樣的結果。(服務器端自增長返回值)
String fix = null;
for (int i = 0; i < 5; i++) {
String result =cacheService.findCache("0");
if (fix == null ||fix.equals(result)) {
System.out.println("i=" + i + " OK: " + result);
} else {
System.err.println("i=" + i + " ERROR: " + result);
}
fix = result;
Thread.sleep(500);
}
// LRU的缺省cache.size爲1000,執行1001次,應有溢出
for (int n = 0; n < 1001; n++) {
String pre = null;
for (int i = 0; i < 10; i++) {
String result =cacheService.findCache(String.valueOf(n));
if (pre != null &&!pre.equals(result)) {
System.err.println("n=" + n + " ERROR: " + result);
}
pre = result;
}
}
// 測試LRU有移除最開始的一個緩存項
String result =cacheService.findCache("0");
if (fix != null &&!fix.equals(result)) {
System.out.println("OK: "+ result);
} else {
System.err.println("ERROR:" + result);
}
}
}
6、客戶端控制檯,返回值
i=0 OK: request: 0,response: 0
i=1 OK: request: 0,response: 0
i=2 OK: request: 0,response: 0
i=3 OK: request: 0,response: 0
i=4 OK: request: 0,response: 0
OK: request: 0, response:1001
使用結果緩存的服務方法必須是冪等的,也就是說,相同的輸入參數返回相同的結果,參數第一次計算緩存結果,下一次相同參數傳入時直接返回結果。
緩存策略有三種:
1、LruCache,lru基於最近最少使用原則刪除多餘緩存,保持最熱的數據被緩存。
2、ThreadLocalCache,threadlocal當前線程緩存,比如一個頁面渲染,用到很多portal,每個portal都要去查用戶信息,通過線程緩存,可以減少這種多餘訪問。
3、JCache,jcache與JSR107集成,可以橋接各種緩存實現。
除此之外,我們還可以自定義擴展緩存。