一些常見的關(guān)于
xmemcached的問題,收集整理,集中解答在此。事實上這里的大部分問題都可以在
用戶指南里找到。
一、XMemcached是什么?
經(jīng)常碰到的一個問題是很多朋友對
memcached不了解,誤以為
xmemcached本身是一個緩存系統(tǒng)。Memcached是一個開源的,C寫的分布式key-value緩存,XMemcached只是它的一個訪問客戶端。Memcached通過網(wǎng)絡(luò)協(xié)議跟客戶端交互,通過客戶端你才可以去使用memcached,xmemcached是它的java客戶端之一。
二、為什么要選擇xmemcached?
memcached的java客戶端有多個選擇,為什么要選擇xmemcached?理由如下:
1、支持所有的文本協(xié)議和二進制協(xié)議,支持連接
Kestrel和
TokyoTyrant等memcached協(xié)議兼容的系統(tǒng)并作特殊處理。
2、支持動態(tài)添加和刪除memcached節(jié)點。
3、支持客戶端統(tǒng)計
4、支持JMX監(jiān)控和統(tǒng)計,可以通過JMX增刪節(jié)點。
5、高性能
6、支持節(jié)點的權(quán)重設(shè)置
7、支持nio的連接池,在高負載環(huán)境下提高吞吐量。
三、對jdk版本有什么要求?
Xmemcached僅支持jdk1.5及以上版本。
四、使用的時候需要創(chuàng)建多個MemcachedClient對象嗎?MemcachedClient是不是線程安全?
MemcachedClient是線程安全的,由于xmemcached的網(wǎng)絡(luò)層實現(xiàn)是基于nio長連接的,因此你并不需要重復(fù)創(chuàng)建多個MemcachedClient對象,通常來說將MemcachedClient設(shè)置為全局的唯一單例的服務(wù)使用,如果是使用spring配置,那更是簡單,在spring配置文件里配置一個MemcachedClient,其他對象引用即可使用。
五、為什么會拋出java.util.TimeoutException?
這是由于xmemcached的通訊層是基于非阻塞IO的,那么在請求發(fā)送給memcached之后,需要等待應(yīng)答的到來,這個等待時間默認(rèn)是1秒,如果超過1秒就拋出java.util.TimeoutExpcetion給用戶。如果你頻繁拋出此異常,可以嘗試將全局的等待時間設(shè)置長一些,如我在壓測中設(shè)置為5秒:
MemcachedClient memcachedClient=……
memcachedClient.setOpTimeout(5000L);
請注意,setOpTimeout設(shè)置的是全局的等待時間,如果你僅僅是希望將get或者set等操作的超時延長一點,那么可以通過這些方法的重載方法來使用:
<T> T get(java.lang.String key,long timeout)
boolean set(java.lang.String key, int exp,java.lang.Object value,
long timeout)
……
六、Kestrel和TokyoTyrant不支持flag字段,xmemcached是怎么解決的?
Xmemcached在存儲的value前面自動加上和去除4個字節(jié)的flag,這一切對應(yīng)用來說是透明的。具體請看用戶指南。
七、連接memcacheq,取出來的消息比放進去的多?
這是由于memcacheq和kestrel一樣,不支持multi get協(xié)議,因此只要關(guān)閉xmemcached的multi get優(yōu)化就可以了。
memcachedClient.setOptimizeGet(false);
所謂multi get優(yōu)化是指xmemcached會將連續(xù)的單個get請求合并成一個multi get請求作批量獲取,提高效率。
八、連接kestrel,為什么過一段時間會自動斷開并重連?
你可能使用的是kestrel 1.2以下版本,kestrel 1.2才支持version協(xié)議,xmemcached是基于version協(xié)議做心跳檢測,因此當(dāng)使用kestrel 1.2以下版本的時候會發(fā)生心跳檢測失敗并斷開連接重連的情況,你可以升級kestrel,也可以關(guān)閉心跳檢測:
memcachedClient.setEnableHeartBeat(false);
九、我使用maven,怎么引用xmemcached?
xmemcached 1.2.5已經(jīng)加入了maven的中心倉庫,因此你可以直接引用
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>1.2.5</version>
</dependency>
如果是之前版本,我推薦你升級,或者自己手工加入私人的maven倉庫。
十、連接池是怎么回事?設(shè)置多大為好?
在高負載環(huán)境下,nio的單連接也會遇到瓶頸,此時你可以通過設(shè)置連接池來讓更多的連接分擔(dān)memcached的請求負載,從而提高系統(tǒng)的吞吐量。設(shè)置連接池通過
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000"));
builder.setConnectionPoolSize(5);
MemcachedClient client=builder.build();
或者通過spring配置也可以。
連接池通常不建議設(shè)置太大,我推薦在0-30之間為好,太大則浪費系統(tǒng)資源,太小無法達到分擔(dān)負載的目的。
十一、性能建議及優(yōu)化手段
性能的調(diào)整只能給出一般性的原則,實際情況千差萬別,每次調(diào)整都需要做實際的測量才能確定是否帶來期望的效果。
1、如果你的數(shù)據(jù)較小,如在1K以下,默認(rèn)的配置選項已經(jīng)足夠。如果你的數(shù)據(jù)較大,我會推薦你調(diào)整網(wǎng)絡(luò)層的TCP選項,如設(shè)置socket的接收和發(fā)送緩沖區(qū)更大,啟用Nagle算法等等:
MemcachedClientBuilder builder = new XMemcachedClientBuilder(
AddrUtil.getAddresses(servers));
builder.setSocketOption(StandardSocketOption.SO_RCVBUF, 32 * 1024); // 設(shè)置接收緩存區(qū)為32K,默認(rèn)16K
builder.setSocketOption(StandardSocketOption.SO_SNDBUF, 16 * 1024); // 設(shè)置發(fā)送緩沖區(qū)為16K,默認(rèn)為8K
builder.setSocketOption(StandardSocketOption.TCP_NODELAY, false); // 啟用nagle算法,提高吞吐量,默認(rèn)關(guān)閉
默認(rèn)如果連接超過5秒沒有任何IO操作發(fā)生即認(rèn)為空閑并發(fā)起心跳檢測,你可以調(diào)長這個時間:
builder.getConfiguration().setSessionIdleTimeout(10000); // 設(shè)置為10秒;
更多網(wǎng)絡(luò)層配置選項請參見Configuration類。
2、Xmemcached默認(rèn)會做兩個優(yōu)化:將連續(xù)的單個get合并成一個multi get批量操作獲取,將連續(xù)的請求合并成socket發(fā)送緩沖區(qū)大小的buffer發(fā)送。
如果你對響應(yīng)時間比較在意,那么可以將合并的因子減小,或者關(guān)閉合并buffer的優(yōu)化:
memcachedClient.setMergeFactor(50); //默認(rèn)是150,縮小到50
memcachedClient.setOptimizeMergeBuffer(false); //關(guān)閉合并buffer的優(yōu)化
如果你對吞吐量更在意,那么也可將合并因子調(diào)大,默認(rèn)是150。但是也不可太大,太大可能導(dǎo)致平均響應(yīng)時間延長。
3、如果你對心跳檢測不在意,也可以關(guān)閉心跳檢測,減小系統(tǒng)開銷
memcachedClient.setEnableHeartBeat(false);
這個關(guān)閉,僅僅是關(guān)閉了心跳的功能,客戶端仍然會去統(tǒng)計連接是否空閑,禁止統(tǒng)計可以通過:
builder.getConfiguration().setStatisticsServer(false);