본문 바로가기

카테고리 없음

Database 데드락 발생 시 해결 방법

반응형

스트리밍 서버를 개발 하다가 데이터베이스 데드락이 발생 해 서버가 다운 되는 현상이 발생했다.

클라이언트가 채널에 접속 했을 때 데이터베이스에 유저의 정보를 저장하고 퇴장했을 때 저장한 정보를 지워야 한다.

동시 접속자 수가 1000명인 경우 한번에 접속 해도 문제가 없었지만 5000명이 넘어갔을 때 부터 문제가 발생했다.

CPU 점유율이 100%로 치솟아 렉이 걸리거나 심한 경우 서버가 다운되는 현상이 발생했다. 

원인은 테스트 프로그램으로 N명의 유저들을 임의적으로 채널에 접속 시키는데 중간에 종료시키면 한번에 N명의 유저들의 소켓이 끊기면서 채널에 퇴장하게 된다.

그 때 여러개의 DB 커넥션이 생성되고 교착상태가 발생하는 것이었다.

물론 데이터베이스 커넥션 풀을 늘리는 것으로 어느 정도 해결할 수 있겠지만 무한정으로 늘릴 수도 없기 때문에 하나의 커넥션으로 여러 개의 쿼리를 처리할 수 있게 만들어 보았다.

 

Add 함수를 통해 쿼리를 큐에 쌓는다.

DelayWorkWatcher 클래스는 주기적으로 일정 시간을 기다렸다가 Execute 함수를 실행시키는 역할을 한다.

Execute 함수는 쿼리에 쌓인 데이터를 복사해 데이터베이스에 접근하는 역할을 한다.

 

    public class DelayQueryWatcher
    {
        private static string TAG = "DelayQuery";
        
        private DelayWorkWatcher _watcher;
        private Queue<string> _delayQuery = new Queue<string>(5000); // userid, query
        private ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
        private Repository _repository;

 
        public DelayQueryWatcher(Repository repository, int period)
        {
            this._watcher = new DelayWorkWatcher(TAG, period, ExecuteQuery, false);
            this._repository = repository;
        }
        public void Add(string query)
        {
            using (this._rwLock.GuardWrite())
            {
                this._delayQuery.Enqueue(query);
                Console.WriteLine($"{TAG} : ADD {Util.MillsToDate(Util.CurrentTimeMills())}, {query}");
            }
        }
        
        public void Start()
        {
            this._watcher.Start();
        }

        private void ExecuteQuery()
        {
            if (this._delayQuery.Count == 0) 
                return;
            
            Queue<string> tempQuery;
            using (this._rwLock.GuardWrite())
            {
                tempQuery = new Queue<string>(this._delayQuery);
                this._delayQuery.Clear();
            }
            
            this._repository.ExecuteQuery(tempQuery);
        }
    }

 

값 비싼 DB 커넥션을 한번만 생성할 수 있기 때문에 부하가 덜 발생한다는 장점이 있지만 Database와의 싱크가 최대 period만큼 생길 수 있다는 단점이 있다.

 

반응형