Backend

개발 중 예상치 못한 Redis 메모리 초과 문제로 서버가 다운되는 경험을 했다.  테스트용으로 임시 서버를 두고 작업을 해두었던 터라, 잠깐의 시간 동안 Redis Memory가 가득 찰 일은 없겠다는 안일한 생각을 했다. 그래서 Redis의 maxmemory와 maxmemory-policy 설정을 따로 해두지 않았었다. 그러다보니 무제한으로 데이터를 저장할 수 있는 상태가 되었다. 그리고 서버가 꽝 터졌다. 이번 기회를 통해 Redis 설정을 최적화하는 과정을 공유해보고자 한다.  문제 상황개발 중이던 프로젝트에서, Redis를 사용해 방에 참가한 사용자 닉네임을 list 자료구조에 저장했다.  테스트 중, 클라이언트에서 소켓 이벤트를 잘못 처리해 엄청난 양의 데이터가 Redis로 흘러들어왔고, 순식..
문제 상황로컬 환경에서 배포된 서버 Backend의 WebSocket으로 접근하는 상황이었다.인증 정보를 쿠키로 전달하려 했지만, WebSocket 연결이 완료되지 못했다.bet.gateway.ts handleConnection(client: Socket) { try { const cookies = this.jwtUtils.parseCookies( client.handshake.headers.cookie, ); const accessToken = cookies["access_token"]; if (!accessToken) { client.emit("error", { event: "handleConnection", ..
문제 상황 실시간으로 베팅이 이루어지는 서비스이다. "만약 많은 사용자가 동시에 베팅을 진행할 경우, 동시성 문제가 일어나 데이터가 부정확해지는 것은 아닐까?" 고민을 하게 되었다. 구체적인 상황은 아래와 같다.1. 베팅을 하면 카운트가 올라간다. (베팅 참여자, 베팅한 금액)2. 카운트를 올리기 위해 데이터를 조회한다.3. 조회한 데이터에 증가 연산을 수행한다.4. 업데이트 된 데이터를 저장한다. 위 경우, 만약 두 명의 사용자가 데이터가 1인 시점에 접근해 각각 1씩 올려도 3이 아니라 2가 되는 동시성 문제가 발생하게 되는 것이다.   결론부터 이야기하면, 레디스와 레디스의 HINCRBY 명령어를 통해 원자성을 보장할 수 있었다. HINCRBY 명령어와 가상의 테스트 시나리오를 통해, 어떻게 동시성..
Redis는 단일 스레드(single-threaded) 기반으로 동작한다!레디스는 단일 스레드를 기반으로 동작한다.즉, 한번에 하나의 요청만 가능하다. 이는 하나의 명령을 처리하는 동안 다른 명령은 대기 상태로 머무르게 된다는 것을 말한다. Redis 명령어 처리 과정이 부분에서 내부 처리 과정을 이해해보는 것도 좋을 것 같다.Redis는 클라이언트의 요청을 처리할 때 두 가지 주요 단계를 거친다.processInputBuffer 단계Redis는 클라이언트로부터 들어오는 데이터를 입력 버퍼(input buffer)에 저장하고, 클라이언트가 보낸 패킷이 하나의 완전한 명령어로 완성될 때까지 이 버퍼에 쌓이게 된다.processCommand 단계패킷이 완전한 명령어로 완성되면, Redis는 processCo..
MySQL의 명령어를 공부해본 사람이라면, DROP과 TRUNCATE, DELETE 명령어의 차이를 들어보았을 것이다.  간단하게 이야기를 하자면, DELETE 명령어는 원하는 데이터를 지울 수 있고, 삭제 후 잘못 삭제한 것을 되돌릴 수 있다. TRUNCATE 명령어는 테이블은 삭제하지는 않고, 데이터만 삭제한다. 삭제 후 절대 되돌릴 수 없다. DROP 명령어는 테이블 전체를 삭제한다. 삭제 후 절대 되돌릴 수 없다.   그럼 DROP 명령어는 어떻게 작동하길래, 테이블이 통채로 사라질까?MySQL의 innoDB에서는 테이블을 .ibd 파일로 저장한다.  DROP시 .ibd 파일이 어떻게 되는지 살펴보자.mysql> CREATE DATABASE test_db;Query OK, 1 row affecte..
MySQL은 내부적으로 OS의 파일 I/O를 사용한다. 그럼 어느 정도는 직접 구현해볼 수 있지 않을까?  우선 MySQL의 아키텍처를 참고해보았다.MySQL은 SQL 구문이 들어오면 Parser -> 전처리기 -> 옵티마이저 -> 엔진 실행기 -> 스토리지 엔진 순서로 동작한다.  설계여기서 옵티마이저와 엔진 실행기는 제거하고 설계했다. 옵티마이저의 실행 계획 알고리즘 CBO를 구현할 역량이 없다고 생각했다. 또 내부적으로 실행 계획에 따라 풀스캔이나 인덱스로 탐색하는 것을 구현해야하는데, 마찬가지로 구현할 역량이 없다고 판단했다.  스토리지 엔진은 InnoDB를 참고했다.  그런 이유로 아키텍처는 아래와 같이 구성했다.   이번 구현에서 초점을 둔 것은, Disk I/O를 최대한 줄이는 것을 목표로 ..
동구름이
'Backend' 카테고리의 글 목록