之前寫的文章嵌赠,我隆重介紹到Garnet服務(wù)端如何安裝部署畅买。此外同仆,我還寫了一段客戶端運(yùn)行的代碼,來(lái)驗(yàn)證Garnet服務(wù)端可用性枪向。
記得當(dāng)時(shí)我用的是純String的存儲(chǔ)方式進(jìn)行寫入和讀取的勤揩。OK,代碼也找到了秘蛔。Copy過(guò)來(lái)給大家可以回顧一下陨亡。
using StackExchange.Redis;
var connString = "192.168.1.12:3278,password=012345";
var connection = ConnectionMultiplexer.Connect(connString);
var db = connection.GetDatabase();
db.StringSet("StringKey","Hello Garnet!");
var value = db.StringGet("StringKey");
Console.WriteLine(value);
一位有相當(dāng)開發(fā)經(jīng)驗(yàn)的讀者,發(fā)郵件跟我說(shuō):“真實(shí)項(xiàng)目開發(fā)當(dāng)中深员,我們很少這么用呀数苫!我們?cè)诰彺娴臄?shù)據(jù)一般都是結(jié)構(gòu)化的,絕少用Pain Text”辨液。
是的虐急,非常正確!既然如此滔迈,我今天就順著這個(gè)話題止吁,深入探討一下吧×呛罚看看Garnet或Redis的數(shù)據(jù)序列化方式有哪些敬惦,我們應(yīng)該怎么選擇。
常用的序列化方式有三種:JSON
谈山、MessagePack
俄删、ProtoBuf
。下面我用C#類庫(kù)BeetleX.Redis
(https://www.nuget.org/packages/BeetleX.Redis/)奏路,分別對(duì)以上三種序列化方式來(lái)做個(gè)演示一下吧畴椰。
對(duì)象實(shí)體類
首先,聲明一個(gè)實(shí)體對(duì)象的類鸽粉,用來(lái)創(chuàng)建對(duì)象實(shí)例供我們做序列化測(cè)試斜脂。
[MessagePackObject]
[ProtoContract]
[BeetleX.Packets.MessageType(1)]
public class Goods
{
[Key(1)]
[ProtoMember(1)]
public int id { get; set; }
[Key(2)]
[ProtoMember(2)]
public string name { get; set; }
[Key(3)]
[ProtoMember(3)]
public decimal price { get; set; }
[Key(4)]
[ProtoMember(4)]
public int qty { get; set; }
[Key(5)]
[ProtoMember(5)]
public DateTime createdAt { get; set; }
}
數(shù)據(jù)序列化寫入和讀取
using BeetleX.Redis;
using MessagePack;
using ProtoBuf;
static async Task TestBeetleXRedis(string format)
{
RedisDB DB = null;
switch (format)
{
case "Json":
DB = new RedisDB(0, new JsonFormater());
break;
case "ProtoBuff":
DB = new RedisDB(0, new ProtobufFormater());
break;
case "MessagePack":
DB = new RedisDB(0, new MessagePackFormater());
break;
default:
throw new NotSupportedException(format);
}
DB.Host.AddWriteHost("192.168.1.12", 3278).Password = "012345";
var goods = new Goods()
{
id = 1,
name = "IPhone15 Pro",
price = 999.99m,
qty = 1000,
createdAt = DateTime.Now
};
var key = $"{format}_GoodsObject";
await DB.Set(key, goods);
goods = await DB.Get<Goods>(key);
Console.WriteLine(goods);
}
await TestBeetleXRedis("Json");
await TestBeetleXRedis("ProtoBuff");
await TestBeetleXRedis("MessagePack");
執(zhí)行完以上代碼,我們打開RedisInsight客戶端触机,可以看到剛才我們寫入的對(duì)應(yīng)以上三種序列化方式的緩存數(shù)據(jù)帚戳。
對(duì)比分析
1、存儲(chǔ)空間
其中儡首,Json占用所的存儲(chǔ)空間最大片任,比另外兩個(gè)明顯大了很多。ProtoBuff比MessagePack略大一點(diǎn)蔬胯,基本上不分伯仲对供。
存儲(chǔ)空間占用大小意味這什么?意味著服務(wù)器成本的開支笔宿!
假設(shè)我們的項(xiàng)目用Json序列化存儲(chǔ)的緩存數(shù)據(jù)有10G犁钟,那么我們至少需要一臺(tái)12G內(nèi)存的服務(wù)器。如果換MessagePack泼橘,那么一臺(tái)8G內(nèi)存的服務(wù)足夠應(yīng)付了涝动。
2、序列化/反序列化性能
至于序列化的性能炬灭,Json無(wú)疑是墊底的醋粟。這些網(wǎng)上測(cè)試用例很多,大家搜索一下就能找到重归。我懶得去copy了米愿。值得一提的是,我曾經(jīng)看過(guò)某個(gè)號(hào)稱高性能序列化Json的C#代碼鼻吮,發(fā)現(xiàn)JSON的算法真的很復(fù)雜育苟,遠(yuǎn)不如ProtoBuff和MessagePack簡(jiǎn)潔高效。
3椎木、內(nèi)容可讀性
接著我們看看數(shù)據(jù)內(nèi)容违柏,可讀性Json > MessagePack > ProtoBuff。Json本來(lái)就是文本數(shù)據(jù)香椎,可讀性最高完全沒(méi)有意外漱竖。
4、總結(jié)
- 在實(shí)際的項(xiàng)目中畜伐,我們一般會(huì)對(duì)Redis緩存數(shù)據(jù)進(jìn)行序列化處理馍惹。
- 我們對(duì)三種序列化方式進(jìn)行對(duì)比,發(fā)現(xiàn)Json性能弱玛界,且暫用存儲(chǔ)空間大万矾。它的唯一優(yōu)點(diǎn)是內(nèi)容具有非常高的可讀性。
- 如果您要大規(guī)模使用Redis緩存慎框,并且追求高性能低成本的話勤众,強(qiáng)烈建議不要用Json序列化!