본문 바로가기

과거공부모음

나의 개발일지 TIL(Today I learned) - 트랜잭션, 동시성 제어

Today I learned

최종 프로젝트에서 예약 기능을 구현해보기 위해서 미리 알아보면서 필요한 기능을 학습하고 있다

예약 기능에 무엇이 필요한가 생각을 하다가 혹시 3명만 예약을 해야하는데 같은 날 같은 시간에

동시에 예약이 5명이 예약을 진행한다면 5명이 다 예약이 되어버리는 문제가 발생하지 않을까

생각을 했다 그래서 바로 간단한 테스트를 진행해 보았다

//cats.service.ts

try {
      const cats = await this.catsRepository.find({
        where: { deleteAt: null },
      });

      if (cats.length >= 2) {
        throw new Error('testing error');
      }

      this.catsRepository.insert({
        name: cat.name,
        age: cat.age,
        breed: cat.breed,
      });
      
    } catch (err) {
      console.log(err);
    }
// axios index.js

setTimeout(() => {
    axios({
      url: '<http://localhost:8080/cats>',
      method: 'post',
      data: {
        name: '누누',
        age: 2,
        breed: '먼치킨',
      },
    })
      .then(() => {
        console.log('누누 등록');
      })
      .catch((e) => {
        console.log('axios 통신실패');
      });
  }, '5000');
  setTimeout(() => {
    axios({
      url: '<http://localhost:8080/cats>',
      method: 'post',
      data: {
        name: '나나',
        age: 2,
        breed: '먼치킨',
      },
    })
      .then(() => {
        console.log('나나 등록');
      })
      .catch((e) => {
        console.log('axios 통신실패');
      });
  }, '5000');
  setTimeout(() => {
    axios({
      url: '<http://localhost:8080/cats>',
      method: 'post',
      data: {
        name: '도도',
        age: 2,
        breed: '먼치킨',
      },
    })
      .then(() => {
        console.log('도도 등록');
      })
      .catch((e) => {
        console.log('axios 통신실패');
      });
  }, '5000');
  setTimeout(() => {
    axios({
      url: '<http://localhost:8080/cats>',
      method: 'post',
      data: {
        name: '다다',
        age: 2,
        breed: '먼치킨',
      },
    })
      .then(() => {
        console.log('다다 등록');
      })
      .catch((e) => {
        console.log('axios 통신실패');
      });
  }, '5000');

setTimeout을 이용해서 동시에 post요청을 진행했다

if문에 걸리지 않고 모두 데이터베이스에 입력이되는 문제가 생각했던 그대로 발생했다

이 문제를 해결하기 위해서 트랜잭션을 적용해 보았다

트랜잭션을 이용해서 동시에 데이터베이스에 접근하지 못하게 동시성 제어를 해야한다

학습을 하다가 다중 사용자 환경을 지원하는 DBMS는 반드시 동시성 제어를 해야한다고 한다

고립 수준 (Isolation level)을 이용해서 트랜잭션이 동시에 실행되면서 발생하는 문제를 해결하기 위해서 DBMS가 제공하는 명령어가 있다

지금 발생하는 문제는 오손읽기(Drity Read) 때문에 발생한다고 생각했다

쓰는 작업을 하는 트랜잭션이 쓰는 작업을 하는 동안 다른 트랜잭션이 중간에 데이터를 읽으면 발생하는 문제다

그래서 READ COMMITTED 레벨로 설정해서 진행해봤지만 문제는 동일하게 발생한다

데이터를 변경 또는 삽입을 하려고 할 떄 SELECT를 못하게 모두 락을 걸어버리는 SERIALIZABLE으로

레벨을 올려서 진행을 했다 4개가 동시에 데이터베이스에 삽입되는 문제는 발생하지 않지만

데드락 문제가 발생을 했다

문제해결을 하지 못했다 어떻게 해야하지?

startTransaction이 동시에 발생한다면 어떻게 될까?

데드락에 대해서 더 알아보기

서로 다른 트랜잭션이 데이터베이스를 점유하려고 할 때 발생하는 에러

TypeScript로 처리하기 매우 힘든 구현

동시성 제어가 매우 힘들면 통락을 걸어버리는 방법도 최소한 해결 방안이다

TypeScript에서 하기 힘들기 때문에 Redis를 이용해서 동시성 제어를 할 수 있다

Redis를 이용해서 예약에서 발생하는 동시성 제어를 처리할 수 있도록 학습하자

nestjs의 Queues를 사용해서 nestjs/bull을 이용해서 처리해보자

동시성 제어를 확실한 테스트를 하기 위해서 제이미터를 사용해보자

 

오늘 배운점은 시야가 좁아지지 말자! 너무 데이터베이스 쪽에서만 해결해보려고 하다가 방법을 찾지 못했다