Cảnh báo PagerDuty lúc 2 giờ sángBạn nhận được cảnh báo lúc 2 giờ sáng. Bảng điều khiển giám sát cho thấy lưu lượng truy cập giảm 100%, và cơ sở dữ liệu đã ngừng hoạt động. Khi bạn cố gắng khởi động lại MySQL, nó bị crash ngay lập tức. Xem nhanh nhật ký lỗi (thường nằm tại /var/log/mysql/error.log hoặc qua journalctl -xeu mysql) tiết lộ một thông báo gây khó chịu:
InnoDB: Unable to lock ./ibdata1, error: 11
InnoDB: Check that you do not already have another mysqld process using the same InnoDB data or log files.
Các hệ thống Linux sử dụng mã lỗi 11 để báo hiệu EAGAIN (Tài nguyên tạm thời không khả dụng). Trong ngữ cảnh này, engine InnoDB đang cố gắng đặt một khóa fcntl độc quyền lên file ibdata1. Nó thất bại vì một tiến trình khác—hoặc một thread bị treo—đã nắm giữ khóa đó. MySQL tắt ngay lập tức để ngăn hai tiến trình cùng ghi vào một file, điều này có thể gây ra hỏng dữ liệu không thể phục hồi chỉ trong vài phút.
Các nguyên nhân phổ biến- Một instance MySQL trước đó bị crash nhưng để lại một tiến trình 'zombie'.- Systemd đã cố gắng khởi động lại MySQL trước khi tiến trình cũ hoàn tất việc flush buffer pool 10GB xuống đĩa.- Quyền sở hữu không chính xác (ví dụ: root sở hữu một file thay vì mysql) ngăn dịch vụ quản lý các khóa của chính nó.- Trong môi trường Docker, việc khởi động lại container có thể không giải phóng được file handle trên volume của máy chủ.- Hai instance MySQL khác nhau vô tình được cấu hình để sử dụng cùng một datadir.## Quy trình gỡ lỗi### 1. Tìm kiếm các tiến trình ZombieĐừng quá tin tưởng vào systemctl status. Đôi khi trình quản lý dịch vụ nghĩ rằng MySQL đã dừng, nhưng nhân Linux vẫn đang theo dõi một tiến trình đang chạy. Sử dụng ps để tìm bất kỳ database engine nào còn sót lại.
ps aux | grep -iE 'mysql|mariadb'
Nếu bạn thấy một ID tiến trình (PID) như 1234 đang chạy, hãy thử tắt nó một cách bình thường trước. Nếu nó không phản hồi trong vòng 30 giây, hãy sử dụng tín hiệu mạnh hơn:
# Thử cách lịch sự trước
kill 1234
# Đợi 10 giây. Nếu nó vẫn còn đó, cưỡng ép nó:
kill -9 1234
2. Xác định tiến trình đang giữ fileKhi ps không hiển thị điều gì rõ ràng, khóa có thể đang được giữ bởi một tiến trình mà bạn không nhận ra. Tiện ích fuser sẽ cho bạn biết chính xác ai đang chạm vào file dữ liệu của bạn. Chạy lệnh này với tư cách root:
fuser -v /var/lib/mysql/ibdata1
Nếu một PID xuất hiện trong đầu ra, đó chính là thủ phạm. Điều này thường thấy trong các thiết lập mà script sao lưu hoặc snapshot tự động có thể đang khóa các file cơ sở dữ liệu.
3. Kiểm tra các file khóa cũMySQL tạo ra các file .lock nhỏ để điều phối quyền truy cập. Nếu máy chủ mất điện, các file này có thể vẫn tồn tại trên đĩa. Kiểm tra thư mục dữ liệu của bạn để tìm những tàn dư này:
ls -la /var/lib/mysql/*.lock /var/lib/mysql/mysql.sock.lock
Nếu bạn đã xác nhận rằng không có tiến trình MySQL nào đang chạy, hãy di chuyển các file này sang một thư mục tạm thời như /tmp/ và thử khởi động lại dịch vụ.
Các giải pháp hiệu quả### Giải pháp A: Đặt lại quyền thư mụcCác vấn đề về quyền thường giả dạng lỗi khóa. Nếu người dùng mysql không thể ghi vào thư mục, nó không thể tạo khóa. Điều này thường xuyên xảy ra sau khi di chuyển dữ liệu thủ công hoặc thực hiện thao tác rsync.
# Đặt lại quyền sở hữu cho người dùng và nhóm mysql
chown -R mysql:mysql /var/lib/mysql
# Thiết lập quyền thư mục tiêu chuẩn (750)
find /var/lib/mysql -type d -exec chmod 750 {} +
# Thiết lập quyền file tiêu chuẩn (640)
find /var/lib/mysql -type f -exec chmod 640 {} +
Giải pháp B: Giải quyết xung đột mount trong DockerTrong Docker hoặc Kubernetes, lỗi này thường có nghĩa là hệ điều hành máy chủ chưa giải phóng file handle từ một container trước đó. Chỉ khởi động lại container thường là không đủ. Bạn có thể cần khởi động lại chính daemon Docker để xóa các file lock ở cấp độ nhân.
docker-compose down
systemctl restart docker
docker-compose up -d
Giải pháp C: Chế độ phục hồi khẩn cấpNếu không có tiến trình nào khác và các quyền đều hoàn hảo, file ibdata1 của bạn có thể đang bị kẹt ở trạng thái 'dirty'. Bạn có thể bỏ qua bước kiểm tra khóa ban đầu bằng cách vào chế độ phục hồi. Thêm dòng này vào file my.cnf hoặc /etc/mysql/mysql.conf.d/mysqld.cnf của bạn bên dưới mục [mysqld]:
innodb_force_recovery = 1
Khởi động dịch vụ. Nếu nó hoạt động, hãy thực hiện ngay một bản sao lưu đầy đủ bằng mysqldump. Khi dữ liệu của bạn đã an toàn, hãy xóa dòng phục hồi và thử khởi động lại bình thường. Không bao giờ chạy một trang web production với chế độ phục hồi được bật, vì nó vô hiệu hóa nhiều bước kiểm tra tính toàn vẹn của dữ liệu.
Xác minh việc khắc phụcSau khi xóa khóa, hãy khởi động dịch vụ và theo dõi nhật ký trong thời gian thực:
systemctl start mysql
tail -f /var/log/mysql/error.log
Tìm thông báo: [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Nếu bạn thấy thông báo đó, cơ sở dữ liệu của bạn đã trực tuyến trở lại và hoạt động tốt.

