Duplicate logs are a common problem in real-time log processing, primarily caused by the following factors:
Value of Deduplication:
Core mechanism:
PARTITION BY: Defines the deduplication dimension (e.g., reqid)ROW_NUMBER() window function: Assigns a unique sequence number to each record within a partitionORDER BY: Determines the retention policy (ASC retains the first record, DESC retains the last one)row_num = 1: Filters to retain the target recordSteps | Operation | Description |
|---|---|---|
1.1 | A BytePlus Flink project has been activated. | Refer to Activate Flink |
1.2 | A Flink SQL job has been created. | Refer to Create Flink SQL Job |
CREATE TABLE raw_logs ( log_time TIMESTAMP(3), reqid VARCHAR(40), -- Request ID (deduplication key) service VARCHAR(20), -- Service name level VARCHAR(10), -- Log level message STRING, -- Log content proc_time AS PROCTIME(), -- Processing time -- Event time configuration (Optional) WATERMARK FOR log_time AS log_time - INTERVAL '10' SECOND ) WITH ( 'connector' = 'kafka', 'topic' = 'raw_logs', 'properties.bootstrap.servers' = 'kafka:9092', 'scan.startup.mode' = 'earliest-offset', 'format' = 'json', 'json.ignore-parse-errors' = 'true' );
CREATE TABLE dedup_logs_simple ( reqid VARCHAR(40) PRIMARY KEY NOT ENFORCED, log_time TIMESTAMP(3), service VARCHAR(20), message STRING ) WITH ( 'connector' = 'kafka', 'topic' = 'dedup_logs', 'properties.bootstrap.servers' = 'kafka:9092', 'format' = 'json' ); INSERT INTO dedup_logs_simple SELECT reqid, log_time, service, message FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY reqid ORDER BY proc_time DESC -- Keep latest by processing time ) AS row_num FROM raw_logs ) WHERE row_num = 1;
INSERT INTO dedup_logs_simple SELECT reqid, log_time, service, message FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY reqid, service -- Partition by composite key ORDER BY proc_time DESC -- Keep latest by processing time ) AS row_num FROM raw_logs ) WHERE row_num = 1;
INSERT INTO dedup_logs_simple SELECT reqid, log_time, service, message FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY reqid, HOUR(proc_time) -- Partition by hour ORDER BY proc_time ASC -- Keep the first record per hour ) AS row_num FROM raw_logs ) WHERE row_num = 1;
The behavior of TTL in different modes is as follows:
Mode | ORDER BY | Cleanup condition is met | Output behavior |
|---|---|---|---|
keepFirst | ASC | First record time + TTL | Output new records directly |
keepLast | DESC | Last update time + TTL | Retracts the old value, then outputs the new value |
Feature | Processing Time (PROCTIME) | Event Time |
|---|---|---|
Accuracy | Low (depends on processing speed) | High (based on the actual time of occurrence) |
Out-of-order processing | Not supported | Supported (via Watermark) |
Configuration complexity | Simple (auto-generated) | Complex (requires WATERMARK definition) |
Use cases | Simple deduplication, latency-sensitive | Precise deduplication, requires time accuracy |
Complete Event Time Example:
CREATE TABLE dedup_event_time ( reqid VARCHAR(40), log_time TIMESTAMP(3), service VARCHAR(20), message STRING ) WITH (/* Kafka configuration */); INSERT INTO dedup_event_time SELECT reqid, log_time, service, message FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY reqid ORDER BY log_time DESC -- Sort by event time ) AS row_num FROM raw_logs WHERE WATERMARK(log_time) IS NOT NULL -- Ensure event time is valid ) WHERE row_num = 1;
-- Add a prefix to reduce state size (for high-cardinality keys) PARTITION BY SUBSTRING(reqid, 1, 4), reqid
SET 'table.exec.mini-batch.enabled' = 'true'; SET 'table.exec.mini-batch.size' = '5000';
After deduplicating data in Flink, use Flink's exactly-once semantics to ensure data accuracy.
Symptoms | Possible causes | Solutions |
|---|---|---|
Deduplication results still contain duplicates | The TTL is set too short | Increase the TTL |
State size continuously grows | The partition key cardinality is too high | Optimize the partition key or increase parallelism |
Processing latency increases | Data skew | Add a random prefix to distribute the load |
Watermark does not advance | Event-time data interruption | Add heartbeat data or use processing time |
State recovery failure | Incomplete checkpoint | Check storage system connectivity |