Skip to content

Commit 6103bbc

Browse files
giedria-hilaly
authored andcommitted
Added data processing example
Rename instance.yaml to instance-template.yaml Added scripts for processing Fixed scripts path Update README.md
1 parent 3201118 commit 6103bbc

File tree

7 files changed

+1032
-0
lines changed

7 files changed

+1032
-0
lines changed

examples/data-processor/README.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Event Driven Architectures with Amazon EKS and AWS Controllers for Kubernetes
2+
3+
This data processing example uses event-driven approach for data ingestion and process orchestration, along with Amazon EMR on EKS for data processing implementation. This example uses [New York City taxi data](https://www.nyc.gov/site/tlc/about/tlc-trip-record-data.page).
4+
## Architecture
5+
6+
Following diagram illustrates flow of the example and services used:
7+
8+
![Architecture diagram](./assets/eks-eda.png)
9+
1. Once data object lands into input bucket on Amazon S3, it sends event to the Amazon EventBridge
10+
2. EventBridge, based on a rule, starts AWS Step Functions workflow execution that orchestrates data processing
11+
3. Workflow creates EMR on EKS virtual cluster and starts Apache Spark job, specifying script in an S3 bucket to be used and data object in the S3 to be processed
12+
4. Spark job reads the newly arrived data from S3, runs the processing, and saves output data to a S3 bucket.
13+
5. In parallel to the data processing by Spark, Step Functions workflow copies incoming data file to a data lake (another S3 bucket)
14+
6. Once Spark finishes data processing, workflow reads results from the S3 bucket and puts them to an Amazon DynamoDB database
15+
7. Workflow sends event to the EventBridge custom bus, notifying all subscribers that data processing task finished
16+
8. Amazon Simple Notification Service (SNS) receives event from the event bus and sends e-mail message to the subscribers
17+
18+
Following diagram shows Step Functions workflow:
19+
![StepFunctions workflow](./assets/stepfunctions_graph.png)
20+
21+
## Prerequisites
22+
EKS cluster with EMR on EKS deployed and IRSA configured. Following steps are based on [AWS ACK tutorial instructions](https://aws-controllers-k8s.github.io/community/docs/tutorials/emr-on-eks-example/)
23+
24+
Install kro in the cluster created in the previous step following [instructions](https://kro.run/docs/getting-started/Installation)
25+
26+
## Create instance
27+
28+
Create kro ResourceGroup for the data processor:
29+
```shell
30+
kubectl apply -f eda-eks-data-processor.yaml
31+
```
32+
33+
Create instance of the data processor
34+
35+
Set workload name (it will be used as a prefix for the stack components):
36+
```shell
37+
export WORKLOAD_NAME="eda-eks-demo"
38+
```
39+
40+
Following steps assume that input, scripts and data lake buckets are the same one. Resource group creates a new input bucket only. If you use the same name for scripts and lake, it will use input bucket for all purposes. Specify different bucket name for the scripts library and data lake if necessary.
41+
42+
```shell
43+
export INPUT_BUCKET_NAME="${WORKLOAD_NAME}-bucket"
44+
export SCRIPTS_BUCKET_NAME="${WORKLOAD_NAME}-bucket"
45+
export LAKE_BUCKET_NAME="${WORKLOAD_NAME}-bucket"
46+
```
47+
48+
```shell
49+
envsubst < "instance-template.yaml" > "instance.yaml"
50+
```
51+
Check that the instance definition populated with values. Update prefix, API name or description values in the definition if desired.
52+
```shell
53+
cat instance.yaml
54+
```
55+
56+
## Deploy instance
57+
58+
Apply the instance definition:
59+
```shell
60+
kubectl apply -f instance.yaml
61+
```
62+
63+
64+
## Post-deployment steps
65+
### S3 event notification configuration update
66+
Check newly created bucket name:
67+
```shell
68+
export BUCKET_NAME=$(kubectl get bucket.s3.services.k8s.aws -o jsonpath='{.items..metadata.name}' --namespace $WORKLOAD_NAME | grep $WORKLOAD_NAME)
69+
```
70+
This step is required until ACK missing feature is implemented.
71+
```bash
72+
# Enable EventBridge notifications as ACK does not support it at this time and they are not enabled by default
73+
aws s3api put-bucket-notification-configuration --bucket $BUCKET_NAME --notification-configuration='{ "EventBridgeConfiguration": {} }'
74+
```
75+
### Spark data processing script upload
76+
```bash
77+
aws s3 cp ./scripts s3://$BUCKET_NAME/scripts --recursive
78+
```
79+
80+
## Test
81+
82+
List all resources in the stack namespace (it will take some time to get all results):
83+
```shell
84+
kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --ignore-not-found -n $WORKLOAD_NAME
85+
```
86+
Copy sample data for processing (for example `yellow_tripdata_2024-05.parquet`):
87+
```shell
88+
aws s3 cp <your-sample-data-file-folder>/yellow_tripdata_2024-05.parquet s3://$BUCKET_NAME/input/yellow_tripdata_2024-05.parquet
89+
```
90+
91+
## Clean up
92+
93+
Delete S3 bucket content:
94+
```shell
95+
aws s3 rm --recursive s3://$BUCKET_NAME
96+
```
97+
Delete instance and resource group:
98+
```shell
99+
kubectl delete -f instance.yaml
100+
kubectl delete -f eda-eks-data-processor.yaml
101+
```
102+
103+
Note: You may need to patch resource finalizer in case deletion of the resource hangs. For example, following command patches SNS subscription in `eda-eks-demo` namespace (unconfirmed subscriptions cannot be deleted (they are cleaned up automatically after 48hrs) and prevent resource from deletion):
104+
```shell
105+
kubectl patch subscription.sns.services.k8s.aws/eda-eks-demo-notifications-subscription -p '{"metadata":{"finalizers":[]}}' --type=merge --namespace eda-eks-demo
106+
```
107+
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<mxfile host="drawio.corp.amazon.com" modified="2024-09-04T19:22:20.354Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:129.0) Gecko/20100101 Firefox/129.0" etag="LsC5K9HA4w_bQBm9TeA2" version="21.7.4" type="device">
2+
<diagram name="Page-1" id="sDRVptemRm56i0psgaTi">
3+
<mxGraphModel dx="1056" dy="973" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
4+
<root>
5+
<mxCell id="0" />
6+
<mxCell id="1" parent="0" />
7+
<mxCell id="cbFFLlK-bVltba2RXdJL-4" value="" style="outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#8C4FFF;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.data_lake_resource_icon;" parent="1" vertex="1">
8+
<mxGeometry x="530" y="328" width="78" height="78" as="geometry" />
9+
</mxCell>
10+
<mxCell id="cbFFLlK-bVltba2RXdJL-28" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="cbFFLlK-bVltba2RXdJL-9" target="cbFFLlK-bVltba2RXdJL-27" edge="1">
11+
<mxGeometry relative="1" as="geometry" />
12+
</mxCell>
13+
<mxCell id="cbFFLlK-bVltba2RXdJL-11" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="cbFFLlK-bVltba2RXdJL-6" target="cbFFLlK-bVltba2RXdJL-8" edge="1">
14+
<mxGeometry relative="1" as="geometry" />
15+
</mxCell>
16+
<mxCell id="cbFFLlK-bVltba2RXdJL-6" value="" style="points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#7AA116;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.s3;" parent="1" vertex="1">
17+
<mxGeometry x="330" y="60" width="78" height="78" as="geometry" />
18+
</mxCell>
19+
<mxCell id="cbFFLlK-bVltba2RXdJL-15" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="cbFFLlK-bVltba2RXdJL-8" target="cbFFLlK-bVltba2RXdJL-13" edge="1">
20+
<mxGeometry relative="1" as="geometry">
21+
<mxPoint x="369" y="388" as="targetPoint" />
22+
</mxGeometry>
23+
</mxCell>
24+
<mxCell id="cbFFLlK-bVltba2RXdJL-8" value="" style="points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#E7157B;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.eventbridge;" parent="1" vertex="1">
25+
<mxGeometry x="330" y="230" width="78" height="78" as="geometry" />
26+
</mxCell>
27+
<mxCell id="cbFFLlK-bVltba2RXdJL-9" value="" style="outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#E7157B;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.eventbridge_custom_event_bus_resource;" parent="1" vertex="1">
28+
<mxGeometry x="330" y="590" width="78" height="69" as="geometry" />
29+
</mxCell>
30+
<mxCell id="cbFFLlK-bVltba2RXdJL-10" value="" style="outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#E7157B;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.event;" parent="1" vertex="1">
31+
<mxGeometry x="330" y="170" width="30" height="30" as="geometry" />
32+
</mxCell>
33+
<mxCell id="cbFFLlK-bVltba2RXdJL-21" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="cbFFLlK-bVltba2RXdJL-13" target="cbFFLlK-bVltba2RXdJL-4" edge="1">
34+
<mxGeometry relative="1" as="geometry" />
35+
</mxCell>
36+
<mxCell id="cbFFLlK-bVltba2RXdJL-52" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="cbFFLlK-bVltba2RXdJL-13" target="cbFFLlK-bVltba2RXdJL-9" edge="1">
37+
<mxGeometry relative="1" as="geometry" />
38+
</mxCell>
39+
<mxCell id="cbFFLlK-bVltba2RXdJL-13" value="AWS Step Functions workflow" style="points=[[0,0],[0.25,0],[0.5,0],[0.75,0],[1,0],[1,0.25],[1,0.5],[1,0.75],[1,1],[0.75,1],[0.5,1],[0.25,1],[0,1],[0,0.75],[0,0.5],[0,0.25]];outlineConnect=0;gradientColor=none;html=1;whiteSpace=wrap;fontSize=12;fontStyle=0;container=1;pointerEvents=0;collapsible=0;recursiveResize=0;shape=mxgraph.aws4.group;grIcon=mxgraph.aws4.group_aws_step_functions_workflow;strokeColor=#CD2264;fillColor=none;verticalAlign=top;align=left;spacingLeft=30;fontColor=#CD2264;dashed=0;" parent="1" vertex="1">
40+
<mxGeometry x="304" y="390" width="130" height="130" as="geometry" />
41+
</mxCell>
42+
<mxCell id="cbFFLlK-bVltba2RXdJL-18" value="" style="group;" parent="1" vertex="1" connectable="0">
43+
<mxGeometry x="30" y="120" width="250" height="256" as="geometry" />
44+
</mxCell>
45+
<mxCell id="cbFFLlK-bVltba2RXdJL-17" value="" style="fillColor=#EFF0F3;strokeColor=none;dashed=0;verticalAlign=top;fontStyle=0;fontColor=#232F3D;whiteSpace=wrap;html=1;" parent="cbFFLlK-bVltba2RXdJL-18" vertex="1">
46+
<mxGeometry width="250" height="256" as="geometry" />
47+
</mxCell>
48+
<mxCell id="cbFFLlK-bVltba2RXdJL-1" value="" style="points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#ED7100;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.eks;" parent="cbFFLlK-bVltba2RXdJL-18" vertex="1">
49+
<mxGeometry width="78" height="78" as="geometry" />
50+
</mxCell>
51+
<mxCell id="RE9Nt39qmt5__te_f2S3-1" value="Amazon EKS" style="text;whiteSpace=wrap;html=1;" vertex="1" parent="cbFFLlK-bVltba2RXdJL-18">
52+
<mxGeometry y="78" width="80" height="10" as="geometry" />
53+
</mxCell>
54+
<mxCell id="RE9Nt39qmt5__te_f2S3-2" value="Amazon EMR on EKS" style="text;whiteSpace=wrap;html=1;" vertex="1" parent="cbFFLlK-bVltba2RXdJL-18">
55+
<mxGeometry x="80" y="190" width="130" height="20" as="geometry" />
56+
</mxCell>
57+
<mxCell id="cbFFLlK-bVltba2RXdJL-44" value="3" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeWidth=2;fontFamily=Tahoma;spacingBottom=4;spacingRight=2;strokeColor=#d3d3d3;" parent="cbFFLlK-bVltba2RXdJL-18" vertex="1">
58+
<mxGeometry x="150" y="220" width="20" height="20" as="geometry" />
59+
</mxCell>
60+
<mxCell id="cbFFLlK-bVltba2RXdJL-2" value="" style="points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#8C4FFF;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.emr;" parent="1" vertex="1">
61+
<mxGeometry x="136" y="230" width="78" height="78" as="geometry" />
62+
</mxCell>
63+
<mxCell id="cbFFLlK-bVltba2RXdJL-19" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="cbFFLlK-bVltba2RXdJL-13" target="cbFFLlK-bVltba2RXdJL-2" edge="1">
64+
<mxGeometry relative="1" as="geometry">
65+
<mxPoint x="300" y="460" as="sourcePoint" />
66+
</mxGeometry>
67+
</mxCell>
68+
<mxCell id="cbFFLlK-bVltba2RXdJL-20" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=classic;startFill=1;" parent="1" source="cbFFLlK-bVltba2RXdJL-6" target="cbFFLlK-bVltba2RXdJL-2" edge="1">
69+
<mxGeometry relative="1" as="geometry" />
70+
</mxCell>
71+
<mxCell id="cbFFLlK-bVltba2RXdJL-25" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="cbFFLlK-bVltba2RXdJL-13" target="cbFFLlK-bVltba2RXdJL-24" edge="1">
72+
<mxGeometry relative="1" as="geometry">
73+
<mxPoint x="304" y="455" as="sourcePoint" />
74+
<mxPoint x="175" y="308" as="targetPoint" />
75+
</mxGeometry>
76+
</mxCell>
77+
<mxCell id="cbFFLlK-bVltba2RXdJL-24" value="" style="points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#C925D1;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.dynamodb;" parent="1" vertex="1">
78+
<mxGeometry x="136" y="520" width="78" height="78" as="geometry" />
79+
</mxCell>
80+
<mxCell id="cbFFLlK-bVltba2RXdJL-27" value="" style="points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;fillColor=#E7157B;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.sns;" parent="1" vertex="1">
81+
<mxGeometry x="330" y="740" width="78" height="78" as="geometry" />
82+
</mxCell>
83+
<mxCell id="cbFFLlK-bVltba2RXdJL-38" value="" style="outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#E7157B;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.event;" parent="1" vertex="1">
84+
<mxGeometry x="340" y="525" width="30" height="30" as="geometry" />
85+
</mxCell>
86+
<mxCell id="cbFFLlK-bVltba2RXdJL-41" value="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeWidth=2;fontFamily=Tahoma;spacingBottom=4;spacingRight=2;strokeColor=#d3d3d3;" parent="1" vertex="1">
87+
<mxGeometry x="380" y="200" width="20" height="20" as="geometry" />
88+
</mxCell>
89+
<mxCell id="cbFFLlK-bVltba2RXdJL-43" value="2" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeWidth=2;fontFamily=Tahoma;spacingBottom=4;spacingRight=2;strokeColor=#d3d3d3;" parent="1" vertex="1">
90+
<mxGeometry x="380" y="356" width="20" height="20" as="geometry" />
91+
</mxCell>
92+
<mxCell id="cbFFLlK-bVltba2RXdJL-45" value="4" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeWidth=2;fontFamily=Tahoma;spacingBottom=4;spacingRight=2;strokeColor=#d3d3d3;" parent="1" vertex="1">
93+
<mxGeometry x="280" y="70" width="20" height="20" as="geometry" />
94+
</mxCell>
95+
<mxCell id="cbFFLlK-bVltba2RXdJL-46" value="5" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeWidth=2;fontFamily=Tahoma;spacingBottom=4;spacingRight=2;strokeColor=#d3d3d3;" parent="1" vertex="1">
96+
<mxGeometry x="490" y="376" width="20" height="20" as="geometry" />
97+
</mxCell>
98+
<mxCell id="cbFFLlK-bVltba2RXdJL-47" value="6" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeWidth=2;fontFamily=Tahoma;spacingBottom=4;spacingRight=2;strokeColor=#d3d3d3;" parent="1" vertex="1">
99+
<mxGeometry x="234" y="535" width="20" height="20" as="geometry" />
100+
</mxCell>
101+
<mxCell id="cbFFLlK-bVltba2RXdJL-49" value="7" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeWidth=2;fontFamily=Tahoma;spacingBottom=4;spacingRight=2;strokeColor=#d3d3d3;" parent="1" vertex="1">
102+
<mxGeometry x="380" y="570" width="20" height="20" as="geometry" />
103+
</mxCell>
104+
<mxCell id="cbFFLlK-bVltba2RXdJL-51" value="8" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeWidth=2;fontFamily=Tahoma;spacingBottom=4;spacingRight=2;strokeColor=#d3d3d3;" parent="1" vertex="1">
105+
<mxGeometry x="380" y="710" width="20" height="20" as="geometry" />
106+
</mxCell>
107+
<mxCell id="RE9Nt39qmt5__te_f2S3-3" value="Amazon S3" style="text;whiteSpace=wrap;html=1;" vertex="1" parent="1">
108+
<mxGeometry x="338" y="138" width="70" height="20" as="geometry" />
109+
</mxCell>
110+
<mxCell id="RE9Nt39qmt5__te_f2S3-4" value="Amazon EventBridge" style="text;whiteSpace=wrap;html=1;" vertex="1" parent="1">
111+
<mxGeometry x="310" y="308" width="130" height="20" as="geometry" />
112+
</mxCell>
113+
<mxCell id="RE9Nt39qmt5__te_f2S3-8" value="Amazon DynamoDB" style="text;whiteSpace=wrap;html=1;" vertex="1" parent="1">
114+
<mxGeometry x="115" y="598" width="120" height="20" as="geometry" />
115+
</mxCell>
116+
<mxCell id="RE9Nt39qmt5__te_f2S3-9" value="Amazon SNS" style="text;whiteSpace=wrap;html=1;" vertex="1" parent="1">
117+
<mxGeometry x="330" y="818" width="80" height="20" as="geometry" />
118+
</mxCell>
119+
<mxCell id="RE9Nt39qmt5__te_f2S3-10" value="Amazon EventBridge&lt;br&gt;Custom Bus" style="text;whiteSpace=wrap;html=1;align=center;" vertex="1" parent="1">
120+
<mxGeometry x="310" y="650" width="120" height="40" as="geometry" />
121+
</mxCell>
122+
<mxCell id="RE9Nt39qmt5__te_f2S3-12" value="Amazon S3&lt;br&gt;(Data Lake)" style="text;whiteSpace=wrap;html=1;" vertex="1" parent="1">
123+
<mxGeometry x="530" y="406" width="70" height="20" as="geometry" />
124+
</mxCell>
125+
</root>
126+
</mxGraphModel>
127+
</diagram>
128+
</mxfile>
96.6 KB
Loading
121 KB
Loading

0 commit comments

Comments
 (0)