draw.io에서 바로 불러올 수 있는 단색(Monochrome) 스타일의 XML 다이어그램 코드와 각 구성요소 설명입니다.
아래 XML 전체를 복사한 후, draw.io(또나 diagrams.net)에서 [File] [Import from] [Text...] 메뉴에 붙여넣거나, [Edit] [Insert] [Advanced] [XML...]을 통해 불러오면 다이어그램이 생성됩니다.
<mxGraphModel dx="1200" dy="800" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" background="#ffffff" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<!-- Title -->
<mxCell id="title" value="MinIO S3 Metadata & Prefix Aggregation Pipeline (StarRocks)" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=18;fontStyle=1;fontColor=#111111;" vertex="1" parent="1">
<mxGeometry x="320" y="20" width="540" height="30" as="geometry" />
</mxCell>
<!-- Source 1: Kafka -->
<mxCell id="kafka" value="<b>[Kafka Topic]</b><br><i>s3.events</i><hr><div align="left">&bull; <b>Payload:</b> S3 Event Log<br>&bull; ObjectCreated / ObjectRemoved<br>&bull; Real-time Stream</div>" style="shape=mxgraph.flowchart.direct_data;whiteSpace=wrap;html=1;fillColor=#f8f9fa;strokeColor=#333333;strokeWidth=1.5;fontSize=11;fontColor=#111111;" vertex="1" parent="1">
<mxGeometry x="40" y="90" width="220" height="100" as="geometry" />
</mxCell>
<!-- Process: Routine Load -->
<mxCell id="routine_load" value="Routine Load<br><font size="1">(Real-time Ingestion)</font>" style="html=1;whiteSpace=wrap;rounded=1;fillColor=#ffffff;strokeColor=#333333;strokeWidth=1.5;fontSize=12;fontColor=#111111;" vertex="1" parent="1">
<mxGeometry x="310" y="120" width="130" height="40" as="geometry" />
</mxCell>
<!-- Table 1: object_current_state -->
<mxCell id="tbl_current_state" value="<b>[StarRocks Table]</b><br><b>object_current_state</b><br><font color="#555555">Primary Key Model</font><hr><div align="left">&bull; <b>PK:</b> object_id (md5)<br>&bull; bucket, object_key, prefix<br>&bull; size_bytes, etag, event_time<br>&bull; <b>__deleted:</b> TINYINT (0/1)<br><hr><i>Role: Real-time S3 Object State Store</i></div>" style="html=1;whiteSpace=wrap;rounded=1;fillColor=#ffffff;strokeColor=#333333;strokeWidth=1.5;fontSize=11;fontColor=#111111;align=center;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="500" y="80" width="260" height="160" as="geometry" />
</mxCell>
<!-- Source 2: MinIO Inventory Parquet -->
<mxCell id="aistor_s3" value="<b>[AIStor S3 Bucket]</b><br><i>Inventory Parquet Files</i><hr><div align="left">&bull; Daily Snapshot Export<br>&bull; Bucket, Key, Size, LastModified</div>" style="shape=mxgraph.flowchart.stored_data;whiteSpace=wrap;html=1;fillColor=#f8f9fa;strokeColor=#333333;strokeWidth=1.5;fontSize=11;fontColor=#111111;" vertex="1" parent="1">
<mxGeometry x="40" y="290" width="220" height="90" as="geometry" />
</mxCell>
<!-- Process: Python Reconcile Pipeline -->
<mxCell id="reconcile_script" value="Reconciliation Script<br><font size="1">(Python + FILES() TVF)</font><hr><div align="left">1. Stage to Temp Table<br>2. Upsert Active Objects<br>3. Soft Delete Missing (`__deleted=1`)</div>" style="html=1;whiteSpace=wrap;rounded=1;fillColor=#ffffff;strokeColor=#333333;strokeWidth=1.5;fontSize=11;fontColor=#111111;" vertex="1" parent="1">
<mxGeometry x="290" y="280" width="170" height="110" as="geometry" />
</mxCell>
<!-- Process: Batch INSERT OVERWRITE -->
<mxCell id="batch_overwrite" value="Daily Batch Update<br><font size="1">(INSERT OVERWRITE)</font>" style="html=1;whiteSpace=wrap;rounded=1;fillColor=#ffffff;strokeColor=#333333;strokeWidth=1.5;fontSize=11;fontColor=#111111;" vertex="1" parent="1">
<mxGeometry x="550" y="290" width="160" height="40" as="geometry" />
</mxCell>
<!-- Table 2: prefix_summary -->
<mxCell id="tbl_prefix_summary" value="<b>[StarRocks Table]</b><br><b>prefix_summary</b><br><font color="#555555">Aggregate Key Model</font><hr><div align="left">&bull; <b>AGG KEY:</b> bucket, prefix<br>&bull; <b>total_object_count:</b> SUM<br>&bull; <b>total_size_bytes:</b> SUM<br>&bull; <b>last_updated:</b> MAX<br><hr><i>Role: Pre-computed Daily Aggregates</i></div>" style="html=1;whiteSpace=wrap;rounded=1;fillColor=#ffffff;strokeColor=#333333;strokeWidth=1.5;fontSize=11;fontColor=#111111;align=center;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="500" y="380" width="260" height="150" as="geometry" />
</mxCell>
<!-- View: v_realtime_prefix_summary -->
<mxCell id="view_hybrid" value="<b>[StarRocks Logical View]</b><br><b>v_realtime_prefix_summary</b><hr><div align="left">&bull; <b>Base Data:</b> prefix_summary (99%)<br>&bull; <b>Delta Data:</b> object_current_state (1%)<br>&nbsp;&nbsp;(Where event_time &gt; last_updated)<br>&bull; FULL OUTER JOIN &amp; COALESCE Aggregation<br><hr><i>Role: Sub-second Real-time Prefix Metrics</i></div>" style="html=1;whiteSpace=wrap;rounded=1;fillColor=#f8f9fa;strokeColor=#333333;strokeWidth=2;fontSize=11;fontColor=#111111;align=center;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="840" y="210" width="280" height="160" as="geometry" />
</mxCell>
<!-- Consumer: API / Dashboard -->
<mxCell id="consumer" value="<b>[External API / Dashboards]</b><br>Grafana, Prometheus, Web Service<br><i>(Fast Response &lt; 10ms)</i>" style="shape=mxgraph.flowchart.display;whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#333333;strokeWidth=1.5;fontSize=11;fontColor=#111111;" vertex="1" parent="1">
<mxGeometry x="880" y="430" width="200" height="70" as="geometry" />
</mxCell>
<!-- Connectors -->
<mxCell id="edge1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#333333;strokeWidth=1.5;" edge="1" parent="1" source="kafka" target="routine_load">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="edge2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#333333;strokeWidth=1.5;" edge="1" parent="1" source="routine_load" target="tbl_current_state">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="edge3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#333333;strokeWidth=1.5;" edge="1" parent="1" source="aistor_s3" target="reconcile_script">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="edge4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#333333;strokeWidth=1.5;" edge="1" parent="1" source="reconcile_script" target="tbl_current_state">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="480" y="335" />
<mxPoint x="480" y="200" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="edge5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#333333;strokeWidth=1.5;" edge="1" parent="1" source="tbl_current_state" target="batch_overwrite">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="edge6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#333333;strokeWidth=1.5;" edge="1" parent="1" source="batch_overwrite" target="tbl_prefix_summary">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="edge7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#333333;strokeWidth=1.5;" edge="1" parent="1" source="tbl_current_state" target="view_hybrid">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="800" y="160" />
<mxPoint x="800" y="260" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="edge8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#333333;strokeWidth=1.5;" edge="1" parent="1" source="tbl_prefix_summary" target="view_hybrid">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="800" y="455" />
<mxPoint x="800" y="310" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="edge9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#333333;strokeWidth=1.5;" edge="1" parent="1" source="view_hybrid" target="consumer">
<mxGeometry relative="1" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
[Kafka (Real-time S3 Events)] ──(Routine Load)──┐
▼
[AIStor Parquet (Daily)] ──(Reconcile Script)──► [object_current_state] (Primary Key)
│ │
│ └──(INSERT OVERWRITE)──► [prefix_summary] (Aggregate Key)
│ │
└───────────────┬─────────────────┘
▼
[v_realtime_prefix_summary] (Hybrid View)
│
▼
[External API / Dashboard]
object_current_state (Primary Key 모델)__deleted) 관리object_id (PK, VARCHAR)bucket / object_key / prefix (VARCHAR)size_bytes (BIGINT)event_time (DATETIME - sequence_col 지정용)__deleted (TINYINT - 0: 존재, 1: 삭제)prefix_summary (Aggregate Key 모델)substring_index) 해체하여 사전 계산해둔 요약 테이블INSERT OVERWRITE 배치 실행bucket / prefix (AGGREGATE KEY)total_object_count (BIGINT SUM)total_size_bytes (BIGINT SUM)last_updated (DATETIME MAX - 배치 수행 스냅샷 시각 저장)v_realtime_prefix_summary (하이브리드 논리 뷰)prefix_summary에서 고속 스캔last_updated 이후에 들어온 1% 미만의 실시간 Kafka 변경분만 object_current_state에서 즉석 계산하여 FULL OUTER JOIN 합산