DE

[DE Blog #21] Thiết Kế Hệ Thống Ad-Tech & Real-Time Bidding (RTB) Ở Quy Mô Hàng Triệu QPS: Xử Lý Siêu Độ Trễ & Attribution Modeling

8 views
[DE Blog #21] Thiết Kế Hệ Thống Ad-Tech & Real-Time Bidding (RTB) Ở Quy Mô Hàng Triệu QPS: Xử Lý Siêu Độ Trễ & Attribution Modeling

1. Bối cảnh thực tế (Context & Problem Statement)

Ngành công nghệ quảng cáo số (Ad-Tech: Google Ads, Meta Ads, The Trade Desk, Shopee Ads, TikTok Ads) vận hành dựa trên giao thức đấu thầu thời gian thực (Real-Time Bidding - RTB / OpenRTB):

  • Mỗi khi người dùng tải một trang web hoặc ứng dụng, một phiên đấu giá (Auction) diễn ra giữa hàng chục nhà quảng cáo để chọn ra banner quảng cáo hiển thị.
  • Thời gian giới hạn toàn bộ vòng đời đấu giá: Tối đa 100ms100\text{ms} (trong đó ngân sách thời gian dành cho tầng Data Lookup / User Profile chỉ vỏn vẹn <5ms< 5\text{ms}).
  • Quy mô thông lượng: Hệ thống phải xử lý từ 1,000,0001,000,000 đến 5,000,000 QPS5,000,000\text{ QPS} trên toàn cầu.

Thách thức kỹ thuật lớn nhất của Data Engineer trong Ad-Tech:

  1. Bài toán Stream-Stream Join lệch pha thời gian: Khớp nối chuỗi sự kiện: Đấu giá (Bid) \rightarrow Hiển thị (Impression) \rightarrow Nhấp chuột (Click) \rightarrow Mua hàng (Conversion). Sự kiện Impression xảy ra trong vòng vài giây, nhưng sự kiện Conversion có thể diễn ra sau đó tận 7 đến 30 ngày!
  2. Quy kết doanh thu (Attribution Modeling): Khi người dùng xem 3 quảng cáo khác nhau trước khi mua hàng, doanh thu được chia cho chiến dịch nào?

2. Các Khái Niệm & Cơ Chế Cốt Lõi

2.1. Vòng Đời Một Giao Dịch Quảng Cáo Trực Tuyến

[1. Bid Request] ---> [2. Bid Response] ---> [3. Win Notice] 
   (1M+ QPS)             (Trong < 100ms)         (Thắng thầu)
                                                      |
                                                      v
[6. Conversion] <--- [5. User Click] <--- [4. Ad Impression]
(Sau 1-30 ngày)       (Sau vài phút)       (Hiển thị banner)

2.2. Kỹ Thuật Stream-Stream Join Hai Tầng (Two-Tier State Storage)

Làm thế nào để join sự kiện Click (hôm nay) với sự kiện Conversion (20 ngày sau) mà không làm nổ tung bộ nhớ RAM của Flink?

  • Tầng 1 - Short-term Real-time Join (Flink In-Memory / RocksDB):
    • Sử dụng Flink Interval Join với cửa sổ trượt ngắn (ví dụ: 1 giờ1\text{ giờ}).
    • Dùng để ghép nối các sự kiện xảy ra tức thì: Bid Request \leftrightarrow Impression \leftrightarrow Click.
    • Dữ liệu được đẩy ngay vào ClickHouse để phục vụ Dashboard theo dõi ngân sách (Budget Pacing & Real-time CTR) cho nhà quảng cáo với độ trễ <2 giaˆy< 2\text{ giây}.
  • Tầng 2 - Long-term Historical Attribution (Data Lakehouse / Spark Batch):
    • Tất cả các sự kiện ClickConversion được ghi bền vững vào Apache Iceberg trên S3.
    • Hàng ngày, một Spark Batch Job quét bảng clicks trong cửa sổ 30 ngày (30-Day Lookback Window) và thực hiện phép LEFT JOIN với bảng conversions để chốt số liệu tài chính và thanh toán hoa hồng.

2.3. Các Mô Hình Quy Kết Quảng Cáo (Attribution Models)

Khi người dùng xem nhiều quảng cáo trước khi quyết định mua hàng:

  1. Last-Touch Attribution (Phổ biến nhất): 100%100\% giá trị đơn hàng được tính cho quảng cáo cuối cùng mà người dùng nhấp vào trước khi mua.
  2. First-Touch Attribution: 100%100\% giá trị được tính cho kênh quảng cáo đầu tiên giúp người dùng biết đến thương hiệu.
  3. Linear Attribution: Chia đều giá trị đơn hàng cho tất cả các lượt tương tác quảng cáo.
  4. Time-Decay Attribution: Các tương tác càng gần thời điểm mua hàng thì nhận được tỷ trọng hoa hồng càng cao.
  5. Data-Driven / Multi-Touch Attribution (MTA): Sử dụng thuật toán học máy (Shapley Value trong Lý thuyết trò chơi hoặc Chuỗi Markov Chain) để tính toán mức độ đóng góp thực tế của từng kênh.

2.4. Lưu Trữ User Profile Phục Vụ Bidding: Aerospike Hybrid Memory Architecture (HMA)

  • Để đưa ra giá bid chính xác trong <5ms< 5\text{ms}, hệ thống cần tra cứu tức thì hồ sơ người dùng (user_interests, age_group, past_purchases).
  • Aerospike HMA: Chỉ lưu khóa chính (Primary Index) trong bộ nhớ RAM, trong khi toàn bộ dữ liệu User Profile được lưu trực tiếp trên ổ cứng NVMe SSD dạng raw block (bỏ qua Linux File System).
    • Kết quả: Đạt tốc độ đọc <1.5ms< 1.5\text{ms} (P99) ở quy mô hàng tỷ người dùng với chi phí phần cứng rẻ hơn 70%70\% so với Redis lưu toàn bộ trên RAM!

3. Các Bảng Markdown So Sánh Chi Tiết

📊 Bảng 1: So Sánh Các Mô Hình Quy Kết Quảng Cáo (Attribution Models)

Mô hình AttributionQuy tắc phân bổ doanh thuƯu điểmNhược điểmUse-case tối ưu
Last-Touch100%100\% cho điểm chạm cuối cùngĐơn giản, dễ tính toán, minh bạchBỏ qua hoàn toàn công sức của các kênh nhận diện ban đầuE-commerce ngắn hạn, Flash Sale
First-Touch100%100\% cho điểm chạm đầu tiênKhuyến khích tìm kiếm khách hàng mớiBỏ qua các kênh chăm sóc/thuyết phục phía sauChiến dịch xây dựng thương hiệu (Brand Awareness)
LinearChia đều 1/N1/N cho tất cả các điểm chạmCông bằng, ghi nhận mọi kênh tham giaKhông phản ánh được kênh nào có tác động quyết địnhBáo cáo tổng quan đa kênh
Time-DecayTăng dần theo thời gian (Hàm mũ giảm dần)Thực tế hơn với hành vi mua sắm cân nhắc lâuVẫn mang tính gán trọng số chủ quanSản phẩm giá trị cao (Ô tô, Bất động sản, Bảo hiểm)
Data-Driven (MTA)Phân bổ bằng thuật toán Machine Learning / MarkovChính xác và tối ưu ngân sách tốt nhấtPhức tạp cao, cần hạ tầng tính toán dữ liệu lớnDoanh nghiệp quy mô lớn với ngân sách Ads hàng triệu USD

📊 Bảng 2: So Sánh 3 Chiến Lược Xử Lý Join Trong Ad-Tech

Tiêu chíFlink Stream Interval Join (Short-term)Aerospike / Redis Lookup JoinSpark Batch Join (Long-term)
Cửa sổ thời gianVài giây đến tối đa 1 giờĐiểm dữ liệu tĩnh tại thời điểm hiện tạiLên đến 30 - 90 ngày
Độ trễ kết quả<1 giaˆy< 1\text{ giây} (Real-time)<5ms< 5\text{ms}Vài giờ (Nightly Batch)
Dung lượng StateGiới hạn theo cụm Flink RocksDBLưu trong cụm NoSQL chuyên dụngLưu trữ trên Object Storage (S3 Lakehouse)
Mục đích chínhĐiều tiết ngân sách (Budget Pacing), Cảnh báo gian lậnLàm giàu ngữ cảnh (User Enrichment) khi BiddingQuyết toán tài chính, Tính phí nhà quảng cáo, MTA

📊 Bảng 3: So Sánh Aerospike vs. Redis Cluster Trong Hạ Tầng Bidding

Tiêu chíAerospikeRedis Cluster
Kiến trúc lưu trữHybrid Memory (Index trong RAM, Data trên NVMe SSD)Pure In-Memory (Toàn bộ dữ liệu nằm trong RAM)
Chi phí phần cứng ($/TB)Thấp hơn 70% ở quy mô lớn (>10 TB> 10\text{ TB})Rất đắt đỏ khi dung lượng dữ liệu phình to
Độ trễ đọc P991ms2ms\approx 1\text{ms} - 2\text{ms}<1ms< 1\text{ms}
Khả năng Scale-outTự động cân bằng cụm (Auto-rebalancing) cực mạnhCần quản lý cấu hình Cluster Sharding phức tạp hơn
Vị thế ngànhTiêu chuẩn số 1 trong các DSP/SSP Ad-Tech lớnTiêu chuẩn cho Caching ứng dụng thông thường

4. Kiến Trúc Thiết Kế Toàn Diện (Full System Design Walkthrough)

[Ad Exchanges: Google, AppLovin, Unity] (1M+ QPS)
                     |
                     v
+-----------------------------------------------------------------------------------+
| GEO-DISTRIBUTED EDGE BIDDING LAYER (Sub-50ms Response)                            |
|                                                                                   |
|  [Edge Bidding Engine] <---> [Aerospike (User Profile Lookup < 2ms)]              |
|           |                                                                       |
|           v (Async Event Emit)                                                    |
|  [Edge Kafka Clusters (Region US / EU / APAC)]                                    |
+-----------------------------------------------------------------------------------+
                     |
                     v (Kafka MirrorMaker 2 / Cross-Region Replication)
+-----------------------------------------------------------------------------------+
| CENTRAL STREAM & REAL-TIME ANALYTICS LAYER (Central Cloud)                        |
|                                                                                   |
|  [Central Kafka Bus: "raw-ad-events"]                                             |
|           |                                                                       |
|           v                                                                       |
|  [Apache Flink Stream Cluster]                                                    |
|   - Real-Time Fraud & Bot Detection (Rate-limiting suspicious IPs)                |
|   - Real-Time Impression-Click Interval Join (1h window)                          |
|   - Budget Pacing & Auto-bidding adjustments                                      |
|           |                                                                       |
|           +---> (1) Write metrics -> [ClickHouse (Advertiser Real-Time Dashboard)]|
|           |                                                                       |
|           +---> (2) Raw Sink -> [Apache Iceberg on S3 (Bronze Layer)]             |
+-----------------------------------------------------------------------------------+
                                                    |
                                                    v
+-----------------------------------------------------------------------------------+
| LONG-TERM DATA LAKEHOUSE & ATTRIBUTION ENGINE (Batch Layer)                       |
|                                                                                   |
|  [Apache Spark Batch Jobs (Daily / Hourly)]                                       |
|   - 30-Day Multi-Touch Attribution (MTA) Markov Chain Models                      |
|   - Financial Ledger & Publisher Payout Calculations                              |
|   - User Profile Aggregation & Sync back to [Aerospike] via Reverse ETL           |
+-----------------------------------------------------------------------------------+

5. Góc Ôn Luyện Phỏng Vấn (Interview Corner)

❓ Câu hỏi 1: Làm thế nào để xử lý bài toán Join giữa sự kiện Impression/Click và sự kiện Conversion khi khoảng cách thời gian có thể kéo dài tới 30 ngày (30-Day Attribution Window) mà không làm sập bộ nhớ của Stream Processing Engine?

  • Gợi ý trả lời (Kiến trúc phân tách 2 giai đoạn):
    • Vấn đề: Nếu duy trì trạng thái của 30 ngày Click events trong RAM/RocksDB của Flink với lưu lượng 1M QPS1\text{M QPS}, dung lượng State sẽ lên tới hàng chục Terabyte, gây nghẽn Checkpoint và sập hệ thống.
    • Giải pháp kiến trúc Two-Tier:
      1. Tầng Stream (Fast Path): Flink chỉ giữ State trong vòng 1 giờ1\text{ giờ} để ghép nối nhanh các sự kiện chuyển đổi xảy ra ngay lập tức, phục vụ tối ưu hóa chiến dịch thời gian thực.
      2. Tầng Batch Lakehouse (Slow Path - Nơi quyết toán chính thức):
        • Toàn bộ sự kiện clicksconversions được ghi vào bảng Apache Iceberg trên S3, phân vùng theo ngày (event_date).
        • Hàng đêm, chạy một Spark SQL Batch Job: Quét bảng conversions của ngày hôm nay và thực hiện Join ngược lại với bảng clicks trong phạm vi 30 ngày trước:
          SELECT 
              c.conversion_id,
              c.user_id,
              c.amount,
              k.ad_id,
              k.campaign_id,
              k.click_timestamp
          FROM fct_conversions c
          JOIN fct_clicks k 
            ON c.user_id = k.user_id 
           AND k.click_timestamp BETWEEN c.conversion_timestamp - INTERVAL 30 DAYS 
                                     AND c.conversion_timestamp;
          
        • Áp dụng thuật toán Attribution để ghi nhận doanh thu chính thức vào Gold Layer phục vụ xuất hóa đơn (Invoicing).

❓ Câu hỏi 2: Aerospike đạt được độ trễ đọc <1.5ms< 1.5\text{ms} cho hàng tỷ bản ghi với chi phí thấp hơn nhiều so với Redis như thế nào?

  • Gợi ý trả lời:
    • Kiến trúc Hybrid Memory Architecture (HMA):
      • Thay vì lưu toàn bộ dữ liệu và khóa trên RAM như Redis, Aerospike tách biệt:
        • Primary Index (Khóa chính): Luôn được nén chặt và lưu trong RAM (mỗi index chỉ tốn 64 bytes).
        • Data (Dữ liệu thực tế): Được ghi trực tiếp vào ổ đĩa NVMe SSD dạng khối thô (Direct Device Access / Raw Disk Blocks) mà không qua hệ thống tập tin (File System) của Linux Kernel.
    • Tối ưu hóa phần cứng:
      • Khi có truy vấn đọc, hệ thống tìm vị trí offset của bản ghi trong RAM (mất <0.1μs< 0.1\mu\text{s}), sau đó thực hiện đúng 1 lần đọc I/O đĩa song song trực tiếp từ ổ SSD NVMe (mất <1ms< 1\text{ms}).
      • Điều này giúp giảm tới 70%80%70\% - 80\% dung lượng RAM cần thiết của toàn bộ cluster so với Redis thuần túy, biến Aerospike thành lựa chọn hàng đầu cho tầng Bidding Cache trong Ad-Tech.

❓ Câu hỏi 3: Làm thế nào để phát hiện và ngăn chặn gian lận nhấp chuột (Click Fraud / Bot Traffic) trong hệ thống Ad-Tech thời gian thực?

  • Gợi ý trả lời theo 3 lớp phòng thủ:
    1. Lớp 1 - Lọc theo quy tắc thời gian thực (Real-time Rule Filter trên Flink):
      • Click Spiking: Phát hiện nếu cùng một IP hoặc device_id tạo ra >10 clicks/phuˊt> 10\text{ clicks/phút} trên cùng một quảng cáo \rightarrow Tự động gắn cờ gian lận và không trừ tiền nhà quảng cáo.
      • Impossible Travel: Khoảng cách địa lý giữa 2 lượt click liên tiếp của cùng 1 user quá xa trong khoảng thời gian ngắn (ví dụ: click ở Hà Nội và click ở New York cách nhau 5 phút).
    2. Lớp 2 - Phân tích đồ thị & Học máy trên Lakehouse (Offline Graph & ML Analysis):
      • Hàng ngày, Spark Job phân tích đồ thị phân bố IP/Subnet, User-Agent bất thường và các cụm click đồng bộ (Click Farms) để truy thu tiền và hoàn trả cho nhà quảng cáo (Refunds/Credits).
    3. Lớp 3 - Phản hồi ngược (Feedback Loop): Tự động đẩy danh sách đen (Blacklisted IPs / Device IDs) từ Lakehouse ngược trở lại tầng Edge Bidding Layer (Aerospike) để từ chối mua quảng cáo từ các nguồn bot này trong tương lai.

6. Tóm Tắt Ghi Nhớ Nhanh (Key Takeaways)

  1. Hệ thống Ad-Tech/RTB đòi hỏi sự kết hợp giữa Sub-5ms Edge Lookup (Aerospike)High-Throughput Stream Processing (Kafka + Flink).
  2. Xử lý bài toán 30-Day Attribution Window bằng kiến trúc Two-Tier Join: Stream Interval Join cho dữ liệu gần (<1h< 1\text{h}) và Spark Batch Join trên Lakehouse cho lịch sử dài hạn (30 ngaˋy30\text{ ngày}).
  3. Multi-Touch Attribution (MTA) bằng thuật toán Markov Chain / Shapley Value là tiêu chuẩn vàng để phân bổ ngân sách marketing công bằng và chính xác.
  4. Triển khai kiến trúc Edge Ingestion với Kafka MirrorMaker 2 để đảm bảo độ trễ phản hồi đấu thầu thấp nhất cho người dùng trên toàn cầu.
0Claps