IT 관련/Database

MariaDB Galera Cluster- lock문제

nullzone 2017. 12. 30.
반응형


MariaDB Galera Cluster- lock문제



MariaDB Galera Cluster 적용시, Lock 문제는 매우 심각하며, 이로 인하여 오히려 Cluster 보다는 replication방법이 더 나을수도 있다는 생각이 종종 든다. 


이번에는 실제 Galera Cluster 적용시 겪게 된 문제를 예로 들어 보겠습니다.

실제 적용되었던 서비스는 앱에서 사용자들의 액션(클릭같은행위)을 서버로 전송 하고 해당 데이터를 가공해서 저장 하는 시스템이였습니다. 앱에서 데이터를 전송 받아 DB로 쏴주는 서버가 약 6대정도 였고.... 트래픽은 DB입장에서 보면 100/초 정도 였습니다. (물론 실시간으로 저장된 정보를 다시 집계 하는 서버로 전송합니다.) 


1. DB단위가 아닌 DB Server 단위로 적용

이 부분은 내가 못찾은 건지 아니면 지원이 안되는 것인지 Cluster 를 DB단위로 구성이 불가 합니다.

server 단위가 되다보니 Cluster에 참여 하는 DB는 오직 필요한  DB만 사용해야 합니다.

제 불평일수도 있는데... 아무튼 좀 불편합니다. 


2. PK없는 테이블은 절대 사용 하면 안된다.

저는 모든 테이블에 PK가 있을 줄 알았는데,  정작 몇 개의 테이블이 PK가 없었습니다.

해당 테이블의 데이터 변경시에 100% lock이 걸리더군요...

찬찬히 Galera Cluster 를 살펴보니 모든 데이터는 Row 단위  복제를 합니다. 

즉, Row단위로 데이터를 처리 하는데 있어서 PK가 없으면 문제가 발생합니다.

당연한 이야기 처럼들리는데 간혹 테이블에 PK 없이 Unique Index를 이용 하는 경우가 있으면 Galera에서 데이터 처리 하는데 PK가 없다고 해서 Unique Index를 이용하지는 않습니다. 당연히 Galera는 PK가 존재 할 것이라고 여기며 이를 이용하여 데이터 싱크를 합니다. 

예를들어 history table라는 테이블이 있는데, 이는 단순히 데이터 집계를 위해 만들어둔 테이블이고 조회는 없고, 일단위 배치로 데이터만 만들어 저장 한다고 해서 PK만들지 않고 reg_date에 index걸어서 두었고, 아울러 일정시간이 지나면 삭제을 위하여  

delete from history where reg_date < 2017-01-01' ; 

와 같은 쿼리를 매일 새벽에 실행되도록 해주었다면,  

이런 쿼리를 돌릴 경우 Galera는 Cluster내의 node에 동일한 query 문을 실행하는 구조가 아니라 Row 단위 처리를 합니다. 

따라서 PK가 없는 테이블에 인덱스 컬럼을 이용하여 row 1개를 삭제 한다고 하면 전체 데이터에서 full scan 하는 구조를 가진듯 합니다. 제가 내부 소스를 볼만한 실력이 없는데 아래와 같은 결과를 보면 row단위 처리를 위해서 반드시 pk를 만들어 줘야 합니다.


show processlist;

     Id  User         Host             db      Command      Time  State                                      Info              Progress  
---------  -----------  ---------------  ------  -------  --------  -----------------------------------------  ----------------  ----------
        1  system user                   (NULL)  Sleep    13911475  wsrep aborter idle                         (NULL)                 0.000
        7  system user                   (NULL)  Sleep         853  applied write set 54959398                 (NULL)                 0.000
       16  system user                   (NULL)  Sleep         973  Delete_rows_log_event::find_row(54959396)  (NULL)                 0.000


3. 대량 처리는 하지 말라

하지 말라는 말은 아니고... 신중하게 처리 해야 합니다. 

실무에서 우리들은 락이 걸리는 쿼리들을  알게 모르게 의외로 많이 사용 합니다.

단지, 그걸 모르고 (혹은 알면서도) 큰 문제가 없으니 그냥 무시 하는 경우가 있습니다. 

그러나 Galera Cluster를 사용시에는 상당히 주의를 요합니다.


단적인 예로 

Insert into table( col, col.....) select 이런문들입니다. 

Target Table, Source Table 모두에 락을 걸게 됩니다.

헌데 select 대상 혹은 insert 대상  테이블에 트랜잭션이 상당히 많다고 하면... 역시 문제의 소지가 있습니다. 

INSERT ON DUPLICATE KEY UPDATE, cvs file 을 등록 하는 경우도 마찬가지 입니다. 


4. Lock이 걸리면 뾰족한 해결책이 없다. 

정말 락이 걸리면 풀리기를 기다리는 수외에는 뾰족한 대책이 없습니다.

결국 서버를 강제로 죽이고 다시 살리는게 속편할수 있습니다.


5. Galera Cluster DB를 이용하는 경우 DB 처리 로직은 매우 신중하게

근래에는 클라이언트에서 간단한 Query 문들은 사용하지만 대규모 트래픽이 있고, 이를 위해 Galera Cluster 를 이용한다면 SQL문은 가급적 관련분야에 경험이 있는 분들이 핸들링 하는게 맞습니다.

트랜잭션 처리 잘해줘야 합니다.

간단한 SQL문이라도 순간 잘못되면 Galera 이 놈은 Lock을 걸고 절대 풀어주질 않아요... 

*insert, update 등의 SQL문만 이라도 주의 해야 합니다. 


6. DB백업도 많은 고민이 필요 하다.

사실 Galera가 이미 백업을 하고 있는 상태라고도 볼 수 있지요...(모든 node가 fail만 나지 않는다면)

그럼에도 불구 하고... 대부분이 배치 백업을 받거나 합니다.

대부분이 백업 할때 

mysqldump -u ......  사용 합니다.

이 역시 Lock이 걸립니다.

실제 적용했던 경험은 잘 운영되던 Galera가 새벽만되면 Lock 이 걸리고 있었습니다. 근무시간 아침에는 락이 풀려 있었기에 몰랐던거지요... 새벽에 DB를 사용하는 서비스가  추가되었는데 새벽만되면 커넥션도 안되고... 데이터 등록시 락이 걸린다는 문의가 있었습니다. 그러나 아침이 되면 문제가 없어서 몇 날을 그냥 보내다가 알게된거지요...

서비스가 몇개월 전부터 활성화 되어 초기 보다 트래픽이 약 10배가 넘어 가면서 데이터 백업량이 급증하였는데 이 백업이 새벽에 돌아가면서 락이 걸렸던 거를 신규 서비스가 DB를 새벽에 사용하면서 알게된 것입니다. 

그래서 모든 배치 작업들을 데이터 한건 처리 할때마다 실시간으로 처리 하는 걸로 변경했습니다. 

어찌보면 트래픽이 폭주 하는 시간에  건건마다 처리 할 로직이 늘어나서 부하를 가중 시킬 것 같았지만 오히려 문제 없이 잘 돌아가더군요.


7. 구조적 설계에 좀더 집중하자.

Galera Cluster가 Master-Slave 방식이 아닌 모두 Master(Primary)형태로 만드는 장점이 있는데 오히려 데이터 변경은 한 노드에서만 하는 걸 권하는 글들을 많이 보게됩니다.

아이러니 하지만, 실제 적용을 위해서는 고민을 많이 해야 하는 부분입니다.

부하 분산을 어떻게 처리 할지 어떤 구조를 가져가야 할지... 등등

(이런 부분은 제가 전문이 아니라)


  

모든 문제는 Lock문제로 귀결됩니다. (제 경우에는)

Galera Cluster의 목적이 

-. 모든 노드에서 데이터 변경 가능 (Active-Active 방식의 다중 마스터 구성 – 모든 노드에서 읽기/쓰기가 가능)

-. 노드 장애 시에도 데이터 유실 없이 높은 가용성 달성

-. 노드 사이의 트랜잭션 지원(클러스트 내 모든 노드 간 데이터 일관성을 보장)

-. 클러스터 내 노드 자동 컨트롤 (노드 장애 시 자동으로 해당 노드 제거, 추가 가능)

이러한 목적을 달성하기 위해서는 node간 데이터 일괄성을 제공 하기 위해서는 락이 필수 입니다.

그런데 정작 이 락 때문에 Galera에 대한 신로도가 떨어지기도 합니다.

Galera Lock 걸리면 강제로 풀수 있는 방법이 별로 없습니다. 역설적으로 말하면 이 락을 강제로 풀수 있는 옵션을 제공학고 이 것을 강제로 이용하는 순간 데이터의 일관성 보장은 없는 것이지요.




아 참고로 Cluster 구성의 node들간에는 네트웍크 트래픽이 많은 편이니 이런 부분들도 고려 하시면 좋겠네요. 

Process monitoring 하실때 각 Process의 State 값을 유심히 보면 query end(맞나?) 등의 잘 못보던 state들이 나올때 유의해서 봐주세요.




       Id  User         Host             db      Command      Time  State                                      Info              Progress  
---------  -----------  ---------------  ------  -------  --------  -----------------------------------------  ----------------  ----------
        1  system user                   (NULL)  Sleep    13911475  wsrep aborter idle                         (NULL)                 0.000
        2  system user                   (NULL)  Sleep        1213  committed 54959393                         (NULL)                 0.000
        3  system user                   (NULL)  Sleep        2893  committed 54959380                         (NULL)                 0.000
        4  system user                   (NULL)  Sleep        1333  committed 54959391                         (NULL)                 0.000
        5  system user                   (NULL)  Sleep        1093  committed 54959394                         (NULL)                 0.000
        6  system user                   (NULL)  Sleep        1333  committed 54959390                         (NULL)                 0.000
        7  system user                   (NULL)  Sleep         853  applied write set 54959398                 (NULL)                 0.000
        8  system user                   (NULL)  Sleep        1213  committed 54959392                         (NULL)                 0.000
        9  system user                   (NULL)  Sleep        1453  committed 54959387                         (NULL)                 0.000
       10  system user                   (NULL)  Sleep        1572  committed 54959385                         (NULL)                 0.000
       11  system user                   (NULL)  Sleep        2653  committed 54959383                         (NULL)                 0.000
       12  system user                   (NULL)  Sleep        3013  committed 54959377                         (NULL)                 0.000
       13  system user                   (NULL)  Sleep        1093  committed 54959395                         (NULL)                 0.000
       14  system user                   (NULL)  Sleep        1453  committed 54959388                         (NULL)                 0.000
       15  system user                   (NULL)  Sleep        1572  committed 54959386                         (NULL)                 0.000
       16  system user                   (NULL)  Sleep         973  Delete_rows_log_event::find_row(54959396)  (NULL)                 0.000
       17  system user                   (NULL)  Sleep        1453  committed 54959389                         (NULL)                 0.000
107360939  root         127.0.0.1:41560  (NULL)  Query           0  init                                       SHOW PROCESSLIST       0.000
107360942  root         127.0.0.1:41562  (NULL)  Sleep           5                                             (NULL)                 0.000







반응형

댓글