Homebrew MySQL이 재부팅 뒤 dyld: Library not loaded로 안 뜰 때 — 원인과 고정 방법

commitlog·4일 전
post-thumbnail

문제: 다른 설치가 공용 라이브러리의 링크를 새 버전으로 옮겼고, 이미 떠 있던 MySQL은 멀쩡하다가 재부팅 때 dyld: Library not loaded로 뜨지 못했습니다.
해결: 재설치가 메이저 업그레이드라는 걸 dry-run으로 확인하고 멈춘 뒤, 필요한 라이브러리 80개를 brew가 관리하지 않는 경로로 옮겨 지금 버전에 고정했습니다.

맥을 재부팅했더니 로컬 MySQL이 뜨지 않았습니다. 재부팅 직전까지 멀쩡히 돌던 DB였고, 그사이 이 DB에 손댄 것도 없었습니다.

원인

macOS · Homebrew · MySQL 9.6 기준

dyld: Library not loaded: /opt/homebrew/opt/protobuf/lib/libprotobuf-lite.35.0.0.dylib

Homebrew는 라이브러리를 버전마다 다른 폴더에 설치하고, 지금 쓰는 버전을 가리키는 opt 심볼릭 링크를 둡니다. MySQL은 이 링크 경로로 라이브러리를 찾습니다.

설치 기록을 거슬러 올라가니 이틀 전 같은 맥에 다른 버전의 MySQL이 설치돼 있었습니다. 그때 protobuf와 abseil 새 버전이 깔리면서 링크도 새 버전으로 옮겨졌습니다. 옛 버전 폴더는 남아 있었지만, MySQL이 찾는 경로에는 그 파일이 더 이상 없었습니다.

설치한 날 문제가 없었던 이유는 실행 중인 프로세스가 뜰 때 로드한 라이브러리를 계속 쓰기 때문입니다. 의존성을 바꾼 설치의 문제는 재시작할 때 드러났습니다.

바꾼 것

처음 계획은 MySQL만 다시 설치하는 것이었습니다. 그 전에 돌려 본 결과는 이랬습니다.

$ brew install --dry-run mysql
Would upgrade 1 formula: mysql 9.6.0_3 -> 26.10.0_1

재설치가 아니라 메이저 업그레이드였습니다. 되돌리려면 데이터 폴더를 통째로 복원해야 해서 멈췄습니다.

대신 9.6을 유지했습니다. 호환되는 라이브러리를 brew가 관리하지 않는 경로로 복사하고, 자체 launchd 설정으로 mysqld를 직접 띄운 뒤 brew pin mysql로 묶었습니다. DYLD_LIBRARY_PATH로 옛 폴더를 가리키는 방법도 있지만 brew cleanup 한 번이면 같은 장애가 나고, mysqld_safe처럼 셸 스크립트를 거치면 macOS가 이 변수를 지웁니다.

확인

옛 버전을 가리키는 라이브러리는 79개였습니다. 그런데 복사 뒤 첫 기동이 실패했습니다. 라이브러리 하나가 @rpath로 파일을 하나 더 불렀기 때문입니다. otool -L은 직접 연결만 보여 줍니다. 그 파일까지 80개를 넣고 DYLD_PRINT_LIBRARIES로 실제 로드 경로를 찍어 80개 모두 새 경로인 것을 확인했습니다.

옛 brew 서비스 설정이 남아 있으면 로그인할 때 MySQL이 하나 더 뜨려 할 수 있어서, 비활성으로 묶고 plist를 밖으로 옮겼습니다. 며칠 뒤 재부팅에서 옛 서비스는 올라오지 않았습니다. 작업 전후 30개 테이블의 행 수는 같았습니다.

남은 것

메이저 업그레이드는 미뤘습니다. 지금 구조는 업그레이드를 막아 둔 것이지 해결한 것이 아닙니다.

패키지를 설치하거나 올린 뒤에는 그 패키지를 쓰는 서비스를 한 번 재시작해 보시길 권합니다.

영상

https://youtu.be/nbJdKHAcCNk

profile
실제 프로덕션에서 내린 개발·인프라 판단과 그 근거를 기록합니다.

0개의 댓글