상세 컨텐츠

본문 제목

Redis 사용기

라이브러리

by ougi 2025. 9. 4. 21:05

본문

오늘은 제가 redis를 사용하게 된 계기와 어떻게 사용했는지 또 redis는 무엇인지에 대하여 글을 적게 되었습니다


 

Redis란?

redis는 Remote(원격)에 위치하고 프로세스로 존재하는 In-Memory 기반의 Dictionary(key-value) 구조 데이터 관리 Server 시스템입니다

 

데이터 고속 읽기와 쓰기에 최적화 되어 있습니다

메모리에서 데이터를 처리하기 때문에 작업 속도가 빠릅니다

많은 프로그래밍 언어 프레임워크에 대한 API를 폭 넓게 지원합니다

 

In-Memory db

디스크나 SSD가 아닌 컴퓨터의 주 메모리(RAM)에 데이터를 저장하고 관리하는 데이터베이스

 

캐시의 구조 패턴

  • Look aside cache: 캐시를 한 번 접근 하여 데이터 여부를 확인 후 있다면 캐시의 데이터를 사용하고 없으면 실제 DB 또는 API를 호출합니다
  • Write Back: insert 쿼리를 일일이 날리지 않고 한꺼번에 배치 처리하기 이해 사용됩니다

해결 방법

제가 이 팀 소개를 구현하면서 총 두 가지 문제가 있었는데 하나씩 말씀 드리겠습니다

CORS

깃허브에 요청을 보낼 때 처음에는 CORS가 터져서 어떻게 해결을 했냐면 next.js에서 제공하는 기능인 route handler 기능을 이용해서 프록시로 우회하여 요청을 처음 보내는데 성공 했습니다 

밑에는 코드와 제가 route handler를 학습할 때 적었던 글입니다

import { NextResponse } from 'next/server';


export async function GET(
  { params }: { params: { id: string } }
) {
  try {
    const { id } = params;

    const githubResponse = await fetch(`https://api.github.com/users/${encodeURIComponent(id)}`, {
      headers: {
        'Accept': 'application/vnd.github.v3+json',
        'User-Agent': 'Gwangju-talent-festival-Client',
      },
    });

    if (!githubResponse.ok) {
      if (githubResponse.status === 404) {
        return NextResponse.json(
          { error: 'not found' },
          { status: 404 }
        );
      }

      return NextResponse.json(
        { error: 'failed to fetch' },
        { status: githubResponse.status }
      );
    }

    const githubData = await githubResponse.json();

    return NextResponse.json(githubData);
  } catch (error) {
    console.error(error);
    return NextResponse.json(
      { error: 'internal server error' },
      { status: 500 }
    );
  }
}

https://baeougi.tistory.com/56

 

next.js route handler에 대해서 알아보자

오늘은 최근에 적용해본 next.js에서 제공하는 route handler라는 기능에 대해서 글을 써보려고 합니다!! route handler란?next.js에서 제공하는 기능 중 하나로 특정 경로에 대한 사용자 정의 요청 처리기(c

baeougi.tistory.com

요청 횟수 제한

그 다음 깃허브로 토큰을 발급 받아서 하는 요청의 제한 수가 1일 5000회로 제한되어 있었는데 이 요청수가 너무 부족하여서

해결 방법을 고민하다가 redis를 선택하게 되었습니다

전체적인 흐름을 말씀 해드리겠습니다

  1. 사용자가 접속하면 캐시가 있는지 확인
  2. 없다면 깃허브에 요청을 다시 전송
  3. 있다면 캐시된 데이터를 반환

추가로 코드와 함께 설명드리겠습니다

// redis.ts

import Redis, { type Redis as RedisType } from "ioredis";

declare global {
  var _redis: RedisType | undefined;
}

function buildUrl(): string {
  if (process.env.REDIS_URL && process.env.REDIS_URL.trim().length > 0) {
    return process.env.REDIS_URL.trim();
  }

  const host = process.env.REDIS_HOST!;
  const port = process.env.REDIS_PORT!;
  const password = process.env.REDIS_PASSWORD ?? "";

  const useTLS = process.env.REDIS_TLS === "1" || process.env.REDIS_TLS?.toLowerCase() === "true";

  const protocol = useTLS ? "rediss" : "redis";
  const passEnc = encodeURIComponent(password);

  return `${protocol}://default:${passEnc}@${host}:${port}`;
}

function createRedis(): RedisType {
  const url = buildUrl();
  const isTLS = url.startsWith("rediss://");
  return new Redis(url, {
    ...(isTLS ? { tls: {} } : {}),
    connectTimeout: 10_000,
    maxRetriesPerRequest: 2,
    retryStrategy: (times: number) => Math.min(times * 200, 2000),
  });
}

export const redis = global._redis ?? createRedis();
if (!global._redis) global._redis = redis;
// 수정된 route.ts

import { redis } from "@/shared/lib/redis";
import { NextResponse } from "next/server";

const KEY = (id: string) => `gh:user:${id}`;
const TTL_SECONDS = 60 * 60 * 24;

export async function GET(_request: Request, { params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;

  let cached: string | null = null;
  try {
    cached = await redis.get(KEY(id));
  } catch (e) {
    throw e;
  }
  if (cached) {
    return new NextResponse(cached, {
      status: 200,
      headers: { "Content-Type": "application/json", "X-Cache": "HIT" },
    });
  }

  const gh = await fetch(`https://api.github.com/users/${encodeURIComponent(id)}`, {
    headers: {
      Accept: "application/vnd.github.v3+json",
      "User-Agent": "gwangtalpe-client",
      Authorization: `Bearer ${process.env.GITHUB_TOKEN ?? ""}`,
    },
    cache: "no-store",
  });

  if (!gh.ok) {
    if (gh.status === 404) {
      return NextResponse.json({ error: "not found" }, { status: 404 });
    }
    return NextResponse.json({ error: "failed to fetch" }, { status: gh.status });
  }

  const data = await gh.json();

  try {
    await redis.set(KEY(id), JSON.stringify(data), "EX", TTL_SECONDS);
  } catch (error) {
    throw error;
  }

  return NextResponse.json(data, { status: 200, headers: { "X-Cache": "MISS" } });
}

글을 마치며..

오늘은 redis에 대해서 알아보았는데 처음 해보는 것이라 처음에 자신이 없었는데 하고나서 되니 정말 기분이 좋고 뿌듯 했던거 같습니다

여러분들도 꼭 무엇이든 도전하시면 좋을거 같습니다

글을 읽어주셔서 감사합니다

728x90

관련글 더보기