{"id":"IL-0430","org":"Hatena","date":"2018-09-26","docs":[],"title":{"en":"Mackerel's Redis stopped answering during a replication setup, keepalived failed over by mistake, and Mackerel degraded","ko":"Redis 장애 조치 뒤 Mackerel 전체가 느려지고 생존 여부 감시가 4시간 넘게 멈췄다"},"domain":["database"],"impact":{"scope":"The whole Mackerel service malfunctioned and alive monitoring stopped from 10:51 to 15:20 JST","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Hatena did not find why recovery took so long, but expects that keeping failover from reacting to short load spikes and giving the application more performance headroom would prevent an outage this long. It also aims to keep problems contained to a small part of the service when a failure does happen.","ko":"Hatena 는 상세한 원인을 밝히지 못했다. 그래도 장애 조치 오작동을 막고, 애플리케이션 성능에 여유를 더 두고, Redis 에 저장하는 데이터를 줄이고, 부적절한 요청을 빨리 찾아 막으면 이번처럼 긴 장애는 막을 수 있다고 보았다. 장애가 나더라도 영향이 좁은 범위에 그치도록 하는 작업을 이어 가겠다고 했다."},"related":[],"sources":[{"url":"https://mackerel.io/ja/blog/entry/announcement/20181015","kind":"blog","archived":"https://web.archive.org/web/20250514052121/https://mackerel.io/ja/blog/entry/announcement/20181015"}],"summary":{"en":"Mackerel keeps monitoring data in Redis, and Redis memory use had been rising. On 26 September 2018 operators started building a Redis replica to scale Redis up. The replication setup took long enough that Redis did not answer for a time, keepalived, the clustering software used for Redis, judged the node to have failed, and an unintended failover followed at 10:51 JST. The application servers then could not reach Redis. Operators switched to the correct Redis at 10:55 and the application briefly recovered, but latency and timeouts came back, and rolling restarts of the application servers did not help.\n\nBetween 11:00 and 14:50 the team blocked requests from organizations that were posting inappropriate metrics, adjusted the application server timeouts, temporarily added capacity to Diamond (the TSDB), raised the number of Kinesis shards and Redis Cluster shards, and scaled out the API application servers. Mackerel was then put in maintenance mode, checked internally, and outside requests were let back in step by step. Recovery was declared at 15:20.\n\nHatena states that the failure started with the unintended failover, but it could not determine why recovery took so long and has stopped investigating. The review put forward one hypothesis: under a particular access pattern that continued for a while, the Scala application slowed down from waiting on synchronisation or lock contention in a thread pool or connection pool. An attempt to reproduce the situation in an isolated environment did not reproduce it.","ko":"2018년 9월 26일 Mackerel 팀은 감시 데이터를 담는 Redis 의 메모리 사용량이 늘어나는 것을 보고 Redis 를 스케일업하기로 했고, 그 준비로 복제를 구성했다. 복제 구성이 오래 걸리면서 Redis 가 응답하지 않는 시간이 생겼고, 클러스터링 소프트웨어인 keepalived 가 이를 노드 고장으로 보고 10시 51분에 장애 조치를 일으켰다. 애플리케이션 서버는 Redis 에 접속하지 못해 올바른 응답을 내지 못했고, Mackerel 시스템 전체가 불안정해지며 생존 여부 감시가 멈췄다.\n\n10시 55분 팀이 Redis 를 올바른 쪽으로 다시 전환해 애플리케이션이 돌아온 것을 잠시 확인했다. 하지만 장애 전부터 있던 네트워크 불안정과 Redis 메모리 증가가 겹치면서 애플리케이션 서버의 지연 시간이 나빠지고 타임아웃이 이어졌다. 애플리케이션 서버를 차례로 재시작해도 나아지지 않았고, 이것이 장애가 길어진 이유였다. 11시부터 14시 50분까지 팀은 부적절한 메트릭을 보내는 Mackerel 조직의 요청을 막고 타임아웃 간격을 조정했다. 또 TSDB 인 Diamond, Kinesis 샤드 수, Redis Cluster 샤드 수, API 애플리케이션 서버를 늘렸다. 그 뒤 잠시 점검 모드로 바꿔 사내에서 확인하고 외부 요청을 조금씩 되돌렸고, 15시 20분 복구를 선언했다.\n\n장애의 발단은 Redis 작업에 따른 의도하지 않은 장애 조치였다. 복구가 길어진 원인은 정확히 밝혀지지 않았다. 회고에서는 특정 접근 패턴이 이어질 때 Scala 애플리케이션에서 스레드 풀이나 커넥션 풀의 동기화 대기 또는 락 경합 때문에 지연 시간이 나빠진다는 가설이 나왔다. 격리된 환경에서 장애 상황을 재현하려 했지만 재현되지 않았고, 원인 조사는 중단했다."},"trigger":{"en":"Redis memory use had been growing, so operators set up replication in order to scale Redis up. Building the replication took a long time and Redis stopped answering for a while, and keepalived treated this as a node failure and started a failover nobody intended.","ko":"감시 데이터를 담는 Redis 를 스케일업하려고 복제를 구성하는 작업을 했다. 복제 구성에 시간이 걸리는 동안 Redis 가 응답하지 않았고, keepalived 가 이를 노드 고장으로 판단해 의도하지 않은 장애 조치를 일으켰다."},"severity":"unknown","symptoms":["monitoring-down","high-latency","intermittent-timeouts"],"timeline":{"detected_after":null,"resolved_after":"4h 29m"},"date_kind":"incident","detection":null,"components":["cache","database-replication","failover-manager"],"root_cause":"config-change","remediation":[{"text":{"en":"Switched back to the correct Redis and briefly saw the application return","ko":"Redis 를 올바른 쪽으로 다시 전환하고 애플리케이션이 돌아온 것을 잠시 확인했다."}},{"text":{"en":"Restarted the application servers one after another, which did not improve the symptoms","ko":"애플리케이션 서버를 차례로 재시작했지만 증상은 나아지지 않았다."}},{"text":{"en":"Detected the organizations posting inappropriate metrics and blocked their requests","ko":"부적절한 메트릭을 보내는 Mackerel 조직을 찾아 그 요청을 차단했다."}},{"text":{"en":"Adjusted the timeout interval of the application servers","ko":"애플리케이션 서버의 타임아웃 간격을 조정했다."}},{"text":{"en":"Temporarily added capacity to Diamond, the TSDB","ko":"TSDB 인 Diamond 를 임시로 증설했다."}},{"text":{"en":"Increased the number of Kinesis shards and Redis Cluster shards","ko":"Kinesis 샤드 수와 Redis Cluster 샤드 수를 늘렸다."}},{"text":{"en":"Scaled out the API application servers","ko":"API 용 애플리케이션 서버를 스케일아웃했다."}},{"text":{"en":"Put Mackerel in maintenance mode, checked it internally and let outside requests back gradually","ko":"잠시 점검 모드로 바꿔 사내에서 확인한 뒤 외부 요청을 조금씩 되돌렸다."}}],"action_items":[{"text":{"en":"Raise the number of keepalived health checks for Redis so a brief load increase does not trigger a failover","ko":"짧은 부하 증가로는 장애 조치가 일어나지 않도록 Redis 의 keepalived 헬스 체크 횟수를 늘렸다."}},{"text":{"en":"Scale Redis up","ko":"애플리케이션 성능에 여유를 두려고 Redis 를 스케일업했다."}},{"text":{"en":"Add more application servers","ko":"애플리케이션 서버 대수를 늘렸다."}},{"text":{"en":"Change the application to store only the monitoring data it needs in Redis, reducing Redis memory use","ko":"애플리케이션을 고쳐 필요한 감시 데이터만 Redis 에 저장하게 해 Redis 메모리 사용량을 줄였다."}},{"text":{"en":"Build a way to detect inappropriate API requests quickly and show them on a dashboard","ko":"부적절한 API 요청을 빨리 찾아내 대시보드에서 볼 수 있는 체계를 만들었다."}},{"text":{"en":"Build a function to block organizations making inappropriate requests quickly","ko":"부적절한 요청을 보내는 조직을 빨리 차단하는 기능을 만들었다."}},{"text":{"en":"Keep improving the accuracy of detecting inappropriate requests and consider adding features such as an API limit","ko":"부적절한 요청을 더 정확히 찾아내고 API Limit 같은 기능을 더하는 것을 검토한다."}},{"text":{"en":"Strengthen monitoring of the application servers' internal processing so problems are handled before they become outages","ko":"애플리케이션 서버의 내부 처리 모니터링을 강화해 장애가 나기 전에 대응할 수 있게 한다."}}],"contributing":["automation-amplified","overlapping-failures"],"recurrence_of":null,"symptoms_text":{"en":"On 26 September 2018 at 10:51 JST the whole Mackerel monitoring service stopped working properly and its alive monitoring stopped. The application servers could not connect to Redis, which stores Mackerel's monitoring data, and could not return correct responses.\n\nAt 10:55 operators switched the application back to the correct Redis and the application seemed to come back. It did not stay stable: application server latency got worse and requests timed out. Restarting the application servers one after another did not improve the symptoms.\n\nThe failure went on until 15:20 JST. Recovery was declared when application server responses were stable, the metrics that mackerel-agent resent had settled and the delay in writing data to the time series database (TSDB) was gone. A network problem and growing Redis memory use had already been present before the incident, and Hatena names both among the combined factors that kept the application unstable.","ko":"10시 51분 Redis 에 장애 조치가 일어난 뒤 애플리케이션 서버가 Redis 에 접속하지 못해 Mackerel 이 요청에 제대로 응답하지 못했다. Mackerel 시스템 전체가 불안정해졌고 생존 여부 감시가 멈췄다.\n\nRedis 를 올바른 쪽으로 다시 전환하자 애플리케이션이 잠시 되살아난 것처럼 보였다. 그러나 동작이 안정되지 않았고, 애플리케이션 서버의 지연 시간이 나빠지고 타임아웃이 났다.\n\n장애 전부터 네트워크 상태가 좋지 않았고 Redis 메모리 사용량도 늘고 있었다. 팀은 애플리케이션 서버를 차례로 재시작했지만 증상은 나아지지 않았다.\n\n복구 단계에서는 mackerel-agent 가 메트릭을 다시 보내고 있었고, TSDB 에 메트릭이 늦게 반영되었다. 팀은 애플리케이션 서버의 응답이 안정되고 이 재전송이 잦아들고 반영 지연이 풀린 것을 보고 15시 20분에 복구를 선언했다."},"updated_at":"2026-11-14T12:34:08.000133Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0430","org_slug":"hatena"}