Data Best Practices (Phần 2): Xây dựng các luồng xử lý dữ liệu
Sự xuất hiện đa dạng các công cụ, framework mới đã nâng cao độ phức tạp trong việc thiết kế hệ thống xử lý dữ liệu. Trong bài viết này, ta sẽ cùng tìm hiểu về các best practice, phương pháp thiết kế data pipeline, các hướng tiếp cận trong thiết kế và một số cách xử lý cho các vấn đề thường gặp.
Đọc thêm Series Data Best Practices:
Phần 1: Thiết kế kiến trúc và các công cụ
Phần 2: Xây dựng các luồng xử lý dữ liệu
Phần 3: Kiểm tra và chuẩn hóa dữ liệu
Phần Cuối: Điều phối và tự động hoá luồng dữ liệu
Bước 2: Xây dựng các luồng xử lý dữ liệu
Data pipeline là giải pháp tự động hóa việc thu thập dữ liệu từ nhiều nguồn khác nhau, thực thi một chuỗi các bước xử lý, và lưu trữ hay truyền tải dữ liệu đến các quy trình kế tiếp để khai thác giá trị dữ liệu. Đối với các nền tảng dữ liệu hiện đại, việc kết hợp các kỹ thuật và công nghệ mới sẽ làm tăng năng suất đồng thời giúp nền tảng dữ liệu được linh hoạt hơn rất nhiều. Sau đây, ta sẽ đi sâu hơn các thành phần quan trọng của nền tảng dữ liệu và xem xét các cách tiếp cận mới.
ETL, ELT hay ETLT?
ETL và ELT là hai quy trình phổ biến và quan trọng trong hệ thống phân tích và xử lý dữ liệu. Trong thời gian gần đây, phương pháp kết hợp cả ETL và ELT thành ETLT ngày càng phổ biến do các kiến trúc data vault và data mesh xuất hiện. Việc lựa chọn phụ thuộc vào yêu cầu cụ thể của việc xử lý dữ liệu, mức độ phức tạp, hiệu suất, khả năng của hệ thống lưu trữ…
- ETL, viết tắt của Extract, Transform, Load (Trích xuất, Biến đổi, Tải), bao gồm việc trích xuất dữ liệu từ nhiều nguồn và biến đổi trước khi tải vào kho dữ liệu.
- ELT, viết tắt của Extract, Load, Transform (Trích xuất, Tải, Biến đổi), sẽ thực hiện trích xuất dữ liệu, tải ngay lập tức vào kho dữ liệu và sau đó mới biến đổi.
- ETLT kết hợp các lợi ích của ETL và ELT bằng cách thực hiện các phép biến đổi đơn giản trên dữ liệu trước khi dữ liệu được tải vào kho dữ liệu, cho phép nhập dữ liệu nhanh hơn và giúp cải thiện chất lượng dữ liệu. Các biến đổi phức tạp, đa nguồn sẽ được thực hiện sau đó, khi cần dữ liệu để phân tích.
Những bài toán phù hợp với ETL:
- Data Warehouse: dữ liệu cần biến đổi (clean, transform thành schema cụ thể,…) trước khi lưu trữ vào kho dữ liệu để khai thác.
- Compliance & Regulations: dữ liệu cần được tổng hợp, ẩn các thông tin nhạy cảm,… trước khi lưu vào kho dữ liệu để đáp ứng các quy định về Compliance của hệ thống.
- Hệ thống cần xử lý khối lượng lớn dữ liệu thô, phi cấu trúc.
Các công cụ phổ biến: Talend, Informatica PowerCenter, Microsoft SQL Server Integration Services (SSIS), Apache Nifi, Pentaho Data Integration.
Những bài toán phù hợp với ELT:
- Big Data: các hệ thống lưu trữ dữ liệu hiện đại (Hadoop, Cloud-based data warehouse,…) đủ khả năng thực hiện biến đổi dữ liệu sau khi tải lên.
- Real-time Processing: dữ liệu cần sẵn sàng càng nhanh càng tốt.
- Data Analysis & Exploration: trong trường hợp cấu trúc dữ liệu cuối thường thay đổi, tải dữ liệu trước khi biến đổi sẽ giúp hệ thống linh hoạt hơn.
Các công cụ phổ biến: Apache Spark, Amazon Redshift, Google BigQuery, Snowflake, Microsoft Azure Data Factory.
Những bài toán phù hợp với ETLT:
- Cross-Platform Analysis: dữ liệu được trích xuất, tải lên một hệ thống trung gian, nơi thực hiện việc biến đổi dữ liệu, và sau đó được tải lên hệ thống cuối cùng để phân tích.
- Data Consolidation: dữ liệu từ nhiều nguồn cần được tổng hợp, biến đổi và tải lên một hệ thống khác.
- Complex Transformation: quá trình biến đổi tốn nhiều tài nguyên mà hệ thống mục tiêu không đủ mạnh để thực thi biến đổi dữ liệu.
Các công cụ phổ biến: Microsoft SQL Server Integration Services, Informatica PowerCenter, Talend Data Integration, IBM InfoSphere DataStage.
Functional Programming
Functional Programming là phương pháp lập trình tập trung vào việc sử dụng pure function để tạo chương trình, từ đó giúp tăng khả năng module hóa, tăng khả năng kết hợp và tăng khả năng đọc hiểu luồng xử lý. Đối với việc tạo data pipeline, Functional Programming có những đặc điểm sau:
- Tính immutable - các dữ liệu không thay đổi trong quá trình xử lí, mà sẽ thực hiện trên bản sao mới của dữ liệu. Điều này giúp tránh được các side effect không mong muốn và dễ dàng theo dõi hành vi của hệ thống.
- Higher-order functions - hàm nhận một hàm khác làm tham số hoặc trả về một hàm như kết quả. Đặc điểm này giúp việc tạo pipeline biến đổi dữ liệu dễ dàng hơn, khi trong mỗi bước xử lí một hàm nhận đầu ra của bước trước làm đầu vào của mình.
- Tích hợp hỗ trợ Parallel processing và concurency, giúp việc xử lý dữ liệu lớn trở nên hiệu quả hơn.
Một số công cụ phổ biến cho Functional Programming trong lĩnh vực Data Engineering có thể kể đến như Apache Spark, Flink, thư viện pandas của Python. Các công cụ này cung cấp các functional programming API và tính năng cho thao tác xử lí và chuyển đổi dữ liệu.
Imperative hay Declarative
Imperative - lập trình mệnh lệnh và Declarative - lập trình khai báo là hai phương pháp khác nhau được sử dụng trong Data Engineering tùy thuộc vào nhiệm vụ cụ thể.
- Imperative programming: là phương pháp chú trọng vào cách thức thực hiện tác vụ bằng cách viết chuỗi các dòng code, command, script,… mô tả từng bước tác vụ được thực thi (ví dụ như code bằng ngôn ngữ Java, Python,…)
- Declarative programming: là phương pháp chú trọng vào khai báo kết quả muốn đạt được và để trình thông dịch của ngôn ngữ quyết định cách thực hiện. SQL là ngôn ngữ khai báo phổ biến nhất trong Data Engineering.
Data engineer thường thuộc một trong hai nhóm: nhóm tập trung vào business - thường sử dụng SQL để nhanh chóng đạt mục tiêu và nhóm tập trung vào kĩ thuật - sử dụng các ngôn ngữ lập trình như Python, Java, Scala, các best practice để xây dựng hệ thống và khả năng mở rộng. Trong thực tế doanh nghiệp sẽ tùy thuộc vào yêu cầu bài toán và nhân lực để chọn hướng phát triển phù hợp. Một số query engine mạnh mẽ như Hive, Presto, Impala cũng được sử dụng để nhanh chóng phát triển hệ thống xử lí dữ liệu cùng đội ngũ mạnh về SQL.
So sánh nhanh về Imperative và Declarative trong Data Engineering:
Imperative | Declarative | |
---|---|---|
Pros | - Mức độ điều khiển, tùy chỉnh cao - Linh hoạt - Nhiều thư viện hỗ trợ | - Dễ đọc hiểu - Tối ưu hóa hiệu suất - Phát triển nhanh chóng |
Cons | - Hệ thống phức tạp - Tốn nhiều effort | - Khó xử lý các tác vụ có độ phức tạp nghiệp vụ cao - Cần kiến thức về Domain |
Một số phương pháp xử lý cho các vấn đề thường gặp
Xử lý SCD
Trong lĩnh vực Data, SCD là viết tắt của Slowly Changing Dimension. Đây là khái niệm trong quản lí dữ liệu nói về cách đối ứng với thay đổi của dữ liệu theo thời gian. SCD được chia thành 3 Type thông dụng:
- SCD Type 1: Ghi đè dữ liệu cũ bằng dữ liệu mới, không lưu lại lịch sử.
- SCD Type 2: Thêm record mới và đánh dấu inactive cho record cũ (hoặc sử dụng trường expireTime), lịch sử thay đổi có thể được truy vấn từ các record cũ.
- SCD Type 3: Thêm một cột mới mỗi khi thay đổi để lưu lại “giá trị trước”, phương pháp này chỉ giữ lại phiên bản hiện tại và một phiên bản trước của dữ liệu.
Ngoài ra, có một số kiểu xử lý SCD theo dạng hybrid như:
- SCD Type 4 (kết hợp Type 1 và Type 2): Sử dụng một bảng để lưu và theo dõi record cũ.
- SCD Type 6 (kết hợp Type 1, 2 và 3): Lưu record mới khi có thay đổi, đồng thời thêm cột vào record cũ để cập nhật giá trị hiện tại cho tất cả record cũ.
Trong hệ sinh thái dữ liệu lớn, có 4 cách tiếp cận để giải quyết SCD:
- Phương pháp xử lý SCD truyền thống: Các phương pháp này có thể phức tạp, dễ gặp lỗi với các tập dữ liệu lớn và làm chậm quá trình ETL.
- Phương pháp snapshot: Lưu lại các snapshot của tất cả dimension mỗi khi quá trình ETL được chạy. Phương pháp này đơn giản hơn so với SCD truyền thống. Các dimension trở thành một loạt các bản snapshot được đánh dấu theo thời gian, mỗi bản đại diện cho trạng thái của dimension tại một thời điểm cụ thể.
- Nested data type: Sử dụng các loại dữ liệu phức tạp như array hay map để theo dõi lịch sử thuộc tính mà không làm thay đổi cấu trúc của bảng.
- Delta Lake: Phương pháp hiệu quả và đảm bảo tính toàn vẹn dữ liệu với tất cả sự xử lý phức tạp đều được thực hiện ngầm.
Xử lý dữ liệu trùng lặp
Dữ liệu trùng lặp có thể là một vấn đề nghiêm trọng đối với một số ứng dụng, đặc biệt là trong lĩnh vực tài chính. Sự trùng lặp thường xảy ra do lỗi và quá trình retry sau đó, dẫn đến nguy cơ dữ liệu bị hỏng và ảnh hưởng đến các hệ thống liên quan.
Để giải quyết vấn đề này, cần tích hợp chiến lược deduplication (xóa bỏ sự trùng lặp) vào data flow. Nhưng việc này tương đối khó khăn trong môi trường xử lý phân tán và có tốc độ xử lý cao, độ trễ của dữ liệu cũng có thể gây nên vấn đề. Một số phương pháp deduplication trong hệ thống quy mô lớn là:
-
Các phương pháp thông dụng như hashing (kỹ thuật băm), binary comparision (so sánh nhị phân), delta differencing (chênh lệch delta)
Binary comparison là phương pháp so sánh để đưa ra kết luận dữ liệu có khác nhau hay không, thay vì nêu chi tiết sự khác biệt cụ thể. Delta differencing là phương pháp chú trọng vào việc tìm điểm khác nhau giữa hai dữ liệu và dùng dữ liệu này (được gọi là delta) để lưu trữ, truyền tải…
-
Unique key: Định nghĩa unique key trên một hoặc nhiều trường để đảm bảo tính duy nhất, bao gồm cả việc tạo bảng chứa unique key và kiểm tra sự tồn tại của key đến tránh trùng lặp.
-
Bloom filter: Cấu trúc lưu trữ dữ liệu dựa trên xác suất giúp nhanh chóng và hiệu quả trong việc xác định một phần tử có thuộc một tập hợp hay không.
-
Exactly-Once Processing: Tận dụng khả năng của hệ thống đảm bảo xử lý mỗi message chỉ một lần duy nhất để tránh xử lý thừa.
Best practices
Các best practice cho quá trình xây dựng data pipeline:
-
Thiết kế pipeline:
- Nghiên cứu xây dựng metadata-driven pipelines
- Tham số hóa data pipeline code để thực hiện đưa dữ liệu vào theo từng phần nhỏ
- Thiết kế tính idempotent cho data pipelines
- Dọn dẹp tài nguyên sau khi thực thi
- Sử dụng feature-flag để dễ dàng quản lý các thành phần trong pipeline
- Giảm thiểu sự phụ thuộc giữa các thành phần trong pipeline
-
Fault tolerance:
- Thiết kế tính đến fault tolerance
- Giám sát các pipeline để phát hiện lỗi không mong muốn
- Chuẩn bị đội ngũ giải quyết các lỗi xảy ra khi vận hành
-
Tối ưu hiệu suất:
- Tránh các tác vụ thực thi quá lâu
- Đảm bảo khả năng chịu lỗi để giảm thiểu data drift
- Đảm bảo tính portability trên các nền tảng khác nhau
- Thu thập thông tin về lưu lượng dữ liệu
- Nghiên cứu sử dụng các công cụ quản lý workload trên các tenant khác nhau
-
Coding practices:
- Thiết kế các function theo triết lý UNIX
- Refactor boilerplate và khuyến khích code reuse
- Giảm thiểu ràng buộc giữa các component trong pipeline
Khi thiết lập các luồng xử lý dữ liệu, một trong những yếu tố quan trọng để có thể quyết định tính sẵn sàng của dữ liệu là chất lượng của dữ liệu. Trong Phần 3 của series Data Best Practices, ta sẽ đi sâu hơn vào bước kiểm tra và chuẩn hoá dữ liệu, cách áp dụng cũng như các tiêu chí quan trọng để có thể xác định chất lượng của dữ liệu.