- Mattermost sử dụng Elasticsearch để giảm tải cho cơ sở dữ liệu và cung cấp kết quả tìm kiếm nhanh hơn nhiều
- Để Elasticsearch hoạt động đúng, cần lập chỉ mục toàn bộ dữ liệu cần tìm kiếm
- Với dữ liệu đã được lập chỉ mục, việc lập chỉ mục thêm cho bài viết và tệp mới sau đó diễn ra khá nhanh
- Tuy nhiên, việc lập chỉ mục đầy đủ từ đầu cho một cơ sở dữ liệu rất lớn (100 triệu bài viết) là cực kỳ chậm (sau 18 giờ vẫn chưa xong nổi một nửa và còn chậm dần đi)
- Thông qua biểu đồ thời gian tiêu tốn theo từng lần gọi cơ sở dữ liệu, nhóm đã xác định truy vấn SQL trong phương thức
PostStore.GetPostsBatchForIndexing là vấn đề
- Truy vấn này về cơ bản sắp xếp các bài viết theo timestamp tạo và trả về N bài viết mới hơn timestamp được cho trước
- Job lập chỉ mục chạy lặp lại truy vấn này cho đến khi mọi bài viết đều được lập chỉ mục
- Phân tích kế hoạch thực thi truy vấn bằng
EXPLAIN (ANALYZE, BUFFERS):
- Khi thực hiện index scan trên bảng Posts, hệ thống đang phải xử lý 40 triệu block để áp dụng điều kiện Filter (309GB)
- JOIN với bảng Channels không phải là vấn đề
- Nếu chỉ áp dụng phần
Posts.CreateAt > ?1 trong mệnh đề OR của điều kiện WHERE thì truy vấn nhanh hơn rất nhiều (30ms)
- Từ đó, khi áp dụng điều kiện
Posts.CreateAt = ?1 AND Posts.Id > ?2 thì tốc độ cực kỳ nhanh (0.047ms)
- Xác định nguyên nhân:
- Truy vấn gốc quét toàn bộ các hàng trong Posts rồi mới lọc bằng Filter, trong khi truy vấn đã chỉnh sửa chỉ kiểm tra index và lấy ra đúng các hàng cần thiết
- Lý do truy vấn ngày càng chậm theo thời gian là vì phải lọc bỏ ngày càng nhiều hàng hơn
- Giải pháp:
- Tận dụng tính năng row constructor comparison của PostgreSQL để đổi điều kiện thành
(Posts.CreateAt, Posts.Id) > (?1, ?2)
- Sau thay đổi này, thời gian thực thi truy vấn giảm mạnh còn 34 mili giây
- Tuy nhiên, trên MySQL thì truy vấn đã sửa lại chạy chậm hơn. Vì truy vấn gốc nhanh hơn trên MySQL nên mã được tách nhánh để dùng truy vấn khác nhau theo từng DB
- Những điều rút ra:
- Khi dùng
EXPLAIN, hãy luôn dùng thêm tùy chọn BUFFERS
- Hãy tận dụng Index Cond thay vì Filter
- Luôn giả định PostgreSQL và MySQL gần như luôn hoạt động khác nhau
- Kết luận
- Việc tối ưu hóa đã giúp giảm thời gian thực thi truy vấn hơn 1000 lần
- Tối ưu hóa này đã được đưa vào Mattermost v9.7.0 và v9.5 ESR
- Quá trình tối ưu hóa cũng mang lại rất nhiều bài học
3 bình luận
Bài cuối cũng có nhắc đến, nhưng tiêu đề của bài này hơi mang cảm giác giật tít một chút... nếu đổi theo hướng thực tế hơn thì có lẽ sẽ là
'Trường hợp ứng dụng PostgreSQL rút ra từ những sai lầm'
chăng..
Ừm... cá nhân mình nghĩ rằng nếu viết một bài ở mức độ này mà gắn với một công ty/sản phẩm cụ thể, thì ngược lại có lẽ độ tin cậy dành cho sản phẩm đó sẽ giảm đi khá nhiều.
Cách sắp xếp thì rõ ràng mạch lạc, nhưng hơi tiếc là giá trị kỹ thuật được chứa bên trong có vẻ hơi thiếu một chút.
Sau khi đọc bài này, ngược lại tôi càng thấy mức độ tin cậy thấp hơn. Vì điều đó có nghĩa là một sản phẩm đang được bán thu tiền đã phát hành tính năng mà thậm chí không có cả bài kiểm thử xử lý dữ liệu khối lượng lớn. Tôi cảm thấy một chỉ mục đơn giản ở mức đó lẽ ra phải được thiết lập ngay từ giai đoạn phát triển tính năng. Trông có vẻ như đã lược bỏ khá nhiều quy trình phát triển phần mềm.