memcache的item key和序列化
一個完整的item長度是鍵長+值長+字尾長+item結構大小(32位元組),item操作就是根據這個長度來計算slab的classid的。
+---------------------------------------+
| key-value | cas | suffix | item head |
+---------------------------------------+
其中suffix的格式是 flag vlen (flag即it_flag,vlen是value的長度;
key預設最大長度為250,需要修改原始碼才能擴充套件;
#define KEY_MAX_LENGTH 250
Item最大長度預設為1M,可透過啟動選項-I修改;
-I Override the size of each slab page. Adjusts max item size (default: 1mb, min: 1k, max: 128m)
MC透過hash表維護item的查詢,新增以及刪除等操作,以查詢為例,其API如下:
item *assoc_find(const char *key, const size_t nkey) {
//採用hash演算法將傳入的key轉換,然後從hash table中查詢;
uint32_t hv = hash(key, nkey, 0);
item *it;
unsigned int oldbucket;
//倘若hash表正在擴容,須判斷此時hash bucket的是在old還是在new table;透過 hv & hashmask(hashpower - 1) 或者hv & hashmask(hashpower)找出對應的hash table下標,
if (expanding && (oldbucket = (hv & hashmask(hashpower - 1))) >= expand_bucket)
{
it = old_hashtable[oldbucket];
} else {
it = primary_hashtable[hv & hashmask(hashpower)];
}
item *ret = NULL;
int depth = 0;
//為應對hash衝突,每個hash bucket都有一個連結串列,透過遍歷該連結串列確定要找到的key
while (it) {
if ((nkey == it->nkey) && (memcmp(key, ITEM_key(it), nkey) == 0)) {
ret = it;
break;
}
it = it->h_next;
++depth;
}
MEMCACHED_ASSOC_FIND(key, nkey, depth);
//向客戶端返回item
return ret;
}
注:hash表預設分配2^16個bucket,當item數量 > bucket*1.5時擴容,每次擴容為原來的2倍;先申請相應記憶體,然後啟動執行緒同步原hash表中資料;
MC只維護了hash table和slab,因此沒有內建方法來遍歷其下所有item,可透過stats命令來間接實現。
1 登入MC,telnet 127.0.0.1 11211
2 檢視所有slab資訊
stats items
STAT items:3:number 1
STAT items:3:age 498
STAT items:22:number 1
STAT items:22:age 498
END
注:這裡的3和22為slab id;
3 依次列舉各個slab,將100替換為0則表示列舉所有key
stats cachedump 3 100
ITEM views.decorators.cache.cache_header..cc7d9 [6 b; 1256056128 s]
END
stats cachedump 22 100
ITEM views.decorators.cache.cache_page..8427e [7736 b; 1256056128 s]
END
現在可透過get key命令獲取每個key對應的item內容。
Key的選擇
應該根據業務型別而定,除了常見的資料命名,還可以選擇如下方式:
1 封裝SQL作為key
下面這個例子就是透過Cache快取查詢資料庫結果的場景,把sql+userId作為一個key,相同使用者第二次查詢時就可以從快取中直接提取:
sql1 = "SELECT * FROM user WHERE user_id = ?"
key = 'SQL:' . user_id . ':' . md5sum(sql1)
if (defined result = memcli:get(key)) {
return result
}
else {
handler = run_sql(sql1, user_id)
t[info] = handler:turn_into_an_array
memcli:set(key, t, 5 * 60)
return t
}
2 Get-By-Group-Key
很多客戶端在處理multiget多伺服器請求時採用序列方式,會導致效能嚴重下降,解決辦法:保證Multiget中的鍵只出現在一臺伺服器。
譬如,使用者名稱字(user:foo:name),使用者年齡(user:foo:age)等資料在雜湊到多臺伺服器上時,不應按照完整的鍵名(user:foo:name和user:foo:age)來雜湊的,而應按照特殊的鍵(foo)來雜湊的,這樣就保證了相關的鍵只出現在一臺伺服器上。
PHP的memcache客戶端提供
Memcached::getMultiByKey — Retrieve multiple items from a specific server
Memcached::setMultiByKey — Store multiple items on a specific server
來源:http://blog.51yip.com/php/729.html
序列化
序列化 (Serialization)將物件轉換為可以儲存或傳輸的形式的過程。在序列化期間,物件將其當前狀態寫入到臨時或永續性儲存區。以後,可以透過從儲存區中讀取或反序列化物件的狀態,重新建立該物件。
除了string和int/long,memcache還可以儲存object型別,但是儲存前需要將其先進行序列化,讀取時再進行反序列化;
MC客戶端預設自動開啟了序列化和反序列化,也可以在set前使用marshal或其他工具進行序列化;
注:由於不同的Client實現的序列化方式不同,所以如果不同的語言使用同一個memcached來存取資料,可能會造成資料不一致的問題。
分別以python和java為例,
Python的客戶端工具memcache.py
if isinstance(val, str):
pass
elif isinstance(val, int):
flags |= Client._FLAG_INTEGER
val = "%d" % val
# force no attempt to compress this silly string.
min_compress_len = 0
elif isinstance(val, long):
flags |= Client._FLAG_LONG
val = "%d" % val
# force no attempt to compress this silly string.
min_compress_len = 0
else:
flags |= Client._FLAG_PICKLE
file = StringIO()
pickler = self.pickler(file, protocol=self.pickleProtocol)
if self.persistent_id:
pickler.persistent_id = self.persistent_id
pickler.dump(val)
val = file.getvalue()
JAVA 的spymemcached client
byte[] b=null;
int flags=0;
if(o instanceof String) {
b=encodeString((String)o);
} else if(o instanceof Long) {
b=tu.encodeLong((Long)o);
flags |= SPECIAL_LONG;
…
} else {
b=serialize(o);
flags |= SERIALIZED;
}
有時MC客戶端自帶的序列化演算法可能不夠高效,導致MC耗用更多的記憶體來儲存,此時可以選擇第三方工具來封裝客戶端序列化機制,譬如google的protobuf;
如下面這個例子http://my.oschina.net/pzh0819/blog/110460
登入MC透過stat slabs命令檢視slab執行情況,大多數item都儲存在STAT 15,且chunk_size為2320(即2K),但是業務資料只是個Element物件,轉化為xml長度僅僅只有700位元組,從這可以看出memcache(客戶端版本:net.spy memcached-2.4.2)客戶端自帶的序列化使儲存的資料翻了將近3倍。透過將Element物件轉為xml字串儲存到MC,快取由以前的6G+減小到當前的2G(資料條數:300W+)。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8494287/viewspace-1444355/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 工作294:for[item.key]使用
- Python字典的遍歷,包括key遍歷/value遍歷/item遍歷/Python
- Python教程分享:Redis和Memcache的區別?PythonRedis
- python的序列化和反序列化Python
- Java的序列化和反序列化Java
- Memcache安全配置
- Scaling Memcache at Facebook
- PHP的序列化和反序列化入門PHP
- .NET物件的XML序列化和反序列化物件XML
- 利用Twemperf測試Memcache的效能
- 談談redis,memcache的區別和具體應用場景Redis
- python (3.x) 實現RSA 加簽 驗籤 以及key的序列化Python
- 從java的序列化和反序列化說起Java
- Java物件的序列化和反序列化實踐Java物件
- Flutter Key的原理和使用 (一) 沒有Key會發生什麼Flutter
- 如何處理redis叢集中hot key和big keyRedis
- 序列化和反序列化pickle和json 模組JSON
- Fastjson定製屬性的序列化和反序列化ASTJSON
- centos7 部署 memcacheCentOS
- Redis 與 memcache(轉載)Redis
- ctf serialize 序列化和反序列化
- xml序列化和反序列化(一)XML
- C++ 序列化和反序列化C++
- JavaScript item()JavaScript
- FileList item()
- 序列化涉及的類和介面
- Java交換map的key和value值Java
- Vue js用split切分並去掉空值和item的空格VueJS
- Python中物件序列化和反序列化Python物件
- [Java基礎]序列化和反序列化Java
- IO流(3) - 序列化和反序列化
- C#序列化和反序列化(json)C#JSON
- 修正memcache.php中的錯誤示例PHP
- [Blue Prism] Data item 的使用
- 面試之 Memcache 相關面試
- CentOS7 安裝 memcacheCentOS
- sticky list item
- item_get
- 為什麼需要序列化和反序列化