thefinalboss commited on
Commit
c21916c
·
verified ·
1 Parent(s): a7d6382

Add AICL example: 59_streaming_pipeline.aicl

Browse files
data/aicl/examples/59_streaming_pipeline.aicl ADDED
@@ -0,0 +1,402 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AICL Example: Streaming Data Pipeline
2
+ # Kafka-like distributed streaming data pipeline with exactly-once semantics, schema registry,
3
+ # stream-table duality, watermarking, and partitioned processing for event-driven architectures.
4
+
5
+ Goal: Build a distributed streaming data pipeline that provides Kafka-like event streaming with
6
+ exactly-once delivery semantics, centralized schema management, stream-table duality for
7
+ stateful processing, and watermark-based time tracking for out-of-order event handling.
8
+
9
+ Constraint: Exactly-once semantics must be guaranteed end-to-end from producer to consumer
10
+ through idempotent producers, transactional publishing, and consumer deduplication.
11
+
12
+ Constraint: Schema registry must support backward, forward, and full compatibility modes
13
+ with zero-downtime schema evolution and automatic migration planning.
14
+
15
+ Constraint: Stream-table duality must allow seamless switching between materialized table
16
+ views and changelog streams with point-in-time query capability.
17
+
18
+ Constraint: Watermarking must track event time progress across all partitions with configurable
19
+ allowed lateness and idle partition detection.
20
+
21
+ Risk: Producer sends duplicate messages during network retry causing duplicate processing
22
+ Recovery: Enable idempotent producer with sequence number tracking per partition; consumer
23
+ deduplication using offset and message key tracking; compaction removes duplicates
24
+
25
+ Risk: Schema evolution breaks deserialization for existing consumers
26
+ Recovery: Schema registry rejects incompatible changes; consumers fall back to last compatible
27
+ schema version; dead-letter queue captures undecodable messages for manual resolution
28
+
29
+ Risk: Partition rebalancing during consumer group changes causes processing gaps
30
+ Recovery: Implement cooperative rebalancing with incremental partition assignment; consumers
31
+ complete in-flight processing before releasing partitions; offset commit on rebalance
32
+
33
+ Risk: Watermark stalls on idle partitions blocking downstream window processing
34
+ Recovery: Detect idle partitions via configurable timeout; advance watermark using active
35
+ partition progress; emit watermark advancement events to unblock downstream operators
36
+
37
+ Risk: State store corruption during stream-table duality materialization
38
+ Recovery: Maintain replicated state store with write-ahead log; recover from replica on
39
+ corruption; fallback to changelog topic replay for full state reconstruction
40
+
41
+ Risk: Broker failure causes data unavailability for critical partitions
42
+ Recovery: Replicate partitions across multiple brokers with ISR quorum; promote in-sync
43
+ replica to leader; under-replicated partition alert triggers automatic re-replication
44
+
45
+ Layer: StreamingPipeline
46
+ SubLayer: EventBroker
47
+ SubLayer: SchemaRegistry
48
+ SubLayer: StreamProcessor
49
+ SubLayer: StateStore
50
+ SubLayer: WatermarkTracker
51
+
52
+ Validation: Exactly-once delivery verified through end-to-end idempotency checks
53
+ Validation: Schema compatibility must pass automated validation before registration
54
+ Validation: Watermark must advance monotonically and never regress
55
+ Validation: State store must be recoverable from changelog within 5 minutes
56
+ Validation: Partition rebalancing must complete within 30 seconds without data loss
57
+ Validation: Consumer lag must not exceed 1000 messages under normal operating conditions
58
+ Validation: All produced messages must be readable by at least one in-sync replica
59
+
60
+ # Level 2: Entities
61
+
62
+ Entity Topic
63
+ topic_id: string
64
+ topic_name: string
65
+ partition_count: integer
66
+ replication_factor: integer
67
+ retention_ms: integer
68
+ cleanup_policy: string
69
+ schema_subject: string
70
+ is_compacted: boolean
71
+
72
+ Entity Producer
73
+ producer_id: string
74
+ client_id: string
75
+ transactional_id: string
76
+ acks_mode: string
77
+ enable_idempotence: boolean
78
+ batch_size: integer
79
+ linger_ms: integer
80
+ schema_version: string
81
+
82
+ Entity ConsumerGroup
83
+ group_id: string
84
+ members: list
85
+ partition_assignment: dict
86
+ commit_offset: dict
87
+ rebalance_strategy: string
88
+ session_timeout_ms: integer
89
+ is_rebalancing: boolean
90
+
91
+ Entity SchemaVersion
92
+ schema_id: integer
93
+ subject: string
94
+ version: integer
95
+ schema_definition: dict
96
+ compatibility_mode: string
97
+ fingerprint: string
98
+ registered_at: datetime
99
+ is_latest: boolean
100
+
101
+ Entity StateStore
102
+ store_id: string
103
+ store_name: string
104
+ store_type: string
105
+ changelog_topic: string
106
+ partition_count: integer
107
+ total_size_bytes: integer
108
+ last_checkpoint: datetime
109
+ is_persistent: boolean
110
+
111
+ Entity Watermark
112
+ partition_id: integer
113
+ event_time: datetime
114
+ watermark_time: datetime
115
+ idle_detected: boolean
116
+ last_event_seen: datetime
117
+ allowed_lateness_ms: integer
118
+
119
+ # Level 3: Behaviors
120
+
121
+ Behavior PublishEvent
122
+ Input:
123
+ topic: string
124
+ key: string
125
+ value: bytes
126
+ headers: dict
127
+ event_timestamp: datetime
128
+ Output:
129
+ partition: integer
130
+ offset: integer
131
+ timestamp: datetime
132
+ Action:
133
+ Validate event against registered schema subject and version
134
+ Assign partition based on key hash or custom partitioner
135
+ Begin transaction if producer is transactional
136
+ Append to partition log with replication to ISR
137
+ Commit transaction and return partition-offset pair
138
+
139
+ Behavior SubscribeToTopic
140
+ Input:
141
+ group_id: string
142
+ topics: list
143
+ rebalance_callback: string
144
+ Output:
145
+ assigned_partitions: list
146
+ committed_offsets: dict
147
+ Action:
148
+ Register consumer with group coordinator
149
+ Participate in cooperative rebalancing protocol
150
+ Receive partition assignments with committed offsets
151
+ Initialize fetch loops for assigned partitions
152
+ Report heartbeat and process records in poll loop
153
+
154
+ Behavior RegisterSchema
155
+ Input:
156
+ subject: string
157
+ schema_definition: dict
158
+ compatibility_mode: string
159
+ Output:
160
+ schema_id: integer
161
+ version: integer
162
+ is_compatible: boolean
163
+ Action:
164
+ Compute schema fingerprint for deduplication check
165
+ Validate compatibility against existing versions per mode
166
+ Register new version if compatible, reject otherwise
167
+ Broadcast schema update to subscribed producers and consumers
168
+ Update schema cache on all broker nodes
169
+
170
+ Behavior MaterializeTable
171
+ Input:
172
+ source_topic: string
173
+ state_store_name: string
174
+ key_extractor: string
175
+ value_aggregator: string
176
+ Output:
177
+ store_id: string
178
+ record_count: integer
179
+ size_bytes: integer
180
+ Action:
181
+ Subscribe to source topic changelog from beginning
182
+ Apply key extraction and value aggregation per record
183
+ Update state store with upsert or delete operations
184
+ Checkpoint state periodically to changelog topic
185
+ Expose point-in-time query interface over materialized state
186
+
187
+ Behavior AdvanceWatermark
188
+ Input:
189
+ partition_id: integer
190
+ event_timestamp: datetime
191
+ Output:
192
+ new_watermark: datetime
193
+ idle_partitions: list
194
+ Action:
195
+ Track per-partition event time progress
196
+ Detect idle partitions exceeding idle timeout
197
+ Compute global watermark as min across active partitions
198
+ Emit watermark advancement events downstream
199
+ Handle late-arriving events within allowed lateness window
200
+
201
+ # Level 4: Conditions
202
+
203
+ Condition: SchemaIncompatible
204
+ When new schema version fails compatibility check against latest version
205
+ Then reject schema registration and return detailed incompatibility report
206
+ with specific fields causing the violation and suggested modifications
207
+
208
+ Condition: ConsumerLagExceeded
209
+ When consumer group lag exceeds 10000 messages on any partition
210
+ Then scale up consumer instances within the group, increase fetch rate,
211
+ and alert operations team if lag continues to grow for 5 minutes
212
+
213
+ Condition: UnderReplicatedPartition
214
+ When partition ISR count drops below configured replication factor
215
+ Then prioritize replica recovery for under-replicated partitions, alert
216
+ operations team, and restrict leader election to in-sync replicas only
217
+
218
+ Condition: IdlePartitionDetected
219
+ When partition receives no events for longer than idle_timeout_ms
220
+ Then mark partition as idle, exclude from watermark computation, and
221
+ advance watermark using only active partitions to prevent stalling
222
+
223
+ Condition: StateStoreCorrupted
224
+ When state store checksum validation fails on checkpoint load
225
+ Then initiate recovery from changelog topic replay, redirect queries
226
+ to replica store during recovery, and log corruption details for analysis
227
+
228
+ # Level 5: Events
229
+
230
+ Event: SchemaRegistered
231
+ On new_schema_version_approved
232
+ Action: Broadcast schema update to all registered producers and consumers,
233
+ update schema cache on brokers, and validate existing data compatibility
234
+
235
+ Event: RebalanceStarted
236
+ On consumer_group_rebalance_triggered
237
+ Action: Pause record processing for partitions being revoked, commit current
238
+ offsets, execute cooperative rebalancing protocol, and resume with new assignments
239
+
240
+ Event: WatermarkAdvanced
241
+ On global_watermark_progress_updated
242
+ Action: Trigger downstream window evaluations, emit late-arrival corrections
243
+ for events between old and new watermark, and update watermark metrics
244
+
245
+ Event: StateCheckpointed
246
+ On state_store_checkpoint_completed
247
+ Action: Commit consumer offsets to match checkpoint, compact changelog topic
248
+ up to checkpoint offset, and log checkpoint metadata for recovery
249
+
250
+ Event: TransactionCompleted
251
+ On producer_transaction_commit_or_abort
252
+ Action: Make transactional records visible to consumers, release partition
253
+ locks held by transaction, and update transaction coordinator state
254
+
255
+ # Level 6: Concurrency
256
+
257
+ Parallel:
258
+ Event production across all topic partitions
259
+ Consumer group record processing per partition
260
+ Schema validation and registration
261
+ State store materialization and checkpointing
262
+ Watermark tracking across all partitions
263
+ Partition replication and ISR management
264
+ Changelog compaction for state stores
265
+
266
+ # Level 7: Optimization
267
+
268
+ Optimize: Throughput and latency of event streaming pipeline
269
+ Priority: Producer batching optimized for throughput without exceeding linger latency
270
+ Priority: Consumer prefetch and parallel processing within partition assignment
271
+ Priority: State store checkpoint frequency balanced against recovery time
272
+ Priority: Schema cache locality on brokers closest to producers and consumers
273
+ Priority: Changelog compaction scheduled during low-traffic periods
274
+
275
+ # Level 8: Learning
276
+
277
+ Learn: Optimal partition count per topic based on throughput patterns
278
+ Goal: Minimize consumer group rebalancing while maximizing parallelism
279
+ Adapt: Partition count recommendations for new topics
280
+ Based: Historical throughput per partition, consumer group size, and rebalance frequency
281
+
282
+ Learn: Consumer fetch parameters for optimal throughput
283
+ Goal: Achieve target throughput with minimum consumer CPU utilization
284
+ Adapt: Fetch size, max poll records, and processing concurrency
285
+ Based: Consumer processing latency, message size distribution, and lag patterns
286
+
287
+ Learn: Watermark idle timeout configuration per topic
288
+ Goal: Advance watermarks promptly without excessive late-arrival corrections
289
+ Adapt: Idle partition timeout and allowed lateness parameters
290
+ Based: Event arrival rate distribution, late arrival frequency, and window accuracy
291
+
292
+ # Level 9: Security
293
+
294
+ Security:
295
+ Encrypt: All inter-broker communication using TLS with mutual authentication
296
+ Encrypt: Data at rest on broker log segments using AES-256 with per-topic keys
297
+ Protect: Schema registry access with RBAC and schema-level permissions
298
+ Protect: Consumer group operations with ACLs per principal and topic
299
+ Protect: State store contents with encryption and access control
300
+ Encrypt: Producer-consumer communication with SASL/OAUTHBEARER and TLS
301
+
302
+ # Level 10: Native
303
+
304
+ Native: Java
305
+ {
306
+ import org.apache.kafka.clients.producer.*;
307
+ import org.apache.kafka.clients.consumer.*;
308
+ import org.apache.kafka.common.*;
309
+ import org.apache.kafka.streams.*;
310
+ import org.apache.kafka.streams.processor.*;
311
+ import org.apache.kafka.streams.state.*;
312
+ import java.time.Duration;
313
+ import java.util.*;
314
+
315
+ public class StreamingPipeline {
316
+
317
+ private final KafkaProducer<String, byte[]> producer;
318
+ private final KafkaStreams streams;
319
+ private final SchemaRegistryClient schemaRegistry;
320
+
321
+ public StreamingPipeline(Properties producerConfig,
322
+ Properties streamsConfig,
323
+ SchemaRegistryClient schemaRegistry) {
324
+ this.producer = new KafkaProducer<>(producerConfig);
325
+ this.schemaRegistry = schemaRegistry;
326
+ this.streams = null;
327
+ }
328
+
329
+ public RecordMetadata publishEvent(String topic, String key, byte[] value,
330
+ Map<String, String> headers) throws Exception {
331
+ String subject = topic + "-value";
332
+ int schemaId = schemaRegistry.getLatestVersion(subject).getId();
333
+
334
+ ProducerRecord<String, byte[]> record = new ProducerRecord<>(topic, key, value);
335
+ headers.forEach(record.headers()::add);
336
+
337
+ try {
338
+ return producer.send(record).get();
339
+ } catch (Exception e) {
340
+ producer.abortTransaction();
341
+ throw new PipelineException("Failed to publish event", e);
342
+ }
343
+ }
344
+
345
+ public KafkaStreams buildMaterializedView(String sourceTopic,
346
+ String storeName) {
347
+ Properties props = new Properties();
348
+ props.put(StreamsConfig.APPLICATION_ID_CONFIG, storeName + "-app");
349
+ props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
350
+
351
+ StreamsBuilder builder = new StreamsBuilder();
352
+ builder.table(sourceTopic,
353
+ Materialized.<String, byte[], KeyValueStore<Bytes, byte[]>>as(storeName)
354
+ .withKeySerde(Serdes.String())
355
+ .withValueSerde(Serdes.ByteArray())
356
+ .withCachingEnabled()
357
+ .withLoggingEnabled(Collections.emptyMap())
358
+ );
359
+
360
+ KafkaStreams streams = new KafkaStreams(builder.build(), props);
361
+ streams.setStateListener((newState, oldState) -> {
362
+ if (newState == KafkaStreams.State.RUNNING) {
363
+ System.out.println("State store " + storeName + " materialized");
364
+ }
365
+ });
366
+ return streams;
367
+ }
368
+
369
+ public static class WatermarkTracker {
370
+ private final Map<TopicPartition, Long> partitionWatermarks = new HashMap<>();
371
+ private final Duration allowedLateness;
372
+ private final Duration idleTimeout;
373
+ private final Map<TopicPartition, Long> lastEventTime = new HashMap<>();
374
+
375
+ public WatermarkTracker(Duration allowedLateness, Duration idleTimeout) {
376
+ this.allowedLateness = allowedLateness;
377
+ this.idleTimeout = idleTimeout;
378
+ }
379
+
380
+ public synchronized long advanceWatermark(TopicPartition tp, long eventTime) {
381
+ lastEventTime.put(tp, System.currentTimeMillis());
382
+ partitionWatermarks.merge(tp, eventTime, Math::max);
383
+ return computeGlobalWatermark();
384
+ }
385
+
386
+ private long computeGlobalWatermark() {
387
+ long now = System.currentTimeMillis();
388
+ long globalWatermark = Long.MAX_VALUE;
389
+ for (Map.Entry<TopicPartition, Long> entry : partitionWatermarks.entrySet()) {
390
+ long lastSeen = lastEventTime.getOrDefault(entry.getKey(), now);
391
+ if (now - lastSeen > idleTimeout.toMillis()) {
392
+ continue;
393
+ }
394
+ globalWatermark = Math.min(globalWatermark, entry.getValue());
395
+ }
396
+ return globalWatermark == Long.MAX_VALUE
397
+ ? partitionWatermarks.values().stream().max(Long::compare).orElse(0L)
398
+ : globalWatermark;
399
+ }
400
+ }
401
+ }
402
+ }