redis를 활용한 api 로그 count 관리

2023. 5. 2. 08:38it

반응형

redis를 활용한 api 로그 count 관리하는 법에 대해 알아 보겠다. 이번 요청 사항은 스마트팩토리 팀에서 api의 call 되는 count 수를 물어봤다. aws 지표를 보여주니 믿지 못한다. 이유는 그렇게 많이 api를 호출 될 일이 없다고 이야기했다. api가 100만건 호출되는게 그렇게 많은 건 아닌데, 믿지 못하시 조금 답답했다. 그리고 apache log도 aws 모니터링 지표도 믿지 않으면..?!?!? 무엇을 믿고 싶은 것일까? 의문이 들었다. 그냥 만들어 달라고 해서, 나는 오늘도 만든다..

 

 

728x90

 

api의 성능 저하를 주지 않고, 사소한 요구사항이 합쳐져서 그냥 redis로 api call 하는 기능을 만들어 보기로 했다. 특별한 이유는 없다. 그냥 평소에 redis incr를 써보고 싶었다. ★

 

redis incr이란?

redis incr은 그냥 해당 키에 일정 값을 증가시키는 함수이다. 그냥 더히기 함수라고 보면 편하다. 문법은 아래와 같다. 

 

1. 기본 문법

 # SET key(사용자 지정키) 0(초기값)
 SET incrkey 0

 

2. 값 증가 시키기

INCR incrkey

 

이렇게 명령어를 날리면 incrkey의 값이 0에서 1로 변하는 것을 볼 수 있다. 아주 심플하다. 그리고 인메모리라 성능도 빠르다. 즉, 이보다 빠른 수 없다는 것이다. 그럼 해당 문법을 활용해 redis를 활용한 api 로그 count 관리하는 법을 알아보겠다. 

 

 

redis를 활용한 api 로그 count 관리

일단 해당 프로그램을 만들기 전에 주의사항이 있다. redis 엔터프라이즈가 아니면, ttl이 지원되지 않는다. 즉, 내가 귀찮지만 데이터를 계속 지워주어야 한다는 것이다. 즉, 최소 2번 통신을 해야한다. redis의 key의 수와 값을 증가시키는 두번의 통신 ㅠㅠ

 

해당 함수는 python으로 짰다. 최대 10개의 로그 count를 관리한다. 사용 방법은 api call 하는 순간 제일 첫번째 줄에 넣으면 된다. 받는 파라미터는 api_name 과 현재 시간을 넣으면 된다. datetime으로 넣으면, 일 단위로 관리가 가능하며, string 으로 넣을 경우, 해당 string으로 받아서 넣는다.

 

즉, 시간 단위로 로그를 관리하고 싶다면 datetime을 시간 yyyy-mm-dd hh:00:00 이런 식으로 해당 함수를 저장하면 된다. 

그럼 해당 함수에 대해 알아보자.


redis를 활용한 api 로그 count 함수

 

반응형

 

# 최대 크기 설정
import redis
import datetime

r = redis.Redis(host='localhost', port=6379, db=0)

MAX_SIZE = 10

def call_api_count(function_name , current_date, value = 1):
    print( current_date )
    print( type(current_date) )
    if type(current_date) == datetime.datetime : 
        current_date = current_date.strftime('%Y-%m-%d')
    
    
    # 해시 크기 확인
    if r.hlen(function_name) >= MAX_SIZE:
        # 가장 오래된 키-값 쌍 삭제
        oldest_key = r.hkeys(function_name)[0]
        r.hdel(function_name, oldest_key)
    r.hincrby(function_name, current_date, value)

 

call_api_count(function_name , current_date, value = 1) 로 파라미터는 총 3개다. 

 

function_name : api의 이름을 넣으면 된다. 그럼 api의 이름별로 해당 데이터가 쌓이게 된다. 해당 키 아래는 current_date 라는 값이 있다.

 

current_date : 우리는 시간 단위로 로그를 관리할 생각이였기에, 해당 시간을 넣어주어야 한다. 동일한 시간의 경우, 값을 value를 증가시키고, 일자가 변경되면, 해당 시간때를 분리해 다시 count를 증가시킨다. 

 

value : 증가되는 값의 디폴트 값이다. 즉, incr의 기본 값이라고 보면 된다. 디폴트값은 1이지만, 다른 값으로 증가시키고 싶다면 해당 값을 변경해서 사용하면 된다.

 

말로 설명하면 이해가 안 갈수 있으니, 아래 그림을 참고하면 된다. 

 

 

MAX_SIZE 의 경우, Current_time이 쌓일 수 있는 수이다. 해당 함수는 10으로 설정이 되어 있어, 10일간 데이터가 쌓이고, 지워진다. 즉, TTL이라고 보면 된다. 뭐 사용자가 원한다면 해당 사이즈는 조정해서 사용하면 된다. 

 

oldest_key = r.hkeys(function_name)[0] 은, 해당 함수에서 가장 첫번째 입력된 값, 즉 가장 오래된 값을 가지고 알는 명령어이다. 그래서 그 명령어로 가지고 온 KEY를 가지고 해당 키를 r.hdel(function_name, oldest_key)  삭제해 준다. 

redis를 활용한 api 로그 count 함수 적용하기

from flask import Flask
import datetime
import redis


app = Flask(__name__)

r = redis.Redis(host='localhost', port=6379, db=0)

MAX_SIZE = 10

def call_api_count(function_name , current_date, value = 1):
    print( current_date )
    print( type(current_date) )
    if type(current_date) == datetime.datetime : 
        current_date = current_date.strftime('%Y-%m-%d')
    
    
    # 해시 크기 확인
    if r.hlen(function_name) >= MAX_SIZE:
        # 가장 오래된 키-값 쌍 삭제
        oldest_key = r.hkeys(function_name)[0]
        r.hdel(function_name, oldest_key)
    r.hincrby(function_name, current_date, value)


@app.route('/helloworld/print')
def helloworld():
    # api count 함수
    current_time = datetime.datetime.now()
    call_api_count('/helloworld/print' , current_time )
    
    return 'Hello_World!!'

app.run(host='0.0.0.0', port=81)

 

helloworld라는 함수가 있는 경우, helloworld 상단에 call_api_count 함수를 등록하면 된다. 그럼 등록 순간부터 자동으로 redis에 해당 api의  call count를 관리해 준다. 

 

귀찮았지만, 1시간도 안 걸려서 바로 배포했다. 그래도 나름 잘 돌아간다. 실시간으로 api count 수가 올라가는거 보니 기분은 좋다 ㅎㅎ

반응형