2013年4月26日 星期五

心得- Memcached in java

簡介

摘要官方網站的介紹


特色有
  • 免費
  • open source
  • 高效率
  • 分散式
  • 使用記憶體儲存
  • 以 key value 物件的方式存取資料
  • 安全性較低,所以建議放在防火牆後面的機器


Server 安裝

原始Lib 並不支援windows 系統, 若是使用linux 等系統的話去官方網站下載就可以
要額外安裝  memcached for win
我是參考 [2] 的步驟
  • 將jar 解壓縮到資料夾如D:\Appserv\memcached
  • 配置服務
    • D:\Appserv\memcached>sc create memcached binPath= "D:\Appserv\memcached\memcached.exe -p 9999 -l 127.0.0.1 -m 128 -d runservice" DisplayName= "memcached server" start= auto depend= TCPIP
    • 其中 -p 9999 是指透過 port 9999 監聽請求 (預設為 11211 ) , -l 127.0.0.1 是指伺服器指定的 IP 位址 (預設為 INDRR_ANY) , -m 128 是指 memcached 最大可用的記憶體為 128 MB (預設 64 MB) ,最後 -d runservice 就是啟動為 Windows 服務。
  • 再去工作管理員開啟服務



重要議題

參考[3] ,摘要幾個重點

撰寫使用 memcached 程式的基本模式就是,先查看有沒有 key-value,有就把快取資料讀出來,沒有就運算結果後存到 memcached sever。這部份算是簡單的。真正困難的事情有兩件:
  • 一是清除過期的快取資料(expire)
  • 二是Key的命名
兩種方式清除快取資料
一是在新增/刪除資料時,順便刪掉這個快取 key-value,這樣下次 request 來時便會重新 快取。
二是在有更新的時候直接重設快取資料(Reset)。要注意的是如果您有不同的程式會直接更新資料庫(也就是不只是透過主應用程式,還有別的背景程式),就會有可能 memcachd 裡面的資料沒有被更新到,
解法有 
1. 清空所有資料 
2. 有一隻程式可以重建 memcached 裡面的資料
3. 統一用一套知道 memcached 機制的介面操作


Key的命名
為了 Security 避免被人猜到 Key 和避免超過 255 bytes 的 key 長度限制,建議你將 Key hash 過

Client API 


我是使用 JAVA 的API  Memcached-Java-Client


摘錄  MemcachedBench.java 的說明 並加上註釋



/**
 * Copyright (c) 2008 Greg Whalin
 * All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the BSD license
 *
 * This library is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.
 *
 * You should have received a copy of the BSD License along with this
 * library.
 *
 * @author Greg Whalin  
 */
package com.meetup.memcached.test;

import cht.batchevent.show.EventList;

import com.meetup.memcached.*;
import java.util.*;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.BasicConfigurator;



/*
 * 
 * 
 * 
 */
public class MemcachedBench2 {

// logger
private static Logger log =
Logger.getLogger( MemcachedBench2.class.getName() );

public static void main(String[] args) {

BasicConfigurator.configure();
org.apache.log4j.Logger.getRootLogger().setLevel( Level.OFF );

int runs = Integer.parseInt(args[0]);
int start = Integer.parseInt(args[1]);

//伺服器位址清單
String[] serverlist = { "127.0.0.1:9999" };


// initialize the pool for memcache servers
SockIOPool pool = SockIOPool.getInstance( "test" );
pool.setServers(serverlist);

pool.setInitConn( 100 );
pool.setMinConn( 100 );
pool.setMaxConn( 500 );
pool.setMaintSleep( 20 );

pool.setNagle( false );
pool.initialize();


// get client instance
MemcachedClient mc = new MemcachedClient( "test" );       // 要和pool 的名稱一樣
mc.setCompressEnable( false );

String keyBase = "testKey";

//String object = "This is a test of an object blah blah es, serialization does not seem to slow things down so much.  The gzip compression is horrible horrible performance, so we only use it for very large objects.  I have not done any heavy benchmarking recently";

long begin = System.currentTimeMillis();
long end = System.currentTimeMillis();
long time = end - begin;


begin = System.currentTimeMillis();
for (int i = start; i < start+runs; i++) {
String str = (String) mc.get(keyBase + i);
// 沒有資料時和資料庫要資料, 取得後放入 memcatch
if(str == null){
System.out.println(i+" is null ");
OBJ_obj = new OBJ();
StringBuffer _theobj = new StringBuffer();
_theobj _obj.getDataFromDB();
String object =_theobj .toString();
mc.set(keyBase + i, object);
}
System.out.println(i+" : " + str);
}
end = System.currentTimeMillis();
time = end - begin;
System.out.println(runs + " gets: " + time + "ms");


// 取得多筆
String[] keys = new String[ runs ];
int j = 0;
for (int i = start; i < start+runs; i++) {
keys[ j ] = keyBase + i;
j++;
}
begin = System.currentTimeMillis();
Map vals = mc.getMulti( keys );
end = System.currentTimeMillis();
time = end - begin;
System.out.println(runs + " getMulti: " + time + "ms");

/*
*  //刪除的語法
* begin = System.currentTimeMillis();
for (int i = start; i < start+runs; i++) {
mc.delete( keyBase + i );
}
end = System.currentTimeMillis();
time = end - begin;
System.out.println(runs + " deletes: " + time + "ms");*/

SockIOPool.getInstance( "test" ).shutDown();
}
}



參考: