Hiredis: pub/sub์— ๋Œ€ํ•œ ์ฝ”๋“œ ์˜ˆ์ œ ์ถ”๊ฐ€

์— ๋งŒ๋“  2011๋…„ 07์›” 15์ผ  ยท  17์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: redis/hiredis

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "hiredis/hiredis.h"
#include "hiredis/async.h"
#include "hiredis/adapters/libevent.h"

void onMessage(redisAsyncContext *c, void *reply, void *privdata) {
    redisReply *r = reply;
    if (reply == NULL) return;

    if (r->type == REDIS_REPLY_ARRAY) {
        for (int j = 0; j < r->elements; j++) {
            printf("%u) %s\n", j, r->element[j]->str);
        }
    }
}

int main (int argc, char **argv) {
    signal(SIGPIPE, SIG_IGN);
    struct event_base *base = event_base_new();

    redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
    if (c->err) {
        printf("error: %s\n", c->errstr);
        return 1;
    }

    redisLibeventAttach(c, base);
    redisAsyncCommand(c, onMessage, NULL, "SUBSCRIBE testtopic");
    event_base_dispatch(base);
    return 0;
}

๋ชจ๋“  17 ๋Œ“๊ธ€

์ข‹์€ ์ œ์•ˆ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์‹ค์šฉ์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ pub/sub์— ๋Œ€ํ•ด ์ƒ๋‹นํžˆ ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ•ฉ๋‹ˆ๋‹ค.

+1, ๋น„๋™๊ธฐ libev pub/sub์— ์–ด๋ ค์›€์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ng ๋Œ€ํ•ด ์‹ ๊ณ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "hiredis/hiredis.h"
#include "hiredis/async.h"
#include "hiredis/adapters/libevent.h"

void onMessage(redisAsyncContext *c, void *reply, void *privdata) {
    redisReply *r = reply;
    if (reply == NULL) return;

    if (r->type == REDIS_REPLY_ARRAY) {
        for (int j = 0; j < r->elements; j++) {
            printf("%u) %s\n", j, r->element[j]->str);
        }
    }
}

int main (int argc, char **argv) {
    signal(SIGPIPE, SIG_IGN);
    struct event_base *base = event_base_new();

    redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
    if (c->err) {
        printf("error: %s\n", c->errstr);
        return 1;
    }

    redisLibeventAttach(c, base);
    redisAsyncCommand(c, onMessage, NULL, "SUBSCRIBE testtopic");
    event_base_dispatch(base);
    return 0;
}

Ubuntu 14.04์—์„œ ์ด ์˜ˆ์ œ๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์ปดํŒŒ์ผํ•˜๋ ค๋ฉด libevent-dev ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ปดํŒŒ์ผํ•˜๋Š” ๋™์•ˆ -levent ํ”Œ๋ž˜๊ทธ๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์„œ์˜ ๋ฌธ์ œ๋Š” ๊ตฌ๋…ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ์•„๋ฌด ๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋‚ด์šฉ์ด ์–ด๋””์—๋„ ์ž‘์„ฑ๋˜์ง€ ์•Š์•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค.

redisAsyncCommand(c, onMessage, NULL, "SUBSCRIBE testtopic");
redisAsyncCommand(c, onAnotherMessage, NULL, "SUBSCRIBE anothertopic");
redisAsyncCommand(c, onReply, NULL, "SET toto 5");
redisAsyncCommand(c, onReply, NULL, "PUBLISH testtopic \"hello\"");
redisAsyncCommand(c, onReply, NULL, "GET toto");

๊ทธ๋ฆฌ๊ณ  2๊ฐœ์˜ ์ฒซ ๋ฒˆ์งธ ๋ช…๋ น๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” REDIS_OK ์‘๋‹ตํ•˜์ง€๋งŒ onReply() ์ฝœ๋ฐฑ์€ NULL ์‘๋‹ต์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

์ผ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ˆ˜ํ–‰ํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ 2๊ฐœ์˜ redis ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” ๊ตฌ๋…(๋ฐ MONITOR)์šฉ์ด๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ๋‚˜๋จธ์ง€์šฉ์ž…๋‹ˆ๋‹ค. ์ด ์ œํ•œ ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•˜๋„๋ก ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ• ๊นŒ์š”?

EACH API์— ๋Œ€ํ•œ ๋ฌธ์„œ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์†Œ์ผ“์ด ๊ฒฐ๊ตญ ๋‹ซํž ๋•Œ ์ด๋ฒคํŠธ๋ฅผ ์–ด๋–ป๊ฒŒ ์บก์ฒ˜ํ•ฉ๋‹ˆ๊นŒ?

์†Œ์ผ“์ด ๊ฒฐ๊ตญ ๋‹ซํž ๋•Œ ์ด๋ฒคํŠธ๋ฅผ ์–ด๋–ป๊ฒŒ ์บก์ฒ˜ํ•ฉ๋‹ˆ๊นŒ?

์•„๋‹ˆ๋ฉด ๋น ๋ฅด๊ฒŒ ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ์ƒˆ ์—ฐ๊ฒฐ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ทธ ์‚ฌ์ด์— ์žˆ๋Š” ๋ฐฉํ™”๋ฒฝ์ด ์—ฐ๊ฒฐ์„ ๋‹ซ๊ณ  ๊ทธ ํ›„์— ํŒจํ‚ท์„ ์‚ญ์ œํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

ํ•ด๋‹น ์—ฐ๊ฒฐ์—์„œ ๊ตฌ๋…๋งŒ ํ•˜๋ฉด ์‹œ๊ฐ„ ์ดˆ๊ณผ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ TCP keepalives๋Š” ASYNC์™€ ํ•จ๊ป˜ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์œผ๋ฉฐ ์–ด์จŒ๋“  ์ด๋“ค์€ ์˜ˆ๋ฅผ ๋“ค์–ด ๋„์ปค ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์˜ Linux์—์„œ ์ œ๋Œ€๋กœ ๊ตฌ์„ฑํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค(์˜ˆ: ๊ฐ„๊ฒฉ, ์žฌ์‹œ๋„ ๋“ฑ).

์ผ๋ฐ˜์ ์œผ๋กœ TCP ์†Œ์ผ“์„ ์‚ฌ์šฉํ•˜๋ฉด ์†Œ์ผ“์—์„œ ์งง์€ ์ฝ๊ธฐ/์“ฐ๊ธฐ ์‹œ๊ฐ„ ์ดˆ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ณด๋‚ธ ํ›„ ์‹œ๊ฐ„ ์ดˆ๊ณผ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ณ  ๋น ๋ฅด๊ฒŒ ๋‹ค๋ฅธ ์„œ๋ฒ„์— ๋‹ค์‹œ ์—ฐ๊ฒฐํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์ž‘์—…์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค...

ping ๋ช…๋ น์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ณด๋‚ด๊ณ  ์—ฐ๊ฒฐ ํ•ด์ œ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋„๋ก ์ฝ๊ธฐ/์“ฐ๊ธฐ ์ œํ•œ ์‹œ๊ฐ„์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค๋ฅธ ๊ฒƒ์ด ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@Gerporgl
๋‚ด ์ž์‹ ์˜ ๊ตฌํ˜„์—์„œ redisAsyncSetDiconnectCallback์„ ํ™œ์šฉํ–ˆ์œผ๋ฉฐ ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์—ฐ๊ตฌํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
https://github.com/nidhhoggr/twemproxy_sentinel/commit/602e07cfdbd57a307ff008e8e9d41909ac34b004

์ œ ๊ฒฝ์šฐ์—๋Š” ์—ฐ๊ฒฐ ํ•ด์ œ ์ด๋ฒคํŠธ๊ฐ€ ๋‚ด๊ฐ€ ํ•ญ์ƒ "์ž๋™ ์—ฐ๊ฒฐ ํ•ด์ œ"๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ์ถฉ๋ถ„ํžˆ ๋นจ๋ฆฌ(๋˜๋Š” ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ์ „ํ˜€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”) ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค(5์‹œ๊ฐ„ ์ด์ƒ ๊ธฐ๋‹ค๋ ธ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๋ถ„ ๋™์•ˆ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์ง€ ๋ชปํ–ˆ์ง€๋งŒ 10-15๋ถ„ ํ›„์— ๋งˆ์นจ๋‚ด ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค)

์ฃผ์ œ์— ๋Œ€ํ•ด ์กฐ๊ธˆ ๋” ์ฝ์€ ํ›„ ๊ตฌ๋…ํ•˜๋Š” ๋™์•ˆ ์—ฌ์ „ํžˆ PING ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ  ๊ฒŒ์‹œ๋œ ๋ฉ”์‹œ์ง€์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์ž์‹ ์˜ PING ์‘๋‹ต ์ด๋ฒคํŠธ๋ฅผ ๊ตฌ๋…ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์–ธ๊ธ‰ํ•˜๋Š” ์ด ๊ฒŒ์‹œ๋ฌผ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.
https://github.com/redis/hiredis/issues/351

๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€๊ธˆ ์ž˜ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ๊ฒƒ์€ ์˜ˆ๋ฅผ ๋“ค์–ด 1์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ PING์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด๋ฉฐ, ๋” ์ด์ƒ ํ•‘ ์‘๋‹ต์„ ๋ฐ›์ง€ ๋ชปํ•˜๋ฉด(๋˜๋Š” ํŠน์ • ํ—ˆ์šฉ ํ•œ๊ณ„ ์ž„๊ณ„๊ฐ’์„ ํ—ˆ์šฉํ•˜๋ฉด) ์—ฐ๊ฒฐ์ด ๋Š์–ด์กŒ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ์ •๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•œ ๋‹ค์Œ ๋‹ค์‹œ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ํ›จ์”ฌ ๋” ๊ฐ•๋ ฅํ•˜๊ณ  ๋น ๋ฅธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

libevent ๋ฐ hiredis๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ผ๋ฐ˜ ๋ฉ”์‹œ์ง€ ์ „๋‹ฌ์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ PING์— ๋Œ€ํ•œ ํƒ€์ด๋จธ ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์™„์ „ํ•œ ๋น„๋™๊ธฐ ๊ตฌ๋… ๊ตฌํ˜„์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Gerporgl
์ด๊ฒƒ์€ ๋งค์šฐ ๋„์›€์ด๋˜์—ˆ์Šต๋‹ˆ๋‹ค!
ํ˜น์‹œ ํ‚ค ๊ณต๊ฐ„ ์ด๋ฒคํŠธ ์•Œ๋ฆผ์— ๋Œ€ํ•ด ๋™์ผํ•œ redisAsyncCommand/Async ์ปจํ…์ŠคํŠธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๊นŒ?
๋‚˜๋Š” ๊ทธ ๋ถ€๋ถ„์ด ์ž‘๋™ํ•˜๋„๋ก ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ถˆํ–‰ํžˆ๋„ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ์‹œ๋„ ํ–ˆ์Šต๋‹ˆ๊นŒ?

redis-cli config set notify-keyspace-events KEA
redisAsyncCommand(c, subscribeCallback, NULL, "PSUBSCRIBE __key*__:*");

@joe-at-startupmedia
๊ฐ์‚ฌ ํ•ด์š”! ๋‚˜๋Š” ์ด๋ฏธ ์ด๊ฒƒ์„ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚ด๊ฐ€ ์–ป๋Š” ๋ชจ๋“  ๊ฒƒ์€ ์ฒซ ๋ฒˆ์งธ psubscribe ์‘๋‹ต์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
๋ฐ์ดํ„ฐ์˜ ์—…๋ฐ์ดํŠธ๋Š” ์‹ค์ œ๋กœ ์ฝœ๋ฐฑ์—์„œ ์ˆ˜์‹ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ƒ˜ํ”Œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

`

SUBSCRIBE_CHANNEL "SUBSCRIBE URLC_Updates" ์ •์˜

SUBSCRIBE_KEYEVENT ์ •์˜ "PSUBSCRIBE '__key __: '"

SCAN_DB "SCAN %d COUNT 100" ์ •์˜

QUERY_KEY "GET %s" ์ •์˜

๋ฌดํšจ์˜
onPubsubMessage(redisAsyncContext *c, ๋ฌดํšจ *์‘๋‹ต, ๋ฌดํšจ *privdata)
{
redisReply *r = (redisReply *) ๋‹ต์žฅ;
if (์‘๋‹ต == NULL) ๋ฐ˜ํ™˜;

/* What if reply type is something else... */
if (r->type == REDIS_REPLY_ARRAY) {

    for (int j = 0; j < r->elements; j++) {
        if (r->element[j]->type == REDIS_REPLY_STRING) { 
            myPubsubFile.open(PUBSUB_FILE, fstream::in | fstream::out | fstream::app);
            myPubsubFile << r->element[j]->str << endl;
            myPubsubFile.close();
        } else if (r->element[j]->type == REDIS_REPLY_INTEGER) {
            cout << "Integer : "<< r->element[j]->integer << endl;
        }
    }
}
return;

}
๋ฌดํšจ์˜
onKeyspaceMessage(redisAsyncContext *c, ๋ฌดํšจ *์‘๋‹ต, ๋ฌดํšจ *privdata)
{
redisReply *r = (redisReply *) ๋‹ต์žฅ;
if (์‘๋‹ต == NULL) ๋ฐ˜ํ™˜;

cout << "Got keyspace event notification from REDIS.. " << endl;

/* What if reply type is something else... */
if (r->type == REDIS_REPLY_ARRAY) {
    cout << "Type is an array.. " << endl;
    cout << "Number of elements here: " << r->elements << endl;

    for (int j = 0; j < r->elements; j++) {
        cout << "\t\t Type for element : " << r->element[j]->type << endl;
        if (r->element[j]->type == REDIS_REPLY_STRING) {
            cout << "\t\t\t" << r->element[j]->str << endl;
        } else if (r->element[j]->type == REDIS_REPLY_INTEGER) {
            cout << "\t\t\t" << "Integer : "<< r->element[j]->integer << endl;
        }   
    }   
} else {
    cout << "This is the type for response : " << r->type << endl;
}   
return;

}
๋ฌดํšจ์˜*
pubsubRecipient(๋ฌดํšจ* ์ธ์ˆ˜)
{
๊ตฌ์กฐ์ฒด event_base *base = event_base_new();

redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
    printf("error: %s\n", c->errstr);
    return NULL;
}   

redisLibeventAttach(c, base);
redisAsyncCommand(c, onPubsubMessage    , NULL, SUBSCRIBE_CHANNEL);
redisAsyncCommand(c, onKeyspaceMessage  , NULL, SUBSCRIBE_KEYEVENT);

`

PS REDIS์—์„œ ํ‚ค ๊ณต๊ฐ„ ์•Œ๋ฆผ์„ ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ตฌ์„ฑ ๋ถ€๋ถ„์€ ๋ณ„๋„์˜ ํ”„๋กœ์„ธ์Šค์— ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ„๋„์˜ ํ„ฐ๋ฏธ๋„์—์„œ redis-cli ์ธ์Šคํ„ด์Šค๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ํ•ด๋‹น ๊ตฌ์„ฑ์˜ ํšจ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ๋ˆ„๋ฝ๋œ ๊ฒƒ์ด ์žˆ์ง€๋งŒ keyevent ๊ตฌ๋… ๋ฌธ์ž์—ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 "PSUBSCRIBE 'key*:*'"

ํ•ด๋‹น ํŒจํ„ด์— ๋งž๊ฒŒ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜์ง€ ์•Š์„๊นŒ์š”?

"PSUBSCRIBE __key*__:*"

์˜ค.. ์ด ํŽธ์ง‘๊ธฐ์—์„œ ์ด์ƒํ•œ ์ผ์ด ๋ฒŒ์–ด์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค... ๋‚ด ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์„ ๋•Œ ํ‚ค ๋ฅผ ๋‘˜๋Ÿฌ์‹ผ ๋ฐ‘์ค„์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋ฌธ์ œ๋Š” ๋‚ด _ _ ํ‚ค * _ _ ํŒจํ„ด์„ ๋‘˜๋Ÿฌ์‹ผ -> ' ' <-(์ž‘์€ ๋”ฐ์˜ดํ‘œ)์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
redis-cli๋Š” ๋ฌธ์ œ ์—†์ด ์ด๋ฅผ ์ˆ˜๋ฝํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ redis ๋ช…๋ น์„ ํ†ตํ•ด ๋ณด๋‚ผ ๋•Œ ์—ฌ๊ธฐ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋ž˜๋œ ๋ฌธ์ œ๋ฅผ ๊ฒช๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๋…„ ์ „์— Wiki์— ์˜ˆ์ œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค(@aluiken์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค).

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰