안녕하세요! 그로스로그 입니다!😊 🌱
장애마다 재로그인이 나던 세션 문제, 그리고 모서리 값 하나를 놓칠 뻔한 순간. 그로스로그의 가장 첫 성장일지 두 편입니다.
성장일지는 멤버들이 2주에 한 번씩 자신의 성장을 기록하는 활동이에요. KNOU에서 컴퓨터과학을 공부하며 각자의 자리에서 일하고 배우는 분들이라, 매 회차 올라오는 글이 정말 다양합니다. 운영진이 그 글들을 모두 읽고, 그중 특히 마음에 남은 글을 함께 골라 큐레이션하고 있어요.
그동안 노션에만 쌓아두었던 이 기록들을, 이제 블로그에서도 하나씩 소개하려고 합니다. 시작은 2024년 5월, 1기 1회차예요. 이때는 회원도 지금보다 훨씬 적었고 운영 방식도 자리를 잡기 전이었는데, 첫 회차부터 이런 글이 올라왔다는 게 지금 다시 읽어도 놀랍습니다.
01
🔧 1주차 로그 — Redis Sentinel 세션 클러스터링
이태형 님
로드밸런서를 뒀는데도 Sticky Session 때문에 트래픽이 한쪽 서버로 쏠리던 상황에서 출발합니다. 더 큰 문제는 그 서버에 장애가 나면 접속 중이던 사용자들이 전부 다시 로그인해야 했다는 점이었어요.
해법은 세션을 각 서버의 메모리가 아니라 외부 Redis에 두는 것입니다. 그러면 어느 서버가 요청을 받든 같은 세션을 읽을 수 있으니 분산이 제대로 동작하죠. 여기에 Sentinel까지 붙여 Redis 자체가 새로운 단일 장애점이 되지 않도록 이중화했습니다.
설정 파일 옵션을 그대로 옮겨 적을 수 있을 만큼 구체적으로 남겨두어서, 같은 구성을 해야 하는 사람이 바로 따라 할 수 있습니다.
성장일지 1회차에, 그것도 그로스로그의 가장 첫 기록으로 실무 장애 대응기가 올라왔습니다.
문제 상황은 이렇습니다. 서버를 여러 대 두고 로드밸런서로 트래픽을 나눴는데, 정작 사용자는 한 서버에만 계속 붙었습니다. Sticky Session 때문이었어요. 그러다 그 서버에 문제가 생기면 거기 붙어 있던 사용자들이 한꺼번에 로그아웃됐습니다. 서버를 늘린 이유가 무색해지는 상황이죠.
해법으로 택한 것이 Redis Sentinel을 이용한 세션 클러스터링입니다. 세션을 각 서버의 메모리가 아니라 외부 Redis에 두면, 어느 서버가 요청을 받든 같은 세션을 읽을 수 있습니다. Sentinel까지 붙인 이유는 Redis 자체가 새로운 단일 장애점이 되지 않게 하기 위해서고요.
조금 더 들어가 보면
세션은 "이 사용자가 로그인한 상태다"라는 사실을 서버가 기억해두는 메모입니다. 문제는 그 메모를 어디에 두느냐예요.
가장 쉬운 방법은 서버 자기 메모리에 두는 겁니다. 서버가 한 대일 땐 아무 문제가 없어요. 그런데 두 대가 되는 순간 곤란해집니다. 1번 서버에 로그인했는데 다음 요청이 2번 서버로 가면, 2번 서버는 그 사람을 모르거든요.
Sticky Session은 이 문제를 "같은 사람은 계속 같은 서버로 보내자"로 우회한 방식입니다. 동작은 하지만 대가가 있어요. 트래픽이 고르게 안 나뉘고, 무엇보다 그 서버가 죽으면 거기 있던 세션이 통째로 사라집니다. 글에서 겪은 재로그인 사태가 정확히 이겁니다.
그래서 나온 게 세션을 바깥에 따로 보관하는 방식입니다. 서버들은 세션을 기억하지 않고, 필요할 때마다 공용 저장소에 물어봅니다. 이러면 서버는 언제든 늘리고 줄이고 죽여도 됩니다. 요즘 클라우드 환경에서 서버를 소모품처럼 다루는 게 가능한 이유가 여기 있어요.
Redis를 쓰는 건 세션이 작고, 자주 읽히고, 빨라야 하기 때문입니다. 그런데 여기서 새 걱정이 생기죠. 세션을 전부 Redis에 몰아뒀는데 Redis가 죽으면요? 그럼 서버가 몇 대든 전원 로그아웃입니다. 장애 지점을 옮겨놓기만 한 셈이에요.
Sentinel이 그 답입니다. Redis를 감시하다가 마스터가 죽으면 복제본 중 하나를 새 마스터로 승격시키고, 애플리케이션에게 "이제 여기로 접속해"라고 알려줍니다. 사람이 새벽에 깨서 손으로 바꿔줄 필요가 없어지는 거죠.
정리하면 이 글은 "분산을 흉내내던 상태에서 진짜 분산으로 넘어가는" 과정을 담고 있습니다. 세션을 밖으로 빼고, 그 밖이 또 무너지지 않게 이중화하고. 규모가 커지는 서비스가 반드시 한 번은 지나는 길입니다.
📝 원문에서는 이렇게 설정합니다
글에서 가장 실용적인 부분이 redis.conf 수정 내역입니다. 복제본(replica) 서버에 넣는 설정을 보면 구조가 한눈에 들어옵니다.
sudo vi /etc/redis/redis.conf bind 0.0.0.0 ::1 logfile "/var/log/redis/redis-server.log" databases 2 requirepass "password" masterauth "password" maxmemory 256mb replicaof 192.168.60.32 6379
마지막 줄 replicaof가 "나는 저 주소의 복제본이다"를 선언하는 부분입니다. requirepass는 이 서버에 접속할 때 쓸 비밀번호고, masterauth는 반대로 마스터에 붙을 때 쓸 비밀번호예요. 둘을 헷갈리면 복제가 조용히 안 됩니다.
maxmemory를 256MB로 잡아둔 것도 눈여겨볼 만합니다. 세션은 개당 크기가 작아서 이 정도로도 상당수를 담을 수 있고, 한도를 정해두면 Redis가 서버 메모리를 다 먹는 사고를 막을 수 있습니다.
큐레이터 노트
"왜 필요한가"에서 시작해 "어떻게 구성하는가"로 내려가는 순서가 교과서적입니다. 많은 기술 글이 설정값부터 나열하다 독자를 잃는데, 이 글은 Sticky Session의 한계라는 구체적인 불편을 먼저 보여주고 시작해요. 그래서 Redis Sentinel이라는 선택이 자연스럽게 납득됩니다.
그리고 설정 파일 옵션까지 남겨둔 점이 좋았습니다. 개념만 설명하고 끝나는 글은 읽을 땐 이해가 되는데 막상 따라 하려면 막히거든요. 어떤 값을 어디에 넣어야 하는지까지 적어두면, 그 글은 읽는 글에서 쓰는 글로 바뀝니다.
무엇보다 이게 성장일지 1회차라는 걸 기억해주세요. 아직 아무도 어떤 글을 써야 하는지 감이 없던 때에, 실무에서 직접 겪은 장애를 재현 가능한 형태로 정리해 올려주셨습니다. 이후 회차들의 기준선이 된 글이에요.
02
🎨 디자인시스템 유지보수 생산성을 어떻게 올릴까 — 시각적 회귀 테스트
변기원 님
styled-components에서 styleX로 스타일 라이브러리를 옮기던 중,
borderRadius 값이 바뀐 걸 하마터면 놓칠 뻔한 아찔한 순간에서 시작합니다.디자인 시스템은 컴포넌트 하나를 고치면 그 영향이 어디까지 퍼지는지 눈으로 다 확인할 수가 없습니다. 테스트 코드는 로직은 잡아주지만 "모서리가 4px에서 8px로 바뀐 것"은 못 잡죠.
그래서 변경 전후 화면을 이미지로 찍어 비교하는 시각적 회귀 테스트를 도입합니다. Chromatic과 BackstopJS를 직접 비교해 각각의 장단을 따진 뒤 선택했고, 최종적으로 UI 차이를 2초 만에 잡아내는 세팅까지 완성했습니다.
이 글의 출발점은 아찔한 순간입니다. styleX로 마이그레이션하던 중, borderRadius 변경을 하마터면 놓칠 뻔했다는 거예요.
디자인 시스템을 손대본 분이라면 이 공포를 아실 겁니다. 컴포넌트 하나를 고쳤는데 그게 어디까지 영향을 주는지 눈으로 다 확인할 수가 없어요. 버튼 컴포넌트를 수정했다면 그 버튼을 쓰는 화면이 수십 개일 텐데, 그걸 전부 열어보고 눈으로 대조할 수는 없으니까요.
조금 더 들어가 보면
우리가 흔히 쓰는 테스트는 "이 함수에 2를 넣으면 4가 나오는가"를 확인합니다. 값이 맞는지 보는 거죠. 그런데 UI에는 값으로 표현되지 않는 영역이 있습니다.
버튼의 모서리가 4px에서 8px로 바뀌었다고 해봅시다. 테스트 코드 입장에서는 아무 문제가 없습니다. 버튼은 여전히 렌더링되고, 클릭하면 여전히 동작하고, 텍스트도 그대로예요. 깨진 건 오직 "보이는 모습"뿐입니다. 그래서 단위 테스트도, 통합 테스트도 이걸 못 잡습니다.
시각적 회귀 테스트(Visual Regression Test)는 접근을 완전히 바꿉니다. 코드를 검사하는 대신 화면을 사진으로 찍어 이전 사진과 픽셀 단위로 비교해요. 사람이 눈으로 하던 일을 기계에게 넘기는 겁니다.
글에서 비교한 두 도구의 성격이 다릅니다.
Chromatic은 Storybook을 만든 팀이 내놓은 클라우드 서비스입니다. 스냅샷을 자기들 서버에 저장하고 관리해주니 세팅이 편하고, 팀원들이 웹에서 변경점을 보고 승인하는 흐름이 자연스러워요. 대신 외부 서비스에 의존하고 비용이 듭니다.
BackstopJS는 내 컴퓨터나 CI에서 직접 돌리는 오픈소스입니다. 공짜고 통제권이 온전히 내 것이지만, 스냅샷 파일을 어디에 두고 어떻게 관리할지 직접 정해야 해요.
여기서 실무의 진짜 어려움이 나옵니다. 시각적 회귀 테스트는 "기준이 되는 사진(baseline)"을 계속 관리해야 합니다. 의도한 디자인 변경이 있을 때마다 "이건 버그가 아니라 의도된 변경이야"라고 승인해서 기준을 갱신해줘야 하죠. 이 과정이 번거로우면 팀은 곧 테스트를 무시하기 시작합니다. 도구 선택이 단순 취향 문제가 아닌 이유예요.
글이 2초라는 숫자를 남긴 것도 그래서 의미가 있습니다. 확인에 걸리는 시간이 짧아야 사람들이 실제로 그 장치를 계속 쓰거든요.
큐레이터 노트
이 글을 고른 이유는 문제를 발견한 지점이 정직해서입니다. "시각적 회귀 테스트가 좋다더라"에서 시작하지 않고, "내가 놓칠 뻔했다"에서 시작해요. 그 차이가 글의 설득력을 완전히 다르게 만듭니다.
도구 두 개를 비교한 것도 좋았습니다. 하나만 소개하면 "이거 쓰세요"가 되지만, 둘을 놓고 고른 이유를 적으면 읽는 사람이 자기 상황에 맞게 판단할 수 있게 되니까요. 팀 규모도 예산도 다 다른데, 결론만 던지는 글은 그 차이를 감당하지 못합니다.
그리고 "2초"라는 숫자를 남긴 것 — 이런 구체성이 나중에 이 글을 찾아 읽을 사람에게 가장 큰 도움이 됩니다.
💡 두 편을 겹쳐 읽으며
두 글은 분야가 다릅니다. 하나는 백엔드 인프라, 하나는 프론트엔드 디자인 시스템이에요. 그런데 구조가 똑같습니다.
눈에 잘 안 보이는 문제를 발견했다 → 보이게 만드는 장치를 도입했다.
이태형 님이 다룬 세션 문제는 평소엔 아무 티가 안 납니다. 서버가 멀쩡히 돌아가는 동안은 누구도 눈치채지 못해요. 장애가 나야만 드러나죠. 변기원 님이 다룬 UI 변경도 마찬가지입니다. 코드는 통과하고 화면도 뜨는데, 누군가 유심히 보기 전까지는 아무도 모릅니다.
두 분 다 그 문제가 터진 뒤에 고치는 대신, 터지기 전에 보이게 만드는 쪽을 택했습니다. 세션을 밖으로 빼서 구조적으로 없앴고, 화면을 사진으로 찍어 기계가 감시하게 했어요.
이번 회차에서 가져갈 것
1. 문제를 옮기지 말고 없애기. Sticky Session은 세션 불일치 문제를 "우회"한 방식이었습니다. 동작은 했지만 장애 시 피해가 그대로 남았죠. 세션을 외부로 빼는 건 우회가 아니라 원인 제거입니다. 지금 쓰고 있는 임시방편이 문제를 없앤 건지 미룬 건지 한 번 확인해볼 만합니다.
2. 테스트가 못 잡는 영역을 알아두기. 단위 테스트를 아무리 촘촘히 짜도 "보이는 모습"은 못 잡습니다. 내 프로젝트에서 테스트가 통과하는데도 사고가 날 수 있는 지점이 어디인지 떠올려보면, 거기가 다음에 자동화할 곳입니다.
3. 재현 가능하게 쓰기. 두 글의 공통점이 하나 더 있습니다. 설정 파일 옵션, 도구 비교, 걸린 시간 — 다음 사람이 따라 할 수 있는 형태로 남겼다는 점이에요. 같은 경험도 이렇게 적으면 자산이 되고, 그냥 적으면 일기가 됩니다.
1기는 2024년 5월에 시작해 8월에 마무리된 그로스로그의 첫 기수였습니다. 지금처럼 체계가 잡혀 있지 않았고 인원도 적었어요. 그래도 매 회차 이런 기록들이 쌓였고, 그게 2기, 3기로 이어지는 기반이 됐습니다.
혼자 겪은 장애는 그냥 지나간 하루지만, 적어두면 누군가의 지름길이 됩니다. 저희가 2년 반 동안 이 활동을 이어온 이유예요.
좋은 글 남겨주신 이태형 님, 변기원 님께 감사드립니다. 그리고 아무 전례도 없던 첫 기수에서 묵묵히 기록을 이어가주신 모든 1기 멤버분들께도요! 😊
다음 큐레이션으로 다시 찾아오겠습니다! 🌱
- 에디터 · 성장일지 큐레이터 -
※ 본 큐레이션은 각 저자가 공개한 글을 소개하는 것이며, 모든 원문의 저작권은 저자에게 있습니다. 저자 본인의 요청이 있을 경우 즉시 수정 또는 삭제합니다.
'성장일지' 카테고리의 다른 글
| [GL 1기] AWS 프리티어 12개월 제대로 쓰기, 그리고 JSP 404 추적 (성장일지 6회차 큐레이션) 🌱 (0) | 2026.08.07 |
|---|---|
| [GL 1기] React-Flask 배포 시행착오와 환경별 설정 분리 (성장일지 5회차 큐레이션) 🌱 (0) | 2026.08.07 |
| [GL 1기] FCM 푸시 알림 붙이기와 간헐적 ChunkLoadError 추적 (성장일지 4회차 큐레이션) 🌱 (0) | 2026.08.07 |
| [GL 1기] EC2에서만 멈추는 스트리밍, 500줄짜리 검색 쿼리 (성장일지 3회차 큐레이션) 🌱 (0) | 2026.08.07 |
| [GL 1기] 인생 2막 개발자의 프로젝트 회고, 그리고 방통대 졸업 전략 (성장일지 2회차 큐레이션) 🌱 (0) | 2026.08.07 |