SQLite WAL lưu hàng đợi URL: một writer, nhiều reader, khóa
SQLite WAL lưu hàng đợi URL là cách dùng một tệp SQLite ở chế độ write-ahead log làm hàng đợi cục bộ cho crawler. Bảng chứa URL cần tải, mỗi worker lấy một nhóm, đánh dấu đã nhận, tải xong thì cập nhật. Không cần máy chủ cơ sở dữ liệu, không cần hàng đợi riêng. Nhưng SQLite có quy tắc khóa rõ ràng: tại một thời điểm chỉ một tiến trình được ghi. ProxyVN chạy SQLite 3.49.1 qua Python ngày 03/11/2026, so chế độ WAL với chế độ journal mặc định, cho hai tiến trình cùng ghi, cho bốn worker cùng nhận task, và giết một tiến trình giữa giao dịch. Bài ghi lại kết quả và giới hạn không nên vượt.
SQLite WAL lưu hàng đợi URL: mục tiêu và phạm vi không lặp
Phần này chốt bài toán, đầu ra và giới hạn.
Bài toán
Một crawler chạy trên một máy, vài tiến trình worker cùng tải trang. Danh sách URL cần tải có vài nghìn tới vài trăm nghìn dòng. Cần một chỗ lưu danh sách bền qua lần khởi động lại, cho nhiều worker cùng lấy việc mà không lấy trùng, và cho một tiến trình theo dõi đọc tiến độ trong lúc worker đang ghi.
Đầu ra nghiệm thu
Đầu ra là bảng đánh giá SQLite WAL cho một writer và nhiều reader của hàng đợi URL cục bộ. Bảng trả lời bốn câu hỏi: đọc khi có ghi có bị chặn không, hai writer tranh nhau thì sao, nhiều worker nhận task có trùng không, tiến trình sập giữa giao dịch có làm hỏng hàng đợi không. Mỗi mục có kết quả chạy thật.
Không quảng cáo nhiều writer
SQLite WAL cho phép đọc song song với ghi, nhưng vẫn chỉ một writer tại một thời điểm. Bài không trình bày SQLite như hàng đợi cho nhiều máy hay hàng chục writer ghi liên tục. Khi cần như vậy, có cơ sở dữ liệu máy chủ và hàng đợi chuyên dụng.
Phiên bản đã khóa
Lab dùng thư viện sqlite3 của Python 3.12, nhân SQLite 3.49.1, trên Windows, ổ đĩa cục bộ. Mỗi tiến trình mở kết nối riêng. Kết quả về khóa phụ thuộc hệ điều hành và hệ thống tệp, nên không áp dụng cho ổ đĩa mạng.
Ai nên đọc
Người viết crawler nhỏ chạy trên một máy và đang lưu hàng đợi bằng tệp văn bản hay biến trong bộ nhớ. Người đã dùng SQLite và gặp lỗi database is locked. Người cần quyết định khi nào SQLite đủ, khi nào phải chuyển sang PostgreSQL hay hàng đợi riêng.
Vì sao không dùng hàng đợi trong bộ nhớ
Hàng đợi trong bộ nhớ của Python nhanh và đơn giản, nhưng mất sạch khi tiến trình dừng. Crawler chạy vài giờ mà khởi động lại giữa chừng sẽ phải bắt đầu từ đầu, hoặc tệ hơn, không biết URL nào đã tải. SQLite giữ trạng thái trên đĩa, khởi động lại là đọc tiếp.
Vì sao không dùng tệp văn bản
Tệp văn bản không có giao dịch: hai worker đọc cùng dòng, cùng nhận cùng URL. Tiến trình sập giữa lúc ghi để lại tệp dở. Đánh dấu trạng thái từng URL phải viết lại cả tệp. SQLite giải quyết cả ba bằng giao dịch, khóa và cập nhật theo dòng, trong một tệp duy nhất.
Đánh giá SQLite WAL cho một writer và reader của hàng đợi URL local với SQLite WAL lưu hàng đợi URL
Phần này tóm tắt cơ chế của WAL.
Journal mặc định
Chế độ mặc định của SQLite là rollback journal, tên chế độ là delete. Khi ghi, SQLite chép trang cũ ra tệp journal, ghi trang mới vào tệp chính, rồi xóa journal khi giao dịch xong. Trong lúc ghi xác nhận, tiến trình ghi giữ khóa độc quyền trên tệp, và người đọc phải chờ.
Write-ahead log
Theo trang Write-Ahead Logging của SQLite, ở chế độ WAL, thay đổi được ghi nối vào tệp wal riêng, tệp chính giữ nguyên cho tới khi checkpoint chép thay đổi về. Tài liệu nêu ưu điểm chính: người đọc không chặn người ghi và người ghi không chặn người đọc. Đọc và ghi có thể diễn ra đồng thời.
Vẫn chỉ một writer
Tài liệu cũng nói rõ: vẫn chỉ có một writer tại một thời điểm. WAL tăng song song giữa đọc và ghi, không giữa ghi và ghi. Hai tiến trình cùng muốn ghi thì một phải chờ.
Không dùng trên ổ đĩa mạng
Tài liệu ghi WAL không hoạt động trên hệ thống tệp mạng, vì mọi tiến trình dùng chung cơ sở dữ liệu phải ở trên cùng một máy để chia sẻ bộ nhớ của tệp shm. Hàng đợi SQLite WAL chỉ dành cho worker cùng máy.
Checkpoint
Tệp wal lớn dần khi có ghi. Checkpoint chép thay đổi từ wal về tệp chính. Mặc định, SQLite tự checkpoint khi wal vượt khoảng 1.000 trang. Nếu luôn có reader giữ phiên đọc cũ, checkpoint không thể hoàn tất và wal tiếp tục lớn.
synchronous và độ bền
Ở chế độ WAL, pragma synchronous bằng NORMAL thường được dùng thay cho FULL. NORMAL ghi ít lần đồng bộ đĩa hơn, nhanh hơn, và vẫn không hỏng cơ sở dữ liệu khi ứng dụng sập. Mất điện đột ngột có thể mất vài giao dịch cuối. Với hàng đợi URL, mất vài thay đổi trạng thái cuối thường chấp nhận được. Lab giữ mặc định.
Ba tệp thay vì một
Ở chế độ WAL, ngoài tệp chính còn có tệp wal và tệp shm. Sao lưu hay chép cơ sở dữ liệu khi đang chạy phải tính cả ba, hoặc dùng API sao lưu của SQLite. Chép riêng tệp chính có thể thiếu thay đổi chưa checkpoint.
Bật WAL và dựng bảng hàng đợi URL cho SQLite WAL lưu hàng đợi URL
Phần này dựng bảng và bật chế độ.
Cột trạng thái dạng chữ
Lab dùng chữ new, claimed, done, failed cho dễ đọc khi truy vấn bằng tay. Dùng số nguyên tiết kiệm chỗ hơn một chút nhưng khó đọc. Với vài trăm nghìn dòng, chênh lệch dung lượng không đáng kể, dễ đọc quan trọng hơn.
Bật chế độ
c = sqlite3.connect("q.db")
print(c.execute("pragma journal_mode=wal").fetchone()[0]) # wal
Lệnh pragma trả về chế độ hiện tại. Chế độ WAL được lưu trong tệp, các kết nối sau tự dùng WAL, không cần bật lại.
Bảng hàng đợi

Bảng hàng đợi
create table q(
id integer primary key,
url text unique,
status text default 'new',
worker text,
claimed_at real)
url có ràng buộc unique để không thêm trùng. status là new, claimed, done hoặc failed. worker và claimed_at ghi ai nhận và lúc nào, để phát hiện task bị kẹt khi worker chết.
Nạp 1.000 URL
Lab chèn 1.000 URL dạng https://shop.vn/p/số vào bảng, trạng thái mặc định new. Hai bảng giống hệt được dựng: một ở chế độ delete, một ở chế độ WAL, để so.
Thêm URL mới khi đang chạy
Crawler thường phát hiện URL mới trong lúc tải. Thêm bằng insert or ignore để ràng buộc unique tự bỏ URL đã có. Việc thêm cũng là ghi, cũng tranh khóa với worker nhận task. Gom nhiều URL mới vào một giao dịch thay vì mỗi URL một giao dịch giúp giảm tranh chấp.
Chỉ mục cho cột trạng thái
Với vài trăm nghìn dòng, truy vấn tìm task new cần chỉ mục trên status và id. Lab có 1.000 dòng nên không cần. Thêm chỉ mục làm mỗi lần cập nhật trạng thái tốn thêm một chút, nhưng truy vấn nhận task nhanh hơn nhiều khi bảng lớn.
Một kết nối cho mỗi tiến trình
Mỗi tiến trình worker nên mở kết nối riêng, không chia sẻ một kết nối giữa các tiến trình. Kết nối SQLite không an toàn khi dùng chung qua fork. Với nhiều luồng trong cùng tiến trình, mỗi luồng cũng nên có kết nối riêng hoặc dùng khóa bao quanh kết nối chung.
Thời gian chờ khóa
Python sqlite3 có tham số timeout khi kết nối, là số giây chờ khóa trước khi báo database is locked. Mặc định là 5 giây. Lab đặt timeout bằng 0 và bằng 3 để thấy cả hai hành vi.
Chế độ giao dịch
Lab mở kết nối với isolation_level bằng None để tự điều khiển giao dịch bằng begin và commit. begin immediate xin khóa ghi ngay từ đầu giao dịch. begin exclusive xin khóa độc quyền. Không ghi gì thì mặc định là deferred, chỉ xin khóa ghi khi gặp câu lệnh ghi đầu tiên.
Đo đọc khi có ghi và hai writer tranh khóa trong SQLite WAL lưu hàng đợi URL
Phần này chạy tiến trình giữ khóa ghi và thử đọc, thử ghi từ tiến trình khác.
Cách thử
Một tiến trình con mở giao dịch begin exclusive, cập nhật 10 dòng, giữ giao dịch 2 giây rồi rollback. Trong 2 giây đó, tiến trình chính thử đọc đếm số task new với timeout 0, rồi thử ghi với timeout 0 và timeout 3 giây.
Chế độ delete: đọc bị chặn
Ở chế độ delete, lệnh đọc báo database is locked ngay lập tức. Khóa độc quyền của tiến trình ghi chặn mọi người đọc. Tiến trình theo dõi tiến độ không xem được gì trong lúc worker đang ghi.
Người đọc thấy ảnh chụp nhất quán
Mỗi giao dịch đọc ở chế độ WAL thấy cơ sở dữ liệu như tại thời điểm nó bắt đầu. Thay đổi của người ghi sau thời điểm đó không lọt vào giữa chừng. Tiến trình theo dõi đếm số task theo trạng thái sẽ luôn ra tổng bằng số dòng, không bị lệch vì đọc giữa lúc ghi.
Chế độ WAL: đọc không bị chặn
Ở chế độ WAL, cùng lệnh đọc trả về 1.000 dòng trong khoảng 6 mili giây, dù tiến trình kia đang giữ khóa độc quyền. Người đọc thấy trạng thái trước giao dịch đang mở, chưa thấy 10 dòng đang được sửa. Đây đúng là điều tài liệu hứa.
Lần thử đầu với begin immediate
Lần chạy đầu, tiến trình con dùng begin immediate thay vì exclusive. Ở chế độ delete, đọc khi đó vẫn thành công. Lý do: begin immediate chỉ giữ khóa dự định ghi, chưa phải khóa độc quyền. Ở chế độ delete, người đọc chỉ bị chặn khi người ghi lên khóa độc quyền, thường là lúc xác nhận giao dịch. Lab đổi sang exclusive để thấy rõ khác biệt.
Ghi thứ hai, timeout 0
Ở cả hai chế độ, ghi từ tiến trình thứ hai với timeout 0 báo database is locked ngay. WAL không cho hai writer cùng lúc. Đây là giới hạn cần nhớ khi thiết kế.
Ghi thứ hai, timeout 3 giây
Với timeout 3 giây, ghi thứ hai thành công sau khoảng 2 giây ở cả hai chế độ, ngay khi tiến trình con rollback. Kết nối tự chờ và thử lại trong phạm vi timeout. Không cần tự viết vòng lặp thử lại.
Timeout mặc định của Python
Nếu không truyền timeout, sqlite3 của Python chờ 5 giây. Đủ cho phần lớn trường hợp. Lỗi locked với timeout mặc định nghĩa là có giao dịch giữ khóa hơn 5 giây, thường là giao dịch đang làm việc không nên nằm trong đó.
Bảng kết quả

Đọc và ghi đồng thời
Thao tác khi có ghi độc quyền đang mở |
delete |
WAL |
|---|---|---|
Đọc, timeout 0 |
database is locked |
đọc được, 6 ms |
Ghi, timeout 0 |
database is locked |
database is locked |
Ghi, timeout 3 giây |
được sau khoảng 2 giây |
được sau khoảng 2 giây |
Lỗi database is locked không phải lỗi dữ liệu
Lỗi này chỉ có nghĩa là không lấy được khóa trong thời gian chờ. Dữ liệu không hỏng. Cách xử lý là tăng timeout, rút ngắn giao dịch của tiến trình đang giữ khóa, hoặc giảm số tiến trình ghi. Bắt lỗi rồi thử lại vô hạn trong mã thường che giấu một giao dịch quá dài ở chỗ khác.
Giao dịch ghi phải ngắn
Thời gian chờ của writer thứ hai bằng thời gian writer đầu giữ khóa. Nếu worker mở giao dịch, nhận task, rồi tải trang trong khi giao dịch còn mở, mọi worker khác phải chờ suốt thời gian tải. Nhận task và tải trang phải là hai bước riêng: giao dịch ngắn để nhận, đóng giao dịch, rồi mới tải.
Nhận task không trùng với nhiều worker trong SQLite WAL lưu hàng đợi URL
Phần này cho bốn tiến trình cùng nhận task.
Câu lệnh nhận task
update q set status='claimed', worker=?, claimed_at=?
where id in (select id from q where status='new' order by id limit ?)
returning id
Một câu lệnh vừa chọn vừa cập nhật vừa trả về id đã nhận. Trong giao dịch begin immediate, không worker nào khác chen vào giữa bước chọn và bước cập nhật. RETURNING có từ SQLite 3.35, bản 3.49.1 trong lab hỗ trợ.
Vòng lặp của worker
Mỗi worker lặp: begin immediate, chạy câu lệnh nhận 20 task, commit, ghi lại id, nghỉ 10 mili giây mô phỏng việc khác, cho tới khi không còn task new. Bốn worker được khởi động cùng lúc nhờ một sự kiện chung.
Lần thử đầu
Lần chạy đầu không có sự kiện đồng bộ. Worker đầu tiên khởi động xong trước khi ba worker kia kịp bắt đầu, và nhận hết 1.000 task trong vòng chưa tới một giây. Trên Windows, tạo tiến trình mới chậm, nên một worker có thể làm xong việc trước khi worker khác sẵn sàng. Lab thêm sự kiện để bốn worker bắt đầu cùng lúc.
Kết quả

Bốn worker không trùng
Bốn worker nhận tổng 1.000 task, 1.000 id khác nhau, không id nào bị nhận hai lần. Mỗi worker nhận 260, 240, 260, 240 task. Toàn bộ mất 0,22 giây.
Kiểm không trùng bằng tập hợp
Lab gom mọi id các worker trả về, so độ dài danh sách với độ dài tập hợp. 1.000 và 1.000 nghĩa là không id nào xuất hiện hai lần. Đây là phép kiểm đơn giản nên chạy mỗi khi đổi câu lệnh nhận task hay chế độ giao dịch.
Vì sao không trùng
begin immediate xin khóa ghi trước khi đọc. Hai worker không thể cùng ở trong đoạn chọn và cập nhật. Worker thứ hai chờ, rồi khi vào được thì các task worker thứ nhất vừa nhận đã có trạng thái claimed, không còn khớp điều kiện new.
Nếu dùng begin deferred
Với giao dịch deferred, hai worker có thể cùng đọc danh sách task new, rồi một worker xin khóa ghi thành công, worker kia bị từ chối. SQLite báo lỗi chứ không cho ghi trùng. Nhưng worker phải xử lý lỗi và thử lại. begin immediate tránh được vòng thử lại này.
Đánh dấu xong và thất bại
Sau khi tải xong, worker mở giao dịch ngắn khác để đặt status bằng done hoặc failed kèm thông tin lỗi. Hai giao dịch nhận và hoàn tất tách nhau bởi thời gian tải. Nhờ vậy, khóa ghi chỉ bị giữ vài mili giây mỗi lần, dù việc tải mất vài giây.
Thứ tự nhận task
Câu lệnh nhận theo id tăng dần, nên URL thêm trước được tải trước. Nếu cần ưu tiên, thêm cột priority và sắp theo nó. Có thể thêm cột next_try để hoãn task thất bại tạm thời tới thời điểm sau, rồi điều kiện nhận task lọc next_try nhỏ hơn hiện tại.
Thông lượng
Nhận 20 task mỗi lần giảm số giao dịch. Nhận từng task một thì số giao dịch gấp 20 lần, mỗi giao dịch giữ khóa ghi một chút. Với hàng đợi URL, nhận theo nhóm vài chục là hợp lý.
Tiến trình sập và kích thước WAL với SQLite WAL lưu hàng đợi URL
Phần này thử sập giữa giao dịch và đo tệp wal.
Sập giữa giao dịch
Sau khi bốn worker nhận hết task, một tiến trình mở begin immediate, cập nhật 50 task về new, rồi thoát đột ngột bằng os._exit trước khi commit. Mở lại cơ sở dữ liệu, số task new là 0. Thay đổi chưa xác nhận bị bỏ, hàng đợi giữ trạng thái trước giao dịch.
Câu dọn task kẹt
Tiến trình dọn chạy định kỳ một câu update đưa task claimed có claimed_at cũ hơn một ngưỡng, ví dụ mười phút, về new. Ngưỡng phải lớn hơn thời gian tải dài nhất của một trang. Đặt ngưỡng quá ngắn sẽ trả task về trong khi worker vẫn đang tải, và trang bị tải hai lần.
Task bị kẹt khi worker chết
Ca ngược lại nguy hiểm hơn: worker nhận task, commit, rồi chết khi đang tải. Task nằm ở trạng thái claimed mãi mãi. SQLite không biết worker đã chết. Cột claimed_at cho phép một tiến trình dọn dẹp tìm task claimed quá lâu và trả về new. Lab không cài tiến trình dọn dẹp.
Không cần làm gì đặc biệt khi khởi động lại
Sau khi tiến trình sập, mở lại cơ sở dữ liệu là SQLite tự khôi phục từ tệp wal hoặc journal. Không có bước sửa chữa thủ công. Điều duy nhất cần làm là chạy câu dọn task claimed bị kẹt từ lần chạy trước.
Kích thước wal
Lab tắt checkpoint tự động, rồi cập nhật cả 1.000 dòng 20 lần. Tệp wal lớn tới 1.130 KB. Mỗi lần cập nhật ghi lại các trang bị sửa vào wal.
Checkpoint TRUNCATE
Chạy pragma wal_checkpoint TRUNCATE trả về bộ ba 0, 0, 0 và tệp wal còn 0 byte. Mọi thay đổi đã được chép về tệp chính, tệp wal được cắt về rỗng. Với checkpoint tự động bật, wal sẽ được chép về định kỳ mà không cần làm tay.
Reader giữ phiên lâu
Nếu một tiến trình theo dõi mở giao dịch đọc và không đóng, checkpoint không thể chép qua điểm mà reader đó đang nhìn. Tệp wal sẽ lớn mãi. Tiến trình theo dõi nên đọc rồi đóng giao dịch ngay, không giữ kết nối trong giao dịch mở.
Kiểm hàng đợi bằng truy vấn
Vì hàng đợi là bảng SQL, kiểm tiến độ chỉ cần một câu đếm theo status. Tìm worker chậm bằng cách gom theo worker. Tìm tên miền hay lỗi bằng cách gom các dòng failed theo tên miền. Đây là lợi ích phụ đáng kể so với hàng đợi chuyên dụng chỉ cho biết số thông điệp.
Sao lưu khi đang chạy
Muốn sao lưu hàng đợi khi worker đang chạy, dùng API backup của sqlite3 hoặc lệnh VACUUM INTO, không chép tệp bằng lệnh hệ thống. Chép tệp chính trong lúc có thay đổi chưa checkpoint sẽ ra bản sao thiếu dữ liệu.
Đầu ra nghiệm thu: đánh giá một writer, nhiều reader và giới hạn của SQLite WAL lưu hàng đợi URL
Phần cuối gom kết quả thành bộ bàn giao.
Bộ bàn giao
Bộ bàn giao gồm lab.py dựng hai cơ sở dữ liệu ở hai chế độ, thử đọc và ghi khi có khóa, chạy bốn worker, thử sập giữa giao dịch, đo wal và checkpoint. Người nhận chạy lại, phải thấy chế độ delete chặn đọc, WAL không chặn đọc, hai writer luôn phải chờ nhau, bốn worker nhận 1.000 task không trùng.
Một dòng cho mỗi URL, không xóa
Giữ dòng của URL đã xong thay vì xóa. Ràng buộc unique trên url nhờ đó chặn được việc thêm lại URL đã tải. Nếu bảng quá lớn, chuyển các dòng done cũ sang bảng lưu trữ, nhưng vẫn giữ url để kiểm trùng.
Khi nào SQLite WAL đủ
Một máy, vài worker, ổ đĩa cục bộ, giao dịch ghi ngắn, số lần ghi mỗi giây vừa phải. Lab với bốn worker nhận theo nhóm 20 hoàn tất 1.000 task trong 0,22 giây, dư sức cho crawler tải vài trang mỗi giây.
Đo trước khi chuyển
Trước khi bỏ SQLite vì lo nó chậm, đo số giao dịch nhận và hoàn tất mỗi giây mà crawler thật sự cần. Crawler tải năm trang mỗi giây chỉ cần mười giao dịch ghi mỗi giây, rất nhỏ so với khả năng của SQLite trên ổ cục bộ. Giới hạn thường đến từ số máy và ổ đĩa mạng, không từ tốc độ.
Khi nào nên chuyển
Worker chạy trên nhiều máy. Cần ổ đĩa mạng. Có nhiều tiến trình ghi liên tục với giao dịch dài. Cần thông báo đẩy khi có task mới thay vì hỏi định kỳ. Khi đó PostgreSQL với SKIP LOCKED hay một hàng đợi chuyên dụng phù hợp hơn.
Khi nào cần proxy với SQLite WAL lưu hàng đợi URL
SQLite là tệp cục bộ, không cần mạng, không cần proxy. Proxy thuộc về bước tải trang mà worker làm sau khi nhận task. Hàng đợi có thể lưu thêm cột ghi nhãn cấu hình mạng đã dùng cho mỗi URL, để biết trang nào tải qua vùng nào.
Với website được phép thu thập, có lúc cần IP tại Việt Nam để nhận đúng trang trong nước. Khi đó anh em có thể mua proxy tĩnh Việt Nam tại trang chủ ProxyVN. Proxy không làm hàng đợi nhanh hơn và không giải quyết lỗi database is locked. Vai trò hợp lệ của proxy được giải thích ở bài Web Scraping proxy là gì.
Không lưu chuỗi proxy trong hàng đợi
Nếu cần biết URL nào dùng cấu hình mạng nào, chỉ lưu nhãn. Chuỗi proxy có mật khẩu không nên nằm trong tệp cơ sở dữ liệu, vì tệp này thường được sao lưu và chép đi. Cách viết chuỗi proxy cho worker đúng định dạng có trong bài định dạng proxy.
Một hàng đợi cho mỗi crawler
Nếu chạy nhiều crawler khác nhau trên cùng máy, mỗi crawler một tệp SQLite riêng. Một tệp dùng chung nghĩa là mọi crawler tranh cùng một khóa ghi. Tách tệp loại bỏ tranh chấp giữa các crawler mà không tốn gì.
Những gì lab chưa thử
Lab chưa thử ổ đĩa mạng, chưa thử hàng trăm nghìn dòng, chưa đo số giao dịch tối đa mỗi giây, chưa cài tiến trình dọn task kẹt. Lab chưa thử Linux, nơi tạo tiến trình nhanh hơn và hành vi khóa có thể khác về thời gian.
Checklist SQLite WAL lưu hàng đợi URL

Checklist
- Bật journal_mode wal một lần.
- url unique, có cột status, worker, claimed_at.
- Nhận task bằng một câu update kèm returning trong begin immediate.
- Giao dịch nhận task ngắn, tải trang ngoài giao dịch.
- Đặt timeout kết nối vài giây.
- Dọn task claimed quá lâu.
- Reader đóng giao dịch ngay sau khi đọc.
- Chỉ dùng trên ổ đĩa cục bộ, cùng một máy.
Câu hỏi thường gặp về SQLite WAL lưu hàng đợi URL
WAL có cho nhiều tiến trình cùng ghi không?
Không. Vẫn chỉ một writer tại một thời điểm. Lab thấy ghi thứ hai báo database is locked khi timeout bằng 0.
WAL khác journal mặc định ở đâu?
Người đọc không bị chặn khi có người ghi. Lab thấy chế độ delete báo khóa khi đọc, WAL đọc được trong 6 mili giây.
Làm sao nhiều worker không nhận trùng task?
Dùng một câu update kèm returning trong giao dịch begin immediate. Lab có bốn worker nhận 1.000 task không trùng id nào.
Tiến trình sập giữa giao dịch có làm hỏng dữ liệu không?
Không. Lab thấy thay đổi chưa commit bị bỏ, hàng đợi giữ nguyên trạng thái trước đó.
Tệp wal có lớn mãi không?
Không nếu checkpoint chạy. Lab tắt checkpoint tự động thì wal lên 1.130 KB, checkpoint TRUNCATE đưa về 0.
Hàng đợi SQLite có cần proxy không?
Không. Proxy thuộc về bước tải trang của worker.
SQLite WAL lưu hàng đợi URL và những điều cần nhớ
SQLite WAL lưu hàng đợi URL là lựa chọn gọn cho crawler một máy. Đọc không bị chặn khi có ghi, giao dịch bảo vệ hàng đợi khi tiến trình sập, và một câu update có returning cho nhiều worker nhận task không trùng. Lab trên SQLite 3.49.1 cũng cho thấy giới hạn rõ ràng: chỉ một writer, nên giao dịch phải ngắn và việc tải trang phải nằm ngoài giao dịch. Cần IP tĩnh cho bước tải trang của worker dùng SQLite WAL lưu hàng đợi URL, liên hệ Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam.