Garnet First Step

๋“œ๋””์–ด ์‹œ๊ฐ„์ด ๋‚˜์„œ Garnet ์„ ์‹œ์ž‘ํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค.
Cache db ๋ฅผ ์‚ฌ์‹ค ๊ฑฐ์˜ ์•ˆ์จ๋ด์„œ ๊ต‰์žฅํžˆ ๊ธด์žฅํ–ˆ์Šต๋‹ˆ๋‹ค.

Site
github : GitHub - microsoft/garnet: Garnet is a remote cache-store from Microsoft Research that offers strong performance (throughput and latency), scalability, storage, recovery, cluster sharding, key migration, and replication features. Garnet can work with existing Redis clients.
official Site : Hello from Garnet | Garnet

ํ•ด๋‹น ์‚ฌ์ดํŠธ์—์„œ ๋ฐ›์œผ์‹œ๊ณ  Site์—์„œ ๋ณด๊ณ  ๋”ฐ๋ผํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์„ค์น˜

cd garnet
dotnet restore
dotnet build -c Release

Test Suite ์‹คํ–‰

dotnet test -c Release -f net8.0 -l โ€œconsole;verbosity=detailedโ€

๋Œ€๋žต์ด๋Ÿฌ๋ฉด ๋ญ”๊ฐ€ ์—„์ฒญ๋‚œ๊ฒƒ์ด PC์— ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

์„ค์น˜๊ฐ€ ๋๋‚˜๊ณ  Instance ๋ฅผ ์˜ฌ๋ฆฝ๋‹ˆ๋‹ค ( ์ด๋•Œ default port 6379๋ฅผ ์˜คํ”ˆํ•˜์„ธ์š”)

์‹คํ–‰

cd main/GarnetServer
dotnet run -c Release -f net8.0

image

๋ญ ์ด๋Ÿฌ๋ฉด garnet ์ด ์‹คํ–‰์ค‘์ด๋ผ๋Š”๋ฐ โ€ฆ ์•ž์œผ๋กœ ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ์ง€ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค.
์ ‘์†์„ ์œ„ํ•ด์„œ๋Š” ์‚ฌ์ดํŠธ์—
Redis-cli ๋‚˜ c#์—์„œ๋Š” StackExchange.Redis Nuget ์—์„œ ์ฐธ์กฐ๋ฅผ ํ•˜๋ฉด ๋œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.


์—ฌ๊ธฐ์„œ garnet ์„ ์„ค์น˜ํ–ˆ๋Š”๋ฐ ๋„๊ตฌ๋Š” redis๋ฅผ ์“ฐ๋ผ๊ณ  ํ•˜๊ณ  ์žˆ๊ตฐ์š” ;;;
๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ redis ์“ฐ์‹œ๋“ฏ ๊ทธ๋Œ€๋กœ ์“ฐ์‹œ๋ฉด ๋œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ;;;

Redis ์ž…์žฅ์—์„œ๋Š” ์•ฝ๊ฐ„ ์–„๋ฏธ์šธ๊ฒƒ ๊ฐ™๊ตฐ์š”

๊ทธ๋ž˜์„œ c# console ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๊ณ 
image

stackexchange๋ฅผ Nuget ์—์„œ ์ฐธ์กฐํ–ˆ์Šต๋‹ˆ๋‹ค.

sample ์†Œ์Šค๋ฅผ ๋ชป์ฐพ์•„์„œ redis c# client ์†Œ์Šค๋ฅผ ๊ทธ๋Œ€๋กœ ์ฐธ๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค.

    public class GarnetStore
    {
        private ConnectionMultiplexer _redis;
        private IServer _server;
        private IDatabase _database;
        private readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions()
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        };
        public GarnetStore(string connectionString)
        {
            _redis = ConnectionMultiplexer.Connect(connectionString);
            if (_redis == null)
            {
                return;
            }

            if (!_redis.IsConnected)
            {
                return;
            }

            _database = _redis.GetDatabase();

            var endpoint = _redis.GetEndPoints().Single();
            _server = _redis.GetServer(endpoint);
        }

        public List<RedisKey> GetKeys(string pattern)
        {
            return _server.Keys(pattern: pattern).ToList();
        }

        public void SetValue(RedisKey key, RedisValue value)
        {
            _database.StringSet(key, value);
        }

        public string GetValue(RedisKey key)
        {
            return _database.StringGet(key);
        }

        public bool JsonSet(string key, object value)
        {
            string json = JsonSerializer.Serialize(value, _jsonSerializerOptions);
            return _database.StringSet(key, json);
        }

        public T JsonGet<T>(string key)
        {
            RedisValue redisValue = _database.StringGet(key);
            if (redisValue.IsNullOrEmpty)
            {
                return default(T);
            }

            return JsonSerializer.Deserialize<T>(redisValue, _jsonSerializerOptions);
        }
    }

    public class MyClass
    {
        public int value1 { get; set; }
        public string value2 { get; set; }
    }

๋ญ ๋Œ€๋žต ์ด๋Ÿฐ์‹์œผ๋กœ ํ•˜๊ณ 

    GarnetStore redis = new GarnetStore("192.168.0.11:6379");
    redis.SetValue("test1", "ans-test1");
    // key๋กœ value๋ฅผ ์ฐพ๋Š”๋‹ค.
    Console.WriteLine(redis.GetValue("test1"));

    // value๋กœ ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋ฅผ ์ž…๋ ฅ
    redis.JsonSet("test2", new MyClass()
    {
        value1 = 1,
        value2 = "test2"
    });

    // key๋กœ ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋ฅผ ์ฐพ๋Š”๋‹ค.
    var resultMyClass = redis.JsonGet<MyClass>("test2");
    Console.WriteLine($"{resultMyClass.value1}, {resultMyClass.value2}");
}

์ด๋ ‡๊ฒŒ ํ•˜์‹œ๋ฉด
image

garnet ์— ๋ฐ์ดํƒ€ ์ž˜๋นผ๊ณ  ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค .

ํ•˜๊ธฐ ์ „์—๋Š” ๊ต‰์žฅํžˆ ์–ด๋ ต๊ณ  ๋‘๋ ค์› ๋Š”๋ฐ ๋„ˆ๋ฌด ์‰ฝ๊ฒŒ ๋˜์„œ ์˜์™ธ์˜€์Šต๋‹ˆ๋‹ค.
๊ทธ๋ƒฅ ๊ธฐ์กด redis ์‚ฌ์šฉ์ž๋“ค์€ ๋„๋ฉ”์ธ๋งŒ ๋ฐ”๊พธ์…”๋„ ๋Œ€์ถฉ ๋ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

12๊ฐœ์˜ ์ข‹์•„์š”

์ €๋„ ๊ฐ€๋„ท ์ผ๋ถ€๋Ÿฌํ•œ๋ฒˆ ์จ๋ณด๊ณ  ์‹ถ์€๋ฐ ๋ง์ด์ฃ  ใ…‹ใ…‹ ์‰ฝ๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋‹ค๋‹ˆ ๋‹คํ–‰์ด๊ตฐ์š”!

3๊ฐœ์˜ ์ข‹์•„์š”

๊ฐœ์ธ์ ์œผ๋กœ๋Š” garnet์ด ์ •๋ง ์ข‹์•˜๋˜๊ฒŒ, linqpad๋‚˜ C# script ๊ฐ™์€ ํ™˜๊ฒฝ์—์„œ๋Š” ์™ธ๋ถ€ ํ”„๋กœ์„ธ์Šค ํ˜•ํƒœ๊ฐ€ ์•„๋‹Œ ๋‹ท๋„ท ๋Ÿฐํƒ€์ž„ ์•ˆ์— ๊นŠ์ด ํ†ตํ•ฉ๋˜์–ด ์‹คํ–‰๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•˜๋Š”๊ฒŒ ์ •๋ง ๋งˆ์Œ์— ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์šด์˜ ์ฒด์ œ ์ˆ˜์ค€์˜ ํŒŒ์ดํ”„๋‚˜ ๋ฉ”๋ชจ๋ฆฌ ๋งต ํŒŒ์ผ๋ณด๋‹ค ํ›จ์”ฌ ์“ฐ๊ธฐ ํŽธํ•˜๊ณ  ์—ฌ๋Ÿฌ ์–ธ์–ด๋ฅผ ์ง€์›ํ•˜๋Š” ํ”„๋กœ์„ธ์Šค ๊ฐ„ ํ†ต์‹  ์ˆ˜๋‹จ (IPC)๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ๋„ ๋งค๋ ฅ์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.!

9๊ฐœ์˜ ์ข‹์•„์š”

์ €๋Š” MSA ์•ฑ์—์„œ redis ๋Œ€์‹  garnet์„ ๋„ฃ์–ด์„œ ํ…Œ์ŠคํŠธ ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๋งค๋„๋Ÿฝ๊ฒŒ ์ž˜ ๋™์ž‘ํ•˜๊ณ , ๋ฉ”๋ชจ๋ฆฌ ์„œ๋ฒ„ ์—ญํ• ๋„, ์„ธ์…˜ DB ์–ด๋Žํ„ฐ๋กœ๋„ ์ž˜ ๋™์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ๊ฑด ๋‹ค๋ฅธ ํŒ€์›๋“ค์€ garnet์„ ์‚ฌ์šฉ ์ค‘์ด๋ผ๋Š” ๊ฑธ ๋ชจ๋ฅด์…จ๋‹ค๋Š”๊ฑฐ์ฃ  :rocket:. redis๋ฅผ ๋ชป ์“ฐ๋Š” ์ƒํ™ฉ์ด ์˜จ๋‹ค๋ฉด ๋ฐ”๋กœ garnet์œผ๋กœ ์ „ํ™˜ํ•  ์ค€๋น„๊ฐ€ ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค :smiling_face:

11๊ฐœ์˜ ์ข‹์•„์š”