Redis CLIENT LIST

Redis Server Course Redis Technical Support Redis Enterprise Server

Redis CLIENT LIST

서버에 접속된 클라이언트들의 정보와 통계값을 조회한다.   보여주는 형태는 다음과 같다.

  • 한 클라이언트는 한 라인에 표시된다.
  • 각 라인은 여러개의 파라미터=값으로 표시된다.


예제는 슬레이브가 1개 있는 마스터 서버에 접속해서 실행한 경우이다.

Example

명령>client list
결과> id=57 addr=127.0.0.1:36820 laddr=127.0.0.1:6379 fd=9 name= age=5 idle=0 flags=N db=0
sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466
events=r cmd=client user=default redir=-1

필드 값의 의미

  • id: 클라이언트 ID (2.8.12 부터 도입되었다)
  • addr: 클라이언트의 주소(ip)/포트
  • laddr: 클라이언트가 접속한 서버의 IP, Port가 표시됩니다.
  • fd: 소켓과 연관된 파일 디스크립터(file descriptor)
  • name: client setname으로 설정하면 이름이 나온다.
    슬레이브는 이름이 설정되어 있지 않다.   센티널 서버는 레디스 마스터와 슬레이브에 2개 접속한다.   예를 들면 sentinel-fcb2f55a-cmd와 sentinel-fcb2f55a-pubsub 이다.   fcb2f55a는 센티널 서버 RUN-ID 앞 8자리이다.
  • age: 접속부터 현재까지 시간(초)
  • idle: 명령을 실행하지 않은 시간(초)
    이 명령을 실행한 클라이언트는 항상 0으로 나온다.   다른 클라이언트의 idle 시간을 확인할 수 있다.  
    슬레이브(플래그 S)일때는 항상 0이다.   왜냐하면 슬레이브는 마스터에 1초에 한번씩 확인 메시지를 보낸다.  
    센티널 서버가 레디스 마스터나 슬라이브에 접속은 보통 1로 나온다.  
  • flags: 클라이언트 플래그
    일반 클라이언트는 N, Monitor 명령을 실행중인 클라이언트는 O, 슬레이브는 S로 표시된다.
    client list를 실행한 클라이언트는 마지막 cmd에 client가 표시된다. Monitor를 실행중인 클라이언트는 cmd에 monitor가 표시되고, 슬레이브 S는 cmd에 reolconf가 표시된다.
    슬레이브 서버에 접속했을때 마스터는 M으로 표시되고, 다른 명령이 없다면 마스터가 슬레이브에 10초에 한번씩 ping을 날리므로 cmd에 ping이 표시되고, idle은 0에서 9까지 증가했다가 다시 0부터 시작한다.
    자세한 내용은 아래 클라이언트 플래그를 보세요.
  • db: 현재 접속된 DB 번호.
  • sub: subscription 채널 수.
  • psub: subscription 페턴 매칭 수.
  • multi: MULTI/EXEC 컨텍스트 명령 수. 디폴트 -1.
  • qbuf: 쿼리 버퍼 길이( 0은 쿼리 의존이 아님)
  • qbuf-free: 쿼리 버퍼 여유 공간(0은 버퍼가 꽉찼음, 여유 공간이 없음을 의미)
  • obl: Output buffer length
  • oll: Output list length(버퍼가 꽉찼을때 이 리스트에서 응답)
  • omem: Output buffer memory usage 버퍼 메모리 사용량
  • events: file descriptor events (아래 파일 디스크립터 이벤트를 보세요)
  • cmd: 마지막 수행된 명령. 명령만 나온다. 키부분은 나오지 않는다.
    슬레이브(플래그 S)일때는 보통 replconf 로 나온다.
    센티널이 레디스 마스터에 2개 접속하는데 ping과 subscribe이다.
    센티널이 레이스 슬레이브에 2개 접속하는데 publish와 subscribe이다.


클라이언트 플래그

  • O: 슬레이브 (모니터 모드)
  • S: 슬레이브
  • M: 마스터
  • x: 클라이언트가 MULTI/EXEC context 실행 중
  • b: 클라이언트가 blocking operation 대기중.
  • i: 클라이언트가 VM I/O 대기중(deprecated)
  • d: a watched keys has been modified - EXEC will fail.
  • c: connection to be closed after writing entire reply.
  • u: the client is unblocked.
  • U: the client is connected via a Unix domain socket.
  • r: the client is in readonly mode against a cluster node. 클러스터에서 읽기전용 모드.
  • A: connected to be closed ASAP.
  • N: no specific flag set.
    레디스 클아이언트로 접속하면 N으로 나온다.
    센티널 서버 접속은 N으로 나온다.


파일 디스크립터 이벤트(File Descriptor Event)

  • r: 읽기 가능 클라이언트 소켓(event loop)
  • w: 쓰기 가능 클라이언트 소켓(event loop)



Source code

Version 3.0.2

struct redisClient
redis.h
/* With multiplexing we need to take per-client state.
 * Clients are taken in a linked list. */
typedef struct redisClient {
    uint64_t id;            /* Client incremental unique ID. */
    int fd;
    redisDb *db;
    int dictid;
    robj *name;             /* As set by CLIENT SETNAME */
    sds querybuf;
    size_t querybuf_peak;   /* Recent (100ms or more) peak of querybuf size */
    int argc;
    robj **argv;
    struct redisCommand *cmd, *lastcmd;
    int reqtype;
    int multibulklen;       /* number of multi bulk arguments left to read */
    long bulklen;           /* length of bulk argument in multi bulk request */
    list *reply;
    unsigned long reply_bytes; /* Tot bytes of objects in reply list */
    int sentlen;            /* Amount of bytes already sent in the current
                               buffer or object being sent. */
    time_t ctime;           /* Client creation time */
    time_t lastinteraction; /* time of the last interaction, used for timeout */
    time_t obuf_soft_limit_reached_time;
    int flags;              /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
    int authenticated;      /* when requirepass is non-NULL */
    int replstate;          /* replication state if this is a slave */
    int repl_put_online_on_ack; /* Install slave write handler on ACK. */
    int repldbfd;           /* replication DB file descriptor */
    off_t repldboff;        /* replication DB file offset */
    off_t repldbsize;       /* replication DB file size */
    sds replpreamble;       /* replication DB preamble. */
    long long reploff;      /* replication offset if this is our master */
    long long repl_ack_off; /* replication ack offset, if this is a slave */
    long long repl_ack_time;/* replication ack time, if this is a slave */
    char replrunid[REDIS_RUN_ID_SIZE+1]; /* master run id if this is a master */
    int slave_listening_port; /* As configured with: SLAVECONF listening-port */
    multiState mstate;      /* MULTI/EXEC state */
    int btype;              /* Type of blocking op if REDIS_BLOCKED. */
    blockingState bpop;     /* blocking state */
    long long woff;         /* Last write global replication offset. */
    list *watched_keys;     /* Keys WATCHED for MULTI/EXEC CAS */
    dict *pubsub_channels;  /* channels a client is interested in (SUBSCRIBE) */
    list *pubsub_patterns;  /* patterns a client is interested in (SUBSCRIBE) */
    sds peerid;             /* Cached peer ID. */

    /* Response buffer */
    int bufpos;
    char buf[REDIS_REPLY_CHUNK_BYTES];
} redisClient;

networking.c
void clientCommand(redisClient *c) {
    if (!strcasecmp(c->argv[1]->ptr,"list") && c->argc == 2) {
        /* CLIENT LIST */
        sds o = getAllClientsInfoString();
        addReplyBulkCBuffer(c,o,sdslen(o));
        sdsfree(o);
    }
}

sds getAllClientsInfoString(void) {
    listNode *ln;
    listIter li;
    redisClient *client;
    sds o = sdsempty();

    o = sdsMakeRoomFor(o,200*listLength(server.clients));
    listRewind(server.clients,&li);
    while ((ln = listNext(&li)) != NULL) {
        client = listNodeValue(ln);
        o = catClientInfoString(o,client);
        o = sdscatlen(o,"\n",1);
    }
    return o;
}

adlist.c

/* Create an iterator in the list private iterator structure */
void listRewind(list *list, listIter *li) {
    li->next = list->head;
    li->direction = AL_START_HEAD;
}

networking.c

/* Concatenate a string representing the state of a client in an human
 * readable format, into the sds string 's'. */
sds catClientInfoString(sds s, redisClient *client) {
    char flags[16], events[3], *p;
    int emask;

    p = flags;
    if (client->flags & REDIS_SLAVE) {
        if (client->flags & REDIS_MONITOR)
            *p++ = 'O';
        else
            *p++ = 'S';
    }
    if (client->flags & REDIS_MASTER) *p++ = 'M';
    if (client->flags & REDIS_MULTI) *p++ = 'x';
    if (client->flags & REDIS_BLOCKED) *p++ = 'b';
    if (client->flags & REDIS_DIRTY_CAS) *p++ = 'd';
    if (client->flags & REDIS_CLOSE_AFTER_REPLY) *p++ = 'c';
    if (client->flags & REDIS_UNBLOCKED) *p++ = 'u';
    if (client->flags & REDIS_CLOSE_ASAP) *p++ = 'A';
    if (client->flags & REDIS_UNIX_SOCKET) *p++ = 'U';
    if (client->flags & REDIS_READONLY) *p++ = 'r';
    if (p == flags) *p++ = 'N';
    *p++ = '\0';

    emask = client->fd == -1 ? 0 : aeGetFileEvents(server.el,client->fd);
    p = events;
    if (emask & AE_READABLE) *p++ = 'r';
    if (emask & AE_WRITABLE) *p++ = 'w';
    *p = '\0';
    return sdscatfmt(s,
        "id=%U addr=%s fd=%i name=%s age=%I idle=%I flags=%s db=%i sub=%i psub=%i multi=%i
				qbuf=%U qbuf-free=%U obl=%U oll=%U omem=%U events=%s cmd=%s",
        (unsigned long long) client->id,
        getClientPeerId(client),
        client->fd,
        client->name ? (char*)client->name->ptr : "",
        (long long)(server.unixtime - client->ctime),
        (long long)(server.unixtime - client->lastinteraction),
        flags,
        client->db->id,
        (int) dictSize(client->pubsub_channels),
        (int) listLength(client->pubsub_patterns),
        (client->flags & REDIS_MULTI) ? client->mstate.count : -1,
        (unsigned long long) sdslen(client->querybuf),
        (unsigned long long) sdsavail(client->querybuf),
        (unsigned long long) client->bufpos,
        (unsigned long long) listLength(client->reply),
        (unsigned long long) getClientOutputBufferMemoryUsage(client),
        events,
        client->lastcmd ? client->lastcmd->name : "NULL");
}

/* This function returns the client peer id, by creating and caching it
 * if client->peerid is NULL, otherwise returning the cached value.
 * The Peer ID never changes during the life of the client, however it
 * is expensive to compute. */
char *getClientPeerId(redisClient *c) {
    char peerid[REDIS_PEER_ID_LEN];

    if (c->peerid == NULL) {
        genClientPeerId(c,peerid,sizeof(peerid));
        c->peerid = sdsnew(peerid);
    }
    return c->peerid;
}



명령문

CLIENT LIST [TYPE normal|master|replica|pubsub] [ID client-id [client-id ...]]

  • 이 명령은 version 2.4.0 부터 사용할 수 있다.
  • 논리적 처리 소요시간은 O(N)입니다. N은 클라이언트의 개수입니다.
  • 버전 2.8.12에서 유일한 client id 필드가 추가되었습니다.
  • 버전 5.0에서 TYPE 옵션이 추가되었습니다.
  • 버전 6.2에서 laddr 필드가 추가되었고, ID 옵션이 추가되었습니다.
Clients for C Hiredis

<< CLIENT SETNAME CLIENT LIST CLIENT INFO >>

Email 답글이 올라오면 이메일로 알려드리겠습니다.

혹시 처음이세요?
레디스게이트에는 레디스에 대한 많은 정보가 있습니다.
레디스 소개, 명령어, SQL, 클라이언트, 서버, 센티널, 클러스터 등이 있습니다.
혹시 필요한 정보를 찾기 어려우시면 redisgate@gmail.com로 메일 주세요.
제가 찾아서 알려드리겠습니다.
 
close
IP를 기반으로 보여집니다.