{"id":"IL-0319","org":"Oregon State University Open Source Lab","date":"2015-07-30","docs":[],"title":{"en":"Dropping databases on the MySQL replica mysql2 also dropped them on mysql1, as the pair actually ran master-master","ko":"mysql2 를 다시 적재하려고 데이터베이스를 지우는 동안 mysql1 의 데이터베이스도 함께 지워졌다"},"domain":["database"],"impact":{"scope":"Databases on the mysql1 and mysql2 MySQL cluster were dropped and unavailable until restored; some data written between July 15th and 17th was lost","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"The lab had stretched its resources to host as many projects as possible, and that came with tradeoffs such as heavily compressed backups to save disk and less redundancy than wanted; the heavy compression made this restore CPU-bound. The lab concluded that it needs to change how it plans, monitors and manages resources, and that the length of the outage and the lack of progress reports were not acceptable.","ko":"Open Source Lab 은 이번 장애에서 MySQL 클러스터를 운영하는 방식과 연구소 전체가 자원을 계획하고 관리하는 방식 모두에서 교훈을 얻었다고 적었다. 디스크 공간을 아끼려고 백업을 강하게 압축한 선택은 전체 복원이 드물었던 그동안에는 괜찮았지만 이번 복원을 크게 늦췄다. 더 많은 프로젝트를 받으려고 자원을 빠듯하게 나눠 써 왔고, 그 대가로 백업을 압축하고 바라던 것보다 이중화를 덜 갖췄다. 장애가 길었던 것과 진행 상황을 알리지 못한 것은 받아들일 수 없는 일이었다고 밝혔다."},"related":[],"sources":[{"url":"https://osuosl.org/blog/mysql1-vip-outage-post-mortem/","kind":"blog","archived":"https://web.archive.org/web/20260214014432/https://osuosl.org/blog/mysql1-vip-outage-post-mortem/"}],"summary":{"en":"The OSU Open Source Lab ran two MySQL 5.5 servers, mysql1 and mysql2. From July 15th, replication on mysql2 kept failing on a couple of session tables, and after several restarts the team decided to reload mysql2 from scratch. Documentation and staff knowledge described the pair as master-slave, but it was configured as master-master. When the reload began on July 30th, the team stopped slave replication on mysql2 and dropped its databases one by one; mysql2 still replicated its statements to mysql1, so the drops removed the databases on mysql1 too. After a few minutes the team noticed mysql1 losing databases, stopped the script and began restoring.\n\nThe restore was slow for three reasons. To save disk space, the lab's main resource limit, backups were taken with mysql-zrm under heavy compression, which made restores CPU-bound. A couple of databases failed to restore on indexing and foreign keys, and each failure forced the team to parse the roughly 200GB backup file again to restore that database separately and then extract the rest. And the backups were taken from mysql2, which had been out of date with mysql1 since the replication failures. Binary logs from the 17th through the 30th let most data be recovered, but some data written between the 15th and the 17th was lost. The lab also said the outage lasted too long and that it did not give enough progress reports during it.","ko":"Oregon State University Open Source Lab 의 mysql1 과 mysql2 는 MySQL 5.5 를 쓰는 서버 한 쌍이다. 7월 15일과 16일 mysql2 의 세션 테이블에서 복제 오류가 이어졌고, 팀은 7월 20일 주간에 mysql2 를 통째로 다시 적재하고 행 기반 복제 같은 다른 복제 방식을 살펴보기로 했다. 문서와 팀 안의 지식으로는 두 서버가 마스터-슬레이브 복제였지만 실제로는 마스터-마스터 복제로 설정돼 있었다.\n\n7월 30일 오후 4시 PDT 에 팀은 mysql2 의 슬레이브 복제를 멈추고 데이터베이스를 하나 지울 때마다 잠깐씩 쉬면서 지웠다. mysql2 는 여전히 mysql1 로 명령을 보내고 있었으므로 두 서버 모두에서 데이터베이스가 지워졌다. 스크립트가 중간중간 쉬었기 때문에 몇 분 뒤 mysql1 에서도 데이터베이스가 지워지는 것을 알아챘다. 팀은 스크립트를 멈추고 곧바로 복원을 시작했다.\n\n복원은 세 가지 이유로 예상보다 훨씬 느리고 손이 많이 갔다. 자원 가운데 디스크 공간이 가장 큰 병목이었기 때문에 mysql-zrm 으로 강하게 압축해 백업해 왔다. 그래서 복원할 때 IO 가 아니라 CPU 가 병목이 됐다. 인덱스와 외래 키 문제로 복원이 실패하는 데이터베이스가 몇 개 있었다. 그때마다 약 200GB 백업 파일 전체를 훑어 문제가 난 데이터베이스와 아직 복원하지 못한 나머지를 따로 꺼내야 했다. 백업은 mysql2 에서 떴는데, mysql2 는 처음 동기화가 실패한 탓에 mysql1 보다 뒤처져 있었다. 17일부터 30일까지의 바이너리 로그가 남아 있어 대부분의 데이터는 되살렸지만 15일과 17일 사이의 데이터 일부는 잃었다. 시험용 데이터베이스와 100GB 넘게 불어난 데이터베이스 여러 개도 복원을 크게 늦췄다."},"trigger":{"en":"On July 30th at 4:00PM PDT the team stopped slave replication on mysql2 and began dropping its databases one at a time to reload it and fix replication errors.","ko":"7월 30일 오후 4시 PDT 에 팀은 복제 오류를 고치려고 mysql2 를 다시 적재하기로 했다. 슬레이브 복제를 멈춘 뒤 mysql2 의 데이터베이스를 하나 지울 때마다 잠깐씩 쉬면서 지웠다."},"severity":"unknown","symptoms":["data-loss","service-unavailable","replication-lag"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"incident","detection":{"en":"The team watching the reload noticed after a few minutes that mysql1 was also dropping databases; the delays between drops in the script gave them that time.","ko":"데이터베이스를 지우는 스크립트가 하나를 지울 때마다 짧게 쉬었기 때문에, 시작하고 몇 분 뒤 mysql1 에서도 데이터베이스가 지워지고 있는 것을 알아챘다."},"components":["database","database-replication","database-backup"],"root_cause":"human-operation","remediation":[{"text":{"en":"Stopped the script that was dropping databases","ko":"mysql1 에서도 데이터베이스가 지워지는 것을 보고 스크립트를 멈췄다."}},{"text":{"en":"Restored the databases from the mysql-zrm backups","ko":"곧바로 지워진 데이터베이스의 복원을 시작했다."}},{"text":{"en":"Pulled each database that failed to restore out of the 200GB backup file and restored it separately","ko":"인덱스와 외래 키 문제로 복원이 실패한 데이터베이스는 약 200GB 백업 파일에서 따로 꺼내 복원했고, 아직 복원하지 못한 나머지 데이터베이스도 다시 꺼내 복원했다."}},{"text":{"en":"Recovered most data with the binary logs from the 17th through the 30th","ko":"백업은 mysql1 보다 뒤처진 mysql2 에서 뜬 것이어서, 17일부터 30일까지의 바이너리 로그로 대부분의 데이터를 되살렸다. 15일과 17일 사이의 데이터 일부는 되살리지 못했다."}}],"action_items":[{"text":{"en":"Evaluate better replication strategies, including row-based replication","ko":"처음 문제였던 복제 오류를 줄이려고 행 기반 복제를 포함해 더 나은 복제 방식을 검토한다."}},{"text":{"en":"Store binlogs as a backup on a separate server","ko":"바이너리 로그를 별도 서버에 백업으로 보관한다."}},{"text":{"en":"Take backups with Percona XtraBackup for much faster full restores","ko":"전체 복원이 훨씬 빨라지도록 Percona XtraBackup 으로 백업한다."}},{"text":{"en":"Use mydumper instead of mysql-zrm for faster logical backups","ko":"논리 백업 속도를 높이려고 mysql-zrm 대신 mydumper 를 쓴다."}},{"text":{"en":"Improve documentation and training for complex systems","ko":"복잡한 시스템의 문서와 교육을 손본다."}},{"text":{"en":"Test full restores regularly on a spare server as part of the backup process","ko":"백업 절차의 하나로 예비 서버에서 전체 복원을 정기적으로 시험한다."}},{"text":{"en":"Gather more accurate time estimates for the restore process","ko":"복원에 걸리는 예상 시간을 더 정확하게 잡는다."}},{"text":{"en":"Audit the hosted databases regularly, since test and very large databases delayed the restore","ko":"호스팅하는 데이터베이스를 정기적으로 점검한다. 시험용 데이터베이스와 100GB 넘게 불어난 데이터베이스 여러 개가 이번 복원을 크게 늦췄다."}},{"text":{"en":"Migrate to a bigger, more powerful MySQL cluster","ko":"더 크고 성능이 좋은 MySQL 클러스터로 옮긴다. 이 이전은 장애 전부터 계획돼 있었다."}},{"text":{"en":"Set a policy and tools to keep the community informed of outages, maintenance and resource use, with dashboards","ko":"장애와 유지보수, 자원 사용량과 경고 신호를 대시보드로 커뮤니티에 더 잘 알리는 정책과 수단을 만든다."}},{"text":{"en":"Define and monitor capacity limits for core services","ko":"핵심 서비스의 용량 한계를 정하고 감시한다."}},{"text":{"en":"Implement redundancy and restore practices for core services, including staff drills","ko":"핵심 서비스에 이중화와 복원 절차를 갖추고 직원 훈련을 한다."}},{"text":{"en":"Migrate more core services to Chef","ko":"핵심 서비스를 더 많이 Chef 로 옮긴다."}},{"text":{"en":"Review documentation, policies and performance metrics periodically","ko":"문서, 정책, 성능 지표를 주기적으로 검토한다."}},{"text":{"en":"Find better ways to draw on community expertise","ko":"커뮤니티의 전문 지식으로 연구소의 역량을 보완할 더 나은 방법을 찾는다."}},{"text":{"en":"Raise funds to replace the oldest infrastructure and reduce technical debt","ko":"가장 낡은 인프라를 교체하고 가장 심한 기술 부채를 해소할 기금을 모은다."}}],"contributing":["assumption-unverified","backup-unverified"],"recurrence_of":null,"symptoms_text":{"en":"On July 30th, a few minutes after the OSU Open Source Lab started reloading the MySQL server mysql2 to fix its replication errors, the team saw that databases were being dropped on mysql1 as well. The script was stopped, and the MySQL service behind mysql1-vip stayed down through a long restore.\n\nThe reload followed two weeks of replication trouble on mysql2. On July 15th replication errors on a couple of session tables paused replication, a large number of statements had to be skipped, and replication was restarted. On July 16th the same tables failed again in far greater number, a ticket was opened, and replication was restarted several times. In the week of the 20th the team decided to reload mysql2 completely and to look at other replication methods, mainly row-based replication.\n\nFor the reload, replication on mysql2 was stopped on purpose at 4:00PM PDT and a script dropped the databases on mysql2 one at a time with a short delay between drops. Documentation and what the staff knew said mysql1 and mysql2 were a master-slave pair, but both MySQL 5.5 servers were configured for master-master replication. Stopping slave replication on mysql2 did not stop mysql2 from sending its statements to mysql1, so each drop ran on both servers. The delays in the script are what let the team notice after a few minutes.\n\nThe restore then took far longer and more manual work than expected. Backups made with mysql-zrm were heavily compressed, so restoring was limited by CPU rather than disk IO. A couple of databases failed to restore because of indexing and foreign keys, and each failure meant parsing the whole backup file of around 200GB to pull out the bad database and then the databases not yet restored. Several test databases and databases that had grown past 100GB slowed the restore further.","ko":"복제 오류를 고치려고 mysql2 의 데이터베이스를 하나씩 지우던 중, 몇 분 뒤 mysql1 에서도 데이터베이스가 지워지고 있는 것을 알아챘다. 지워진 데이터베이스들은 복원될 때까지 쓸 수 없었다.\n\n그 전부터 mysql2 의 복제가 흔들리고 있었다. 7월 15일 세션 테이블 두어 개에서 복제 문제가 나 복제가 멈췄고, 많은 구문을 건너뛴 뒤에야 복제를 다시 시작했다. 7월 16일에는 같은 테이블에서 훨씬 많은 문제가 났고 복제를 여러 번 다시 시작했다. 결국 7월 20일 주간에 mysql2 를 통째로 다시 적재하기로 했다.\n\n문서와 팀 안에서 전해지던 지식으로는 두 서버가 마스터-슬레이브 복제였지만 실제 설정은 마스터-마스터 복제였다. 그래서 mysql2 의 슬레이브 복제를 일부러 멈췄는데도 mysql2 는 여전히 mysql1 로 명령을 보내고 있었다. 이 때문에 mysql2 에서 지운 데이터베이스가 mysql1 에서도 지워졌다.\n\n복원은 예상보다 훨씬 느리고 손이 많이 갔다. mysql-zrm 으로 강하게 압축한 백업이라 복원할 때 CPU 가 병목이 됐다. 인덱스와 외래 키 문제로 복원이 실패하는 데이터베이스가 나올 때마다 약 200GB 짜리 백업 파일 전체를 다시 훑어야 했다. 백업은 mysql1 보다 뒤처진 mysql2 에서 뜨고 있었기 때문에 15일과 17일 사이의 데이터 일부는 되살리지 못했다."},"updated_at":"2026-11-14T12:33:57.272918Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0319","org_slug":"oregon-state-university-open-source-lab"}