Skip to content

Feature Message body cache vi

SkimMail docs edited this page Sep 15, 2026 · 5 revisions

English · Tiếng Việt · 中文

Cache nội dung thư

SkimMail giữ toàn bộ nội dung một lá thư trên đĩa ngay lần đầu bạn mở nó, để lần mở thứ hai không phải chờ IMAP. Từ 1.11.0, cache đó mặc định được mã hoá at-rest, có trần dung lượnghạn tuổi, và cuối cùng cũng được xoá khi thư mà nó thuộc về bị xoá. Trong 1.11.0 bạn cấu hình nó bằng ba biến môi trường — panel trong Settings đã dựng xong nhưng không hiện ở bản này.

Cái gì được cache, và lúc nào

  • Nội dung đã parse (HTML và text) của một lá thư, ghi xuống lần đầu thư đó được mở, và bởi prefetch nền mô tả bên dưới.
  • Nó nằm trong blob store: mặc định là một thư mục dưới DATA_DIR, hoặc bucket S3 của bạn nếu bạn đã đổi storage engine.
  • Tiêu đề, người gửi, ngày, flag, trích đoạn và chỉ mục tìm kiếm nằm trong database chứ không nằm ở đây, và không chịu ảnh hưởng của bất cứ điều gì trên trang này.
  • Attachment không được cache. Mỗi lần bạn mở một file đính kèm là một lần tải lại từ máy chủ thư.

Cache tồn tại vì một lần miss đắt theo cách không storage backend nào chữa được: đó là một vòng IMAP đồng bộ kéo nguyên lá thư về ngay bên trong một request HTTP, tốn cỡ gấp nghìn lần việc đọc lại nội dung từ đĩa.

Cấu hình

Cache luôn bật. Ba biến môi trường điều khiển nó:

Biến Nó làm gì Mặc định
CACHE_MAX_SIZE_MB Dọn bớt nội dung thư đã cache khi vượt tổng này; 0 = không giới hạn 2048
BODY_TTL_DAYS Xoá nội dung thư đã cache cũ hơn số ngày này; 0 = không bao giờ hết hạn 90
BLOB_ENCRYPT Mã hoá nội dung thư mới ghi, at-rest true

Hai biến đầu hoạt động khác biến thứ ba, và chỗ khác nhau đó quan trọng:

  • CACHE_MAX_SIZE_MBBODY_TTL_DAYS là setting Plane 2: environment cung cấp giá trị khởi tạo, còn giá trị bạn lưu từ màn hình — hoặc qua PUT /api/settings/cache — nằm trong database và từ đó trở đi sẽ thắng. Từ 1.11.1, màn hình đó là Settings ▸ Security ▸ Cache nội dung thư. Ở 1.11.0 chính panel này nằm trong tab Storage đang ẩn, nên khi đó environment thật sự là tất cả câu chuyện.
  • BLOB_ENCRYPTboot-only. Không UI, không API, không skimmail config; nó được đọc từ environment lúc khởi động và không ở đâu khác. Nó luôn bật trừ khi bạn tắt tường minh: chỉ false, 0, nooff mới tắt (không phân biệt hoa thường, bỏ qua khoảng trắng hai đầu). Mọi giá trị khác — 1, TRUE, yes, on, hay một lỗi gõ — đều để mã hoá bật, vì một cờ mặc định bật thì phải hỏng về phía an toàn.

1.11.0 làm ngược đúng quy tắc cuối cùng đó. Bản đó so giá trị với đúng chữ true, nên BLOB_ENCRYPT=1, =yes, =on=TRUE đều đọc ra tắt — mã hoá dừng đúng vào lúc người vận hành tin rằng mình vừa bật nó. Đã sửa ở 1.11.1. Nội dung thư đã cache trong lúc bị tắt không được ghi đè tại chỗ; chúng nằm nguyên không mã hoá cho tới khi rời khỏi cache. Hạ giới hạn dung lượng hoặc tuổi trong Settings ▸ Security sẽ đẩy chúng ra, và chúng quay lại ở dạng đã mã hoá.

Xem Cấu hình để biết "Plane 2" nghĩa là gì và ba biến này nằm ở đâu trong bảng tra environment đầy đủ.

Màn hình cài đặt

Settings ▸ Security ▸ Cache nội dung thư, có từ 1.11.1. Nó hiển thị bốn thứ và cho hai hành động:

Dòng Nghĩa là gì
Nội dung đã cache đang lưu bao nhiêu bản, và tổng bấy nhiêu byte
Đang chờ xoá những nội dung đã bị kết án nhưng chưa bị gỡ khỏi store; chỉ hiện khi có
Prefetch nền bật/tắt, cho cả instance. Có từ 1.16.0 — xem "Prefetch thư mới" bên dưới
Giới hạn dung lượng (MB) 0 = không giới hạn. Vượt trần thì thứ lâu không đọc nhất bị bỏ trước
Giữ trong (ngày) 0 = không bao giờ hết hạn

Save áp dụng giới hạn mới ngay lập tức, nên số liệu sử dụng nhảy ngay khi lệnh trả về. Dọn phần không rõ chủ chính là phần dọn dẹp S3 nói ở dưới.

Mọi route phía sau panel này đều chỉ dành cho owner, kể cả lệnh đọc — nên với một operator hay viewer, panel đơn giản là không hiện ra, thay vì hiện ra rồi từ chối. Đó là có chủ đích: một nút bấm mà bạn chỉ nhận được lời từ chối còn tệ hơn là không có nút nào.

Mã hoá at-rest

Với BLOB_ENCRYPT=true (mặc định), mọi nội dung thư mới ghi đều được niêm phong bằng AES-256-GCM. Khoá dẫn xuất từ master key của bạn, nên:

  • Không phát sinh thứ gì mới để backup, để mất hay để xoay vòng. Không có bí mật thứ hai nào tồn tại. Mất master key thì database vốn đã không đọc được, nên điều này không thêm một cách mất dữ liệu nào bạn chưa có sẵn.
  • Nâng cấp không cần migration và không có downtime. Mỗi blob tự nói nó có được niêm phong hay không, nên một store chứa đồng thời nội dung do 1.10.0 ghi và nội dung do 1.11.0 ghi. Đường đọc xử lý được cả hai.
  • Tắt mã hoá không làm mất cache đang có. Đọc thì luôn giải mã; công tắc chỉ quyết định nội dung mới được ghi ra sao.
  • Nếu khoá có lúc nào đó sai, lá thư đó đọc ra thành cache miss và được lấy lại từ máy chủ thư. Sản phẩm suy biến thành chậm, không bao giờ thành mất thư.

Cái nó không phủ: database. Tiêu đề, địa chỉ, trích đoạn và chỉ mục tìm kiếm nằm trên đĩa ở dạng plaintext. Với những thứ đó, hãy mã hoá volume — xem Bảo mật.

Một file backup không bao giờ mang theo khoá này. Nội dung thư đi vào archive ở dạng đã giải mã (bản thân archive có mã hoá riêng) và được niêm phong lại bằng khoá của chính instance đích khi restore, nên một archive vẫn restore được trên máy chưa từng thấy master key của instance này.

Trần dung lượng và hạn tuổi

  • Khi cache vượt CACHE_MAX_SIZE_MB, nội dung lâu không đọc nhất đi trước, dọn xuống 90% của trần chứ không đúng bằng trần — cache không nên sống cả đời ở trạng thái chỉ còn một lá thư nữa là đầy.
  • BODY_TTL_DAYS tính từ lúc nội dung được cache, không phải từ lần đọc cuối: một lá thư ngày nào cũng đọc thì cũ y hệt một lá không ai mở.
  • Hạn tuổi không chỉ là dọn dẹp. Một máy chủ thư reset UIDVALIDITY có thể cấp lại cùng một UID cho lá thư khác, mà cache thì khoá theo account, mailbox và UID — nên không có hạn tuổi thì một nội dung cũ có thể hiện dưới một lá thư mới mãi mãi. TTL chặn chuyện đó lại trong N ngày.
  • Không có timer nền nào. Một lượt dọn chạy khi đã cache thêm khoảng 64 MiB nội dung mới, và chạy ngay khi giới hạn mới được lưu qua API. Việc xoá được chia lô (500 blob mỗi lượt, cộng 50 mỗi vòng poll của sync) để một lượt dọn không bao giờ treo request của ai; phần còn lại được lượt sau nhặt tiếp.
  • Bị dọn chỉ khiến bạn tốn một lần lấy lại, không gì khác. Cache không bao giờ giữ bản sao duy nhất của thư bạn.

Xoá một account giờ xoá luôn nội dung thư của nó

Trước 1.11.0, xoá một account sẽ dọn thư của nó khỏi database nhưng để lại mọi nội dung đã cache trên đĩa vĩnh viễn — vô hình, không lấy lại được, mà vẫn bị tính vào giới hạn dung lượng của Community. Từ 1.11.0, đống byte đó ra đi cùng account. Chuyển một lá thư sang mailbox khác cũng cho nội dung cũ về hưu, vì ở nơi đến nó mang UID mới.

Với blob store filesystem, nội dung đã cache nằm dưới DATA_DIR nên có tính vào giới hạn dung lượng của gói bạn đang dùng. Với engine S3, chúng nằm trong bucket và không bị tính.

Lượt dọn một lần ở lần khởi động đầu tiên của 1.11.0

Một instance nâng lên 1.11.0 có một store đầy nội dung thư mà không có sổ sách nào về chúng. Ở lần khởi động đầu tiên, SkimMail suy ra những blob đáng lẽ phải tồn tại từ chính các lá thư của bạn, ghi số đó vào sổ, và coi phần còn lại là không có chủ. Nó chạy đúng một lần, chạy nền nên không bao giờ làm chậm cổng lắng nghe, và ghi log:

reconciled body cache store=fs indexed=1843 bytes=284127744 extra=12 deleted=12 needs_purge=false

Hai storage engine được đối xử khác nhau có chủ đích:

  • Filesystem — thư mục blob là của riêng SkimMail, nên blob không có chủ thật sự là blob mồ côi. Chúng bị xoá.
  • S3 — bucket có thể đồng thời là nơi chứa backup của bạn. Object không có chủ chỉ được đếm rồi để yên; dòng log ghi needs_purge=true. Không gì bị xoá, vì xoá nhầm một object ở đó có thể phá huỷ bản sao duy nhất của thư bạn.

Trên S3, khoảng trống đó còn tự khép lại: một nội dung thư được ghi vào sổ ở lần đọc kế tiếp, nên một instance dùng bình thường sẽ tự hội tụ mà không cần đụng vào bucket.

Nếu bạn chắc chắn bucket không chứa gì ngoài cache của SkimMail, có một lệnh purge thủ công: Settings ▸ Security ▸ Cache nội dung thư ▸ Dọn phần không rõ chủ. Nó báo lại đã xoá bao nhiêu object.

Vẫn việc đó qua API, cho script:

curl -sS -b /tmp/skim.cookies -X POST http://localhost:8080/api/settings/cache/purge

Cả hai đều chỉ dành cho owner. Xem Ảnh từ xa trong thư để lấy session cookie.

Prefetch thư mới

Sau khi một lượt sync mang thư mới về, SkimMail warm sẵn tối đa 10 nội dung thư mới nhất ở chế độ nền, để cú click đầu tiên là tức thì thay vì phải chờ IMAP.

Ba lần từ chối còn quan trọng hơn chính tính năng:

  • Chỉ khi có người đang kết nối. Không có trình duyệt nào mở thì chẳng có lần mở đầu tiên nào để làm cho nhanh hơn, và trên một đường truyền tính theo dung lượng thì đổi chác đó chỉ là tiền.
  • Không bao giờ với account đã bị tự động dừng sync. Việc suy đoán là thứ cuối cùng mà một hộp thư đang chật vật cần tới.
  • Không bao giờ tính là lỗi sync. Một lần prefetch hỏng bị bỏ qua trong im lặng, vì để việc chạy nền tuỳ chọn đẩy bộ đếm lỗi liên tiếp có thể tự dừng một hộp thư đang hoàn toàn khoẻ mạnh.

Nó cũng dừng khi cache đã chạm trần — bơm vào một cache đầy là đuổi thứ người ta vừa đọc để chứa thứ không ai hỏi. Các lượt lấy giãn nhau 250 ms để nhà cung cấp không thấy một cơn dồn dập.

Từ 1.16.0 đã có một công tắc: Settings ▸ Security ▸ Cache nội dung thư, ngay cạnh giới hạn dung lượng và tuổi — vì đó cùng là một câu hỏi: bao nhiêu thư của bạn nằm trên đĩa này, và nằm ở đó bằng cách nào. Nó mặc định bật, và vẫn bật qua một lượt nâng cấp: lý do đáng để tắt nó (vụ rò rỉ đánh dấu \Seen nói bên dưới) đã được sửa rồi, còn âm thầm đổi một mặc định về hiệu năng dưới chân người dùng lại là một kiểu bất ngờ khác. Khi tắt, prefetch nền không làm việc gì cả — không tính target, không đo cache, không mở kết nối nào — nhưng mở một lá thư vẫn lấy nội dung theo yêu cầu, y hệt mọi lần cache miss khác. Công tắc này chỉ dành cho owner, giống phần còn lại của panel này.

Prefetch từng đánh dấu thư của bạn là đã đọc trên chính máy chủ của bạn — đã sửa ở 1.15.0

Cho tới hết 1.14.0, mọi lá thư SkimMail lấy về đều được yêu cầu bằng FETCH BODY[...], và dạng lệnh này bật ngầm cờ \Seen trên máy chủ thư (RFC 3501 §6.4.5). BODY.PEEK[...] là cùng một lệnh nhưng không có tác dụng phụ ấy, và không chỗ nào trong SkimMail dùng nó.

Vì prefetch chạy nền trên những lá thư mới nhất, thư chưa ai mở đã bị đánh dấu đã đọc trên máy chủ thật — thấy được cả trong webmail lẫn trên điện thoại, chứ không riêng ở đây. Lần đồng bộ kế tiếp đọc trạng thái ấy về, nên mọi thứ bên trong SkimMail vẫn nhất quán và không có gì trông ra vẻ sai. Tải tệp đính kèm và hủy đăng ký một chạm cũng làm điều tương tự.

Hãy nâng lên 1.15.0. Cả ba đường lấy thân thư nay đều PEEK.

Phần thư đã bị đánh dấu như vậy thì không sửa lại được. Nó không phân biệt được với thư bạn thật sự đã đọc, nên chẳng có gì để một migration hoàn tác. Bản vá chặn từ đây trở đi; nó không với ngược lại quá khứ được.

Những gì nó không làm

  • Nó không phải kho lưu trữ. Nội dung bị dọn sẽ được lấy lại từ máy chủ thư; nếu lá thư đã biến mất trên máy chủ thì nó mất thật.
  • Nó không có giới hạn theo account hay theo user. Trần dung lượng và hạn tuổi áp cho cả instance.
  • Nó không cache attachment.
  • Nó không cho bạn biết thư nào đang được cache. Panel báo số lượng và tổng dung lượng, còn lệnh purge tác động lên các object không rõ chủ; không có danh sách theo từng thư và không có cách ghim một nội dung thư lại.

Xem thêm


SkimMail · skimmail@base101.app · 2026-09-15 · commit 767741a

Clone this wiki locally