AWS 기술 블로그

Amazon Aurora MySQL 오해와 진실

지금까지 온라인 게임 서비스의 게임 데이터베이스로는 강력한 성능을 가진 Microsoft SQL Server가 오랜 기간 널리 사용되어 왔습니다. 하지만 점차 다양화된 게임 데이터베이스에 대한 요구사항들에 따라, 많은 프로젝트들이 용도에 맞는 데이터베이스를 유연하게 사용하기 위해 다양한 오픈소스 데이터베이스를 적극 검토하는, 이른바 Database Freedom을 추구하고 있습니다.

AWS에서 클라우드 환경을 위해 커스터마이징한 Amazon Aurora(이하 Aurora)는 이런 솔루션들 중 관계형 데이터베이스로 활용하기에 적합한 강력한 성능과 다양한 기능, 유연성과 안정성을 모두 갖춘 제품입니다. AuroraMySQLPostgreSQL 과 호환되는 완전 관리형 데이터베이스로서, 오픈소스의 비용 효율성과 상용 데이터베이스 수준의 성능을 모두 제공합니다.

하지만 이전에 SQL Server를 사용하는 과정에서 일반적으로 사용하던 일부 기능들이나 요구되는 성능 수준이 오픈 소스 데이터베이스에서는 충분히 지원되지 않는다는 이유로 전환을 주저하는 경우도 많이 있습니다.

이번 블로그에서는 이런 우려 사항들에 대해 간단히 살펴보고, Aurora MySQL 로 데이터베이스를 변경하는 과정에서 우려사항들에 대처하는 방법들을 소개해 드리고자 합니다.

오해와 진실

그럼 이런 우려사항들을 어떻게 해소하거나 줄일 수 있을지, 혹은 이런 우려사항들 중 오해가 있는 부분은 없는지 하나씩 살펴보겠습니다.

오해 1. MySQL Stored Procedure 의 성능 문제

앞서 말씀드렸던 대로 ‘MySQL에서도 Stored Procedure를 사용할 수 있으나, 성능이 떨어진다’고 알고 계시는 분들이 많습니다.
이 내용은 일부는 사실이고 일부는 사실이 아닙니다.

MySQL에서도 Stored Procedure는 사용이 가능합니다만, 일반적인 실행 환경에서 MySQL Stored Procedure를 실행하는 것이 SQL Server에 비해 낮은 성능을 보일 수 있습니다. 하지만 MMORPG 서비스와 같은 특정한 조건의 워크로드에서는 상용 데이터베이스 수준의 성능을 가진 Aurora MySQL을 사용할 경우 동일한 동작을 위해 Stored Procedure를 사용하더라도 충분히 고객이 요구하는 수준의 성능을 기대할 수 있습니다. 자세한 내용은 이어서 업로드될 Stored Procedure의 성능에 대해 테스트한 다른 시리즈 블로그를 참고하시기 바랍니다.

하지만 장기적인 측면에서 보았을 때, 개발이나 유지보수 측면 모두에서 Stored Procedure 를 적극적으로 사용하는 서버 설계 및 구현은 그리 바람직하지 않습니다. 그 이유 역시 다른 블로그에 자세히 설명 예정이며, 다른 기술 문서들에서도 언급되곤 합니다.
각 블로그의 내용 중 이 주제에 맞는 중요 내용만 요약하자면 다음과 같습니다.

  • MySQL에서 Stored Procedure 사용은 connection이 많을 수록 문제가 되지만, 게임 서버 워크로드는 connection pooling을 사용하며 그 접속 개수가 그리 많지 않기 때문에 큰 문제가 없음
  • Stored Procedure는 게임 개발 및 유지보수 과정에서 추가적인 비용과 시간을 필요로 하기 때문에 효율적인 개발을 위해서는 사용하지 않거나 최소한으로 사용하는 것이 좋음

따라서 일부 SQL 문법의 차이에만 주의한다면 Aurora MySQL에서 기존 방식과 유사하게 Stored Procedure를 그대로 사용할 수 있으므로, 보다 적은 부담으로 데이터베이스를 전환할 수 있습니다. 실제 문법 차이가 있는 예를 몇 가지 들어 보겠습니다.

#1. SET NOCOUNT ON

SQL Server의 Stored Procedure는 실행이 완료될 때 영향을 받은 행 수를 표시하는 메시지를 리턴합니다. 하지만 서버 어플리케이션에서 Stored Procedure를 호출할 때 이 메시지가 필요한 경우는 많지 않아서, 대부분 SET NOCOUNT ON 구문을 추가하여 해당 메시지를 받지 않도록 설정하는데요. MySQL은 영향을 받은 행 수를 기본적으로 표시하지 않기 때문에 이 구문을 사용할 필요가 없습니다.

#2. TVP(Table-Valued Parameters)

SQL Server에서 Stored Procedure를 호출하면서 가변 개수의 매개 변수를 여러 개 처리해야 할 경우가 있습니다. 예를 들어 수집형 게임에서 ‘영웅 뽑기’, 소위 ‘가챠’라고 이야기하는 기능을 실행할 때가 그런 경우인데요. 게임에 따라 다르지만 보통 영웅 뽑기는 1번만 할 때도 있고, 10번을 한꺼번에 할 때도 있고, 게임에 따라서는 30번에서 100번까지 한꺼번에 할 때도 있습니다. 이런 경우 뽑은 영웅들을 한 번에 데이터베이스에 저장하기 위해서는 1번에서 100번까지 뽑기를 수행한 결과로 생성된 값들을 Stored Procedure에 매개 변수로 넘겨야 합니다.

이런 경우 SQL Server에서는 TVP 기능을 사용하여 임시 테이블 변수를 선언한 뒤 가변 개수의 레코드를 해당 테이블에 삽입한 후, 그 테이블을 Stored Procedure에 그대로 매개 변수로 전달하여 필요한 동작을 수행합니다.

-- TableType 생성
CREATE TYPE [dbo].[CreateItemType] AS TABLE(
    [Id] [bigint] NULL,
    [OwnerId] [bigint] NULL,    
    [Grade] [tinyint] NULL,
    [Level] [int] NULL,
    [Exp] [bigint] NULL,
    [Enchant] [tinyint] NULL
)
GO

-- Stored Procedure 정의
CREATE PROCEDURE [dbo].[spItemGacha] 
    @heroes AS [dbo].[CreateItemType] Readonly
AS
BEGIN
-- ...
END

-- TableType에 가변 매개변수 준비
DECLARE @gachaData CreateItemType
INSERT INTO @gachaData VALUES (1, 2, 1, 1, 0, 0)

-- 가변 매개변수를 Stored Procedure에 전달
EXECUTE dbo.spItemGacha @gachaData

MySQL에서는 매개 변수를 json으로 받아 파싱하여 처리하거나, Temporary Table을 사용하는 방식으로 TVP에서 기대하는 가변 레코드 입력이라는 요구조건을 만족할 수 있습니다.
Temporary Table을 사용하는 경우 주의할 점은, MySQL에서 Temporary Table은 해당 Table을 생성한 세션이 유지되는 동안 계속 남아 있다는 것입니다. 따라서 사용이 끝난 뒤에는 명시적으로 DROP TEMPORARY TABLE 구문으로 삭제하는 것이 좋습니다.

# Temporary Table 생성
CREATE TEMPORARY TABLE IF NOT EXISTS create_item_type (
    `id` BIGINT NOT NULL,
   `owner_id` BIGINT NOT NULL,    
    `grade` TINYINT NOT NULL,
    `level` INT NOT NULL,
    `exp` BIGINT NOT NULL,
    `enchant` TINYINT NOT NULL
);

INSERT INTO create_item_type VALUES (1, 2, 1, 1, 0, 0);

실제 워크로드에서의 테스트가 필요할 수 있으나 실제 MMORPG와 유사한 환경에서의 TVP 호출을 json이나 Temporary Table을 사용하는 방식으로 대체하여 테스트해 본 결과, Temporary Table을 사용한 경우 고객의 요구사항을 만족할 만한 처리 성능을 보여주었습니다. 앞서 말씀드린 시리즈 블로그에 보다 자세한 내용을 정리하여 제공하겠습니다.

오해 2. 기존에 유용하게 사용하던 기능들

#1. SQL Server Agent

SQL Server에서는 SQL Server Management Studio(SSMS)라는 강력한 통합 툴을 사용하여 데이터베이스 관리를 손쉽게 할 수 있는데요. 그 중 유용하게 쓰이는 기능이 SQL Server Agent 를 통한 주기적인 배치 작업 실행입니다.
GUI에서 간단하게 설정하여 원하는 시간마다 관리 작업을 위한 쿼리들을 실행하는 등의 설정이 가능합니다.

MySQL에서는 이런 기능을 MySQL Event Scheduler 를 통해 처리할 수 있습니다. 위의 예와 같이 매일 오전 12:00에 특정한 Stored Procedure를 처리하는 배치 작업은 아래와 같은 명령으로 설정할 수 있습니다.

DELEMITER //
CREATE EVENT BATCH_JOB_TEST
ON SCHEDULE EVERY 24 HOUR
STARTS '2024-09-01 00:00:00'
DO
    CALL batch_job_proc();

AWS 관리형 서비스들을 이용한다면 AWS Lambda 함수를 실행하여 단순히 쿼리를 실행하는 것 이상으로 복잡한 작업들을 수행할 수 있습니다. 작업을 자동화하고 싶다면 Amazon Eventbridge에서 이벤트 기반으로 AWS Lambda 함수를 실행하여 특정한 조건에서 자동으로 배치 작업을 처리하도록 하는 등의 방법으로도 대체할 수 있습니다.

#2. DMV/Xevent

Dynamic Management Views(DMV)SQL Server에서 성능 모니터링 등을 위해 유용하게 사용되는 view입니다. 예를 들어, CPU 사용 시간 기준으로 상위 10개의 쿼리를 확인하고 싶은 경우는 아래와 같은 쿼리를 실행하여 결과를 확인할 수 있습니다.

SELECT TOP 10
    SUBSTRING(st.text, (qs.statement_start_offset/2) + 1,
        ((CASE qs.statement_end_offset
            WHEN -1 THEN DATALENGTH(st.text)
            ELSE qs.statement_end_offset
        END - qs.statement_start_offset)/2) + 1) AS query_text,
    qs.total_worker_time / qs.execution_count / 1000.0 AS avg_cpu_time_ms,
    qs.execution_count
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
WHERE st.text NOT LIKE '%sys.dm%'
ORDER BY qs.total_worker_time / qs.execution_count DESC;

MySQL 에서도 Performance Schema를 통해 동일한 효과를 얻을 수 있습니다. 같은 결과를 출력하는 명령을 MySQL에서는 다음과 같이 내릴 수 있습니다.

SELECT sys.format_statement(DIGEST_TEXT) AS query,
       ROUND(AVG_TIMER_WAIT / 1000000000, 2) AS avg_cpu_time,
       COUNT_STAR AS exec_count
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT IS NOT NULL
  AND SCHEMA_NAME NOT LIKE 'mysql.%'
ORDER BY AVG_TIMER_WAIT DESC
LIMIT 10;

또한 모니터링 관련된 여러 지표들은 Aurora MySQL의 경우 Performance Insight에서도 확인 가능합니다.
Performance Insight에서는 데이터베이스 동작과 관련된 여러 지표 상황을 보기 쉽게 확인할 수 있게 해 주므로 유용합니다.

이와 같이 SQL Server에서 유용하게 사용하는 많은 기능들을 MySQL에서도 다른 방법으로 충분히 대체할 수 있으며, 성능 역시 크게 뒤쳐지지 않습니다. 특히 SQL Server의 SSMS의 기능들과 유사한 역할을 하는 Aurora MySQL의 기능들 역시 시리즈의 다른 블로그에서 소개할 예정입니다.

Aurora MySQL에서 제공하는 여러 유용한 기능들

단순히 기존 SQL Server 워크로드를 대체하는 것 외에도, Aurora MySQL에서 제공하는 여러 유용한 기능들을 활용하면 보다 편리한 개발 및 서비스가 가능합니다. 이 역시 다른 블로그에 더 자세히 소개되어 있으므로 참고하시기 바랍니다. 해당 블로그의 내용을 간단히 요약하면 다음과 같습니다.

  • 빠른 백업 및 복구를 통한 테스트 환경 구축
  • Blue/Green 배포를 사용한 빠른 데이터베이스 패치
  • Backtrack 및 특정 시점으로의 빠른 복구(PITR)를 활용한 반복 테스트 및 작업 실수에 대한 빠른 대처
  • Zero-ETL로 실시간에 가까운 단순한 분석 아키텍처 구축
  • Limitless Database로 단일 인스턴스 서비스

결론

지금까지

  • 비용 이슈가 있음에도 게임 databaseSQL Server를 사용할 수밖에 없었던 고객들의 우려 사항들
  • 그런 우려사항을 Aurora MySQL을 사용할 경우 어떻게 해결할 수 있는지
  • Aurora MySQL에서 제공할 수 있는 유용한 기능들은 어떤 것들이 있는지

에 대해 짧게 알아보았습니다.
설명드린 내용을 요약하면 다음과 같습니다.

오해 진실
Stored Procedure의 성능 문제 게임 워크로드에서는 사용 가능(하지만 줄이거나 없애는 것이 현대화)
유용하게 사용하는 문법들을 사용할 수 없음 다른 툴 및 기능으로 대체 가능
기존에 익숙하던 툴과 기능들 MySQL 자체 기능이나 AWS 관리형 서비스 등을 활용하여 대체 가능
Aurora MySQL에서 제공하는 여러 기능들을 게임 개발 및 유지 보수에 유용하게 사용 가능

이런 내용들을 잘 이해하셔서 더 많은 게임 개발 조직들이 상용 database에서 비용이나 유지보수 측면에서의 이점이 더 많은 오픈소스 database로 이전하여 효율적인 개발 및 유지보수로 진정한 비즈니스 가치에 집중할 수 있길 바랍니다.
저희 AWS는 게임 고객들의 모든 워크로드 현대화 지원을 위해 준비되어 있으므로, SQL Server 외에도 Microsoft 워크로드 현대화에 관심이 있으신 고객들은 언제든 문의 주시면 도움을 드리겠습니다.

Hyunchang Sung

Hyunchang Sung

성현창 솔루션즈 아키텍트는 게임 고객들이 AWS에서 성공적으로 게임을 개발하고 운영할 수 있도록 지원하고 있습니다. 게임 업계에서 오랫동안 게임 서버 프로그래머로 일했던 경험을 살려 게임 개발 및 서비스 전반에서 고객들에게 필요한 도움을 드리고 있습니다.