Giới thiệu về MapReduce MapReduce là một mô hình, khung xử lý và nền tảng tính toán song song dành cho dữ liệu lớn, bao gồm ba ý nghĩa sau:
-
MapReduce là một nền tảng tính toán hiệu suất cao dựa trên cụm (Cluster Infrastructure). Nó cho phép sử dụng các máy chủ thương mại thông thường để tạo thành cụm phân tán và song song với hàng chục, trăm hoặc nghìn nút.
-
MapReduce là một khung phần mềm tính toán và hoạt động song song (Software Framework). Khung này có thể tự động hóa việc xử lý nhiệm vụ tính toán song song, chia nhỏ dữ liệu và nhiệm vụ, phân bổ và thực thi chúng trên các nút cụm cũng như thu thập kết quả cuối cùng. Hệ thống chịu trách nhiệm xử lý nhiều chi tiết phức tạp liên quan đến lưu trữ phân tán, giao tiếp dữ liệu và xử lý lỗi, giúp giảm đáng kể gánh nặng cho nhà phát triển phần mềm.
-
MapReduce là một mô hình thiết kế chương trình song song (Programming Model & Methodology). Mô hình này cung cấp một phương pháp lập trình đơn giản dựa trên ngôn ngữ lập trình hàm Lisp, cho phép lập trình viên sử dụng hai hàm Map và Reduce để thực hiện các tác vụ tính toán cơ bản, cung cấp các thao tác trừu tượng và giao diện lập trình song song dễ sử dụng để xử lý số lượng lớn dữ liệu.
Quy trình MR: Quy trình thực thi của một công việc MapReduce bao gồm: 1) Viết mã; 2) Cấu hình công việc; 3) Nộp công việc; 4) Phân phối và thực thi nhiệm vụ Map; 5) Xử lý kết quả trung gian; 6) Phân phối và thực thi nhiệm vụ Reduce; 7) Hoàn thành công việc. Dưới đây là ví dụ chi tiết từng bước bằng cách đếm từ.
Làm thế nào để nhận biết dữ liệu có bị nghiêng hay không? Xem thông tin in ra trong quá trình thực thi, nếu hầu hết các nhiệm vụ đã hoàn thành nhưng vẫn còn một hoặc hai nhiệm vụ chưa xong, rất có thể xảy ra hiện tượng dữ liệu nghiêng. Sau đó cần kiểm tra bảng dữ liệu cụ thể để đánh giá sự phân bố dữ liệu và xác nhận.
Hiện tượng dữ liệu nghiêng và nguyên nhân gây ra Dữ liệu nghiêng là khi sự phân chia key không đồng đều, dẫn đến một phần dữ liệu chiếm đa số và phần khác lại ít hơn rất nhiều. Ví dụ với bài toán đếm từ, giai đoạn Map sẽ tạo ra cặp ("aaa", 1), sau đó ở giai đoạn Reduce tiến hành cộng dồn value để đưa ra số lần xuất hiện của "aaa". Nếu văn bản đầu vào có 100GB mà 80GB toàn bộ là "aaa" và 20GB còn lại là các từ khác, điều này sẽ dẫn đến 80GB dữ liệu được giao cho một Reduce duy nhất để xử lý, trong khi 20GB còn lại được phân bổ cho các Reduce khác. Điều này chính là nguyên nhân gây ra hiện tượng dữ liệu nghiêng, biểu hiện là Reduce chạy tới 99% rồi đứng yên chờ Reduce xử lý 80GB kia hoàn thành.
Tại sao dữ liệu nghiêng liên quan đến logic nghiệp vụ và khối lượng dữ liệu Từ góc độ khác, bản chất của dữ liệu nghiêng nằm ở việc một nút node thực hiện nhiệm vụ Reduce gặp khó khăn khi khối lượng dữ liệu quá lớn. Nếu máy có đủ tài nguyên như bộ nhớ, CPU, mạng thì dù dữ liệu nghiêng vẫn có thể xử lý tốt. Tuy nhiên, khi dữ liệu vượt quá khả năng của máy, bất kỳ key nào cũng có thể vượt ngưỡng và làm chậm hoặc thậm chí làm nghẽn việc xử lý Reduce.
Một số nguyên nhân phổ biến dẫn đến dữ liệu nghiêng bao gồm:
- Group by với chiều kích quá nhỏ.
- Distinct count(distinct xx) với giá trị đặc biệt quá nhiều.
- Join giữa các bảng lớn mà key tập trung vào một vài giá trị.
Ảnh hưởng của dữ liệu nghiêng Trong Hadoop, dữ liệu nghiêng có thể ảnh hưởng nghiêm trọng đến hiệu suất và hiệu quả xử lý.
Cách phân vùng phổ biến trong MapReduce là Hash và Range. Hash partition linh hoạt hơn và dễ thực hiện (chỉ cần đặt số lượng Reduce), trong khi Range partition yêu cầu người dùng hiểu rõ phân bố dữ liệu và đôi khi phải lấy mẫu thủ công.
Giải pháp
- Tối ưu thông qua tham số
SET hive.map.aggr=true;
SET hive.groupby.skewindata=true;
hive.map.aggr=true: Thực hiện một phần phép tổng hợp trong Map, tăng hiệu suất nhưng cần nhiều bộ nhớ hơn.
hive.groupby.skewindata=true: Khi dữ liệu nghiêng, cân bằng tải. Truy vấn sẽ tạo ra hai công việc MapReduce. Công việc đầu tiên phân phối ngẫu nhiên dữ liệu Map đến các Reduce để thực hiện phần tổng hợp, sau đó công việc thứ hai tiếp tục xử lý dựa trên kết quả trước đó.
-
Chia nhỏ key nghiêng trong giai đoạn Map Thay vì xử lý trực tiếp key nghiêng, thêm một số hậu tố ngẫu nhiên để phân chia key thành nhiều nhóm nhỏ hơn trước khi tính toán.
-
Thực hiện group trước Thực hiện phép group sớm để giảm áp lực cho Reduce.
-
Sử dụng Map Join Áp dụng Map Join để tránh tình trạng nghẽn trong Reduce.
Ngoài ra, có nhiều cách tiếp cận khác như tăng bộ nhớ JVM cho Reduce, tăng số lượng Reduce, sử dụng Partition tùy chỉnh, tối ưu thuật toán sort merge, và ứng dụng index bitmap.
Ví dụ giải quyết key rỗng Khi log chứa user_id rỗng, join với bảng users có thể gây nghiêng. Giải pháp là chuyển đổi key rỗng thành key mới bằng cách thêm giá trị ngẫu nhiên.
SELECT *
FROM log a
LEFT OUTER JOIN users b
ON CASE WHEN a.user_id IS NULL THEN CONCAT('hive', FLOOR(RAND() * 1000)) ELSE a.user_id END = b.user_id;
Join giữa các kiểu dữ liệu khác nhau Khi một bảng có user_id dạng int và một bảng có user_id dạng string, cần chuẩn hóa kiểu dữ liệu trước khi join.
SELECT *
FROM users a
LEFT OUTER JOIN logs b
ON a.usr_id = CAST(b.user_id AS STRING);
Sử dụng Map Join cho bảng lớn Đối với trường hợp bảng lớn không thể áp dụng Map Join trực tiếp, có thể lọc dữ liệu trước để giảm kích thước.
SELECT /*+MAPJOIN(x)*/
FROM log a
LEFT OUTER JOIN (
SELECT /*+MAPJOIN(d)*/ d.*
FROM (SELECT DISTINCT user_id FROM log) c
JOIN users d ON c.user_id = d.user_id
) x
ON a.user_id = x.user_id;
Kết luận Mục tiêu cuối cùng là phân phối dữ liệu đồng đều hơn giữa các Reduce. Việc tối ưu phụ thuộc vào logic nghiệp vụ cụ thể và phân bố dữ liệu.