규모화된 마이크로서비스 아키텍처를 위해 Redis 및 Lua 스크립트 캐시를 사용하여 데이터를 집계하는 방법


규모화된 마이크로서비스를 기반으로 한 응용 프로그램은 끊임없이 증가하는 데이터를 가지고 있기 때문에 최고급 목록 등 집합 데이터를 효과적으로 제공하는 것은 도전이다.
본 논문에서, 나는 당신에게 Redis 캐시 집합의 데이터를 어떻게 사용하는지 보여 드리겠습니다.데이터베이스는 항목/행 데이터를 "진실의 출처"로 저장하고 슬라이스로 축소한다.

A single Redis instance can handle some 100,000 operations per second


사용자, 게시물, 유형을 포함하는 예시 데이터 모델은 사용자 자신의 용례의 기초가 될 수 있습니다.

컨텐트

  • 예시 용례와 데이터 모델
  • Redis 설정 및 최상위 클래스
  • 상위 사용자, 최신 사용자 게시물 및 받은 편지함 모드
  • 원자용 Lua 스크립트
  • 마지막 생각과 전망

    1. 예시용례와 데이터 모델


    예시에서, microsoft 응용 프로그램 사용자는 분류에 따라 게시물을 작성할 수 있다.그들은 또한 작가의 이름을 포함하여 분류에 따라 댓글을 읽을 수 있다.최신 게시물이 위에 있습니다.분류는 고정적이어서 거의 바뀌지 않는다.

    See my previous post “ ” if you are interested in source code and more details about the example application.


    논리 데이터 모델:

    현재 100만 명의 사용자가 있다.사용자마다 매일 약 10편의 댓글을 쓴다.

    십대류


    홈 페이지에 상위 10개의 범주가 표시됩니다.MySql의 경우 다음과 같은 문이 필요합니다.
    SELECT CategoryId, COUNT(PostId) FROM Post GROUP BY CategoryId ORDER BY COUNT(PostId) LIMIT 10;
    
    수백만 줄에 대해 이 문장을 집행하는 것은 매우 느릴 것이다.매 페이지의 방문에서, 이것은 모두 불가능하다.
    데이터의 양이 매우 많기 때문에, 나는 또 유형별로 나누기로 결정했다.따라서 여러 데이터베이스의 최상위 목록을 결합해야 합니다.

    2. Redis 설정 및 최상위 분류


    설치 Docker Desktop
    Redis 컨테이너를 만들려면 다음과 같이 하십시오.
    C:\dev>docker run --name redis -d redis
    
    컨테이너에 연결하고 redis cli 시작하기
    C:\dev>docker exec -it redis redis-cli
    

    최상위 클래스 추가


    최상위 클래스(CategoriesByPostCount)는 Redis sorted set(ZSET)을 사용합니다.
    범주 5의 첫 번째 항목 ZADD과 99개의 게시물을 추가합니다.
    127.0.0.1:6379> ZADD CategoriesByPostCount GT 99 "Category5"
    
    항목이 추가되었습니다.
    (integer) 1
    
    추가 항목 추가:
    > ZADD CategoriesByPostCount GT 1 "Category1"
    
    (integer) 1
    
    > ZADD CategoriesByPostCount GT 10 "Category2"
    
    (integer) 1
    
    업데이트 범주 5:
    > ZADD CategoriesByPostCount GT 100 "Category5"
    
    (integer) 1
    
    > ZADD CategoriesByPostCount GT 98 "Category5"
    
    (integer) 0
    
    마지막 명령의 결과는 0이다.GT 매개변수 때문입니다.이 매개 변수는 업데이트가 무질서하게 도착하는 상황을 처리하는 데 도움이 됩니다. (post 계수는 감소하지 않습니다.)

    인기 범주 읽기


    ZRANGE을 사용하여 상위 10개의 게시물을 읽습니다.
    > ZRANGE CategoriesByPostCount 0 9 WITHSCORES REV
    
    1) "Category5"
    2) "100"
    3) "Category2"
    4) "10"
    5) "Category1"
    6) "1"
    
    두 번째 페이지(엔트리 11-20) 등을 쉽게 검색할 수 있습니다.
    ZRANGE CategoriesByPostCount 10 19 WITHSCORES REV
    

    선결 조건


    새 게시물을 작성할 때 SQL에서 각 범주의 게시물을 계산할 수 있습니다.
    BEGIN TRANSACTION
    INSERT INTO Post (...)
    UPDATE Categories SET PostCount = PostCount + 1
    COMMIT TRANSACTION
    
    이것은 가능한 것이다. 왜냐하면 데이터베이스는 분류에 따라 구분되기 때문이다.같은 종류의 모든 게시물은 같은 데이터베이스에 있습니다.

    3. 최상위 사용자, 최신 사용자 게시물 및 받은 편지함 모드


    사용자의 게시물이 모든 조각에 흩어져 있다.UPDATE User SET PostCount=PostCount+1을 사용하여 Redis를 업데이트할 수 없습니다.
    Redis의 작업은 반드시 멱이어야 합니다.받은 편지함 모드가 가능합니다.
    자세히 보기: Outbox, Inbox patterns and delivery guarantees explained

    게시물 추가(경쟁 조건 포함)


    새 게시물마다 사용자의 *PostsByTimestamp* 정렬 세트에 항목을 추가합니다.
    > ZADD {User:5}:PostsByTimestamp 3455667878 '{Title: "MyPostTitle", Category: "Category5", PostId: 13}'
    
    (integer) 1
    
    그런 다음 UsersByPostCount에 post 수를 추가합니다.
    > ZINCRBY UsersByPostCount 1 "5"
    
    멱을 기다리게 하려면 우편물을 수신함에 추가한 결과를 확인하십시오.명령을 다시 실행하면 결과가 0이 됩니다(이미 항목이 있음).
    > ZADD {User:5}:PostsByTimestamp 3455667878 '{Title: "MyPostTitle", Category: "Category5", PostId: 13}'
    
    (integer) 0
    
    그런 다음 UsersByPostCount를 추가하지 마십시오.
    ZADD to PostsBy Timestamp 명령과 ZINCRBY to UsersBy Post Count 명령은 원자여야 합니다.Redis Lua 스크립트를 사용하여 원자화하는 방법을 보여 드리겠습니다.우선, 최고급 사용자와 최신 사용자의 댓글을 살펴봅시다.

    최상위 사용자 및 최신 사용자 게시물 읽기


    상위 10개 사용자:
    > ZRANGE UsersByPostCount 0 9 WITHSCORES REV
    
    1) "6"
    2) "10"
    3) "5"
    4) "8"
    5) "3"
    6) "4"
    7) "1"
    8) "3"
    
    아이디 6인 이용자는 댓글 10편, 아이디 5인 이용자는 댓글 8편 등이다.
    ID 5인 사용자의 핫 게시물:
    > ZRANGE {User:5}:PostsByTimestamp 0 9 WITHSCORES REV
    
    1) "{Title: \"MyPostTitle2\", Category: \"Category1\", PostId: 14}"
    2) "3455667999"
    3) "{Title: \"MyPostTitle\", Category: \"Category5\", PostId: 13}"
    4) "3455667878"
    

    4. 원자성을 위한 Lua 스크립트


    Lua 스크립트를 사용하여 자동으로 게시물 추가


    Redis Lua script은 명령ZADD를 PostsByTimestamp, 명령ZINCRBY를 UsersByPostCount 원자로 설정할 수 있습니다.그러나 모든 관건적인 파라미터가 같은 Redis hash tag에 비치도록 사용자마다 별도의 계수기를 필요로 한다.

    The curly braces like in the key “{User:5}:PostsByTimestamp” are signifiers for a Redis hash tag.


    이 루아 스크립트는 정렬 집합에 키를 추가하려고 합니다.키를 추가할 수 있다면, 계수기를 추가할 것입니다.키가 이미 있으면 키 값이 반환됩니다.

    EVAL을 사용하여 Lua 스크립트를 호출하고 "{User:8}: PostsByTimestamp"및 "{User:8}: PostCount"을 키로 전달(명령줄의 한 줄):



    > EVAL "if tonumber(redis.call('ZADD', KEYS[1], ARGV[1], ARGV[2])) == 1 then return redis.call('INCR', KEYS[2]) else return redis.call('GET', KEYS[2]) end" 2 {User:8}:PostsByTimestamp {User:8}:PostCount 3455667999 "{Title: \"MyPostTitle2\", Category: \"Category1\", PostId: 14}"
    
    (integer) 1
    

    그리고 UsersByPostCount에서 사용자 8의 계수를 설정합니다:



    ZADD UsersByPostCount GT 1 "8"
    

    Redis에 스크립트 저장


    다음과 같은 이유로 Redis sript performance에 저장할 수 있습니다.



    > SCRIPT LOAD "if tonumber(redis.call('ZADD', KEYS[1], ARGV[1], ARGV[2])) == 1 then return redis.call('INCR', KEYS[2]) else return redis.call('GET', KEYS[2]) end"
    
    "cd9222afab5eb8d579942016a8c22427eff99429"
    

    해시 호출 스크립트 사용:



    > EVALSHA "cd9222afab5eb8d579942016a8c22427eff99429" 2 {User:8}:PostsByTimestamp {User:8}:PostCount 4455667999 "{Title: \"MyPostTitle3\", Category: \"Category1\", PostId: 20}"
    
    (integer) 2
    



    5. 마지막 생각과 전망


    본문에서 Redis를 설정하고 간단한 용례부터 데이터를 캐시합니다.그리고 inbox 모드와 Lua 스크립트를 사용하여 원자성을 실현합니다


    다음 기사에서는 C#ASP에서 구현하는 방법을 보여 드리겠습니다.NET 코어 마이크로서비스 어플리케이션


    Redis는 제가 본문에서 보여준 것보다 훨씬 많은 것을 제공합니다.다른 명령과 use-cases이 응용 프로그램의 문제를 어떻게 해결하는지 연구할 수 있습니다.실제 응용 프로그램에서 캐시가 무한히 증가하지 않도록 TTL을 사용하여 항목을 자동으로 종료해야 할 수도 있습니다.레디스를 확장해야 할지도 몰라


    질문, 생각 또는 건의가 있으면 저에게 연락하세요

    좋은 웹페이지 즐겨찾기