Kinh nghiệm · Lessons Learned
Khi thiếu bản sao lưu và một script xoá dữ liệu
Báo cáo kinh nghiệm này tóm tắt một sự cố xảy ra khi hợp nhất một lượng lớn tài liệu tài chính và thuế. Nội dung đã được ẩn danh nhưng bám sát chính xác chuỗi lỗi kỹ thuật. Mục tiêu là giúp người vận hành các chia sẻ SMB, bản mirror Nextcloud và kho Git tránh lặp lại cùng sai lầm.
Tình huống
Một chủ doanh nghiệp cá nhân trong lĩnh vực nghiên cứu và tự do muốn chuyển hàng năm tài liệu tài chính từ một chia sẻ nguồn (Samba/NAS) sang một cấu trúc đích được sắp xếp theo năm (các thư mục FY2015 … FY2026 và FY_undatiert). Nguồn chứa nhiều bản sao dư thừa; bước cuối là loại bỏ trùng lặp ("không có tệp nào bị lặp").
Điều gì đã sai
Hai lỗi kết hợp gây ra mất dữ liệu nghiêm trọng:
- Không xác minh bản sao lưu trước khi bắt đầu. Mãi sau sự cố, một bản sao lưu ngoài 8 TB (ngày 16.08) mới được gắn vào. Nếu được kiểm tra trước, lỗi tiếp theo hầu như không gây hại.
- Script loại bỏ trùng lặp với danh sách đường dẫn không được trích dẫn. Danh sách thư mục cần quét được truyền không trích dẫn cho
find. Vì một số đường dẫn chứa dấu cách (vd.share/Banks/Account 1234 5678/2024), shell đã tách các đường dẫn đó. Điều này khiến thư mục cha và con xuất hiện nhiều lần làm điểm bắt đầu —findliệt kê cùng một tệp nhiều lần.
Script so sánh các giá trị băm SHA-256 liên tiếp và xoá mục "trùng" thứ hai. Vì cùng một tệp xuất hiện như "bản trùng của chính nó" do bị liệt kê nhiều lần, nó bị xoá — cùng với mọi lần liệt kê tiếp theo. Các tệp duy nhất bị huỷ, không phải bản sao dư thừa.
(find $SCOPE)"] --> B["Shell tách đường dẫn
có dấu cách thành mảnh"] B --> C["Thư mục cha và con xuất hiện
nhiều lần làm điểm bắt đầu"] C --> D["find liệt kê cùng một tệp
N lần (N > 1)"] D --> E["Dedup so sánh các
giá trị băm liên tiếp"] E --> F["h == prev khi cùng tệp
bị liệt kê lặp lại"] F --> G["rm các 'bản trùng' =
xoá tệp duy nhất"] G --> H["~6.400 tệp duy nhất
bị huỷ"] style G fill:#c0392b,color:#fff style H fill:#c0392b,color:#fff
Việc khôi phục
Ngay khi phát hiện lỗi, thao tác đang chạy được dừng ngay lập tức. Không có kho Git cục bộ nào làm nguồn, nhưng có ba bản sao bổ sung trên máy chủ hoặc bên ngoài:
- Bản mirror đồng bộ Nextcloud của chia sẻ nguồn trên cùng máy chủ → trả về ~5.300 tệp.
- Các kho lưu ZIP còn sót lại trong cấu trúc đích → ~70 tệp nữa chỉ bằng cách giải nén.
- Bản sao lưu ngoài 8 TB (ngày 16.08) → ~600 tệp nữa.
- Git origin (Gitea) cho một kho con bị ảnh hưởng → toàn bộ lịch sử có thể tái tạo qua clone.
(~6.400)"] --> M["Bản mirror đồng bộ
Nextcloud của nguồn"] D --> Z["Các kho lưu ZIP còn sót lại"] D --> B["Bản sao lưu ngoài 8 TB
(16.08)"] D --> G["Git origin (Gitea)
cho kho con"] M -->|"~5.300"| R["Đã khôi phục"] Z -->|"~70"| R B -->|"~600"| R G -->|"Lịch sử"| R R --> S["~98 % được cứu
(~6.300 / ~6.400)"] style S fill:#27ae60,color:#fff
Tổng cộng, khoảng 98 % các tệp bị xoá đã được khôi phục. Khoảng 2 % còn lại là các tệp không tồn tại trong bất kỳ bản sao nào (bao gồm một bản xuất hộp thư và một số tài liệu được tạo sau bản sao lưu).
Tại sao khái niệm GitCover giúp ích ở đây
Câu chuyện cho thấy: ai dựa vào các cấu trúc native-Git sẽ nhanh chóng trở lại làm việc ngay cả sau những lỗi không chủ ý — và đồng thời document tuân thủ GoBD.
Bài học rút ra
- Xác minh bản sao lưu trước, không phải sau. Lý tưởng là 3-2-1: 3 bản sao, 2 phương tiện, 1 bản offline. Bản sao lưu chỉ gắn vào sau khi hỏng thì vô dụng.
- Luôn xử lý đường dẫn phân tách bằng null và có trích dẫn.
find … -print0 | xargs -0thay vìfind $LISTkhông trích dẫn. Dấu cách trong đường dẫn là "kẻ phá hoại" kinh điển. - Dedup không bao giờ được xoá khi cùng tệp bị liệt kê lặp lại. Đúng: giữ đúng một bản sao cho mỗi đường dẫn + nội dung duy nhất; nếu cùng tệp bị liệt kê nhiều lần, không được xoá gì cả (quyết định theo inode hoặc hash+đường dẫn).
- Giữ nhiều nguồn khôi phục độc lập. Bản mirror, kho lưu và kiểm soát phiên bản bổ trợ cho nhau; một nguồn duy nhất là không đủ.
- Bảo vệ các tệp cây làm việc chưa version bằng commit. Nếu chỉ nằm ở trạng thái untracked trong kho, một lệnh
git cleancũng đủ huỷ chúng. Một commit đưa chúng vào lịch sử.
Kết luận: Chỉ một biến không được trích dẫn cũng đủ huỷ hàng ngàn tệp duy nhất. Việc khôi phục chỉ thành công vì có nhiều bản sao độc lập. Cấu trúc, quy trình và kỷ luật không phải là xa xỉ — chúng là sự bảo vệ duy nhất tồn tại.
Thuộc chuyên mục Kinh nghiệm. Các bài viết tiếp theo sẽ theo sau.