├── .gitbook └── assets │ ├── 1Qb5RmfVt6XYVYGonYoBiuA.png │ ├── Databricks Shell - Details for Query 48 (1) (1).png │ ├── Databricks Shell - Details for Query 48 (1).png │ ├── Databricks Shell - Details for Query 48 (2).png │ ├── Databricks Shell - Details for Query 48.png │ ├── broadcast.gif │ ├── image (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (1) (1) (1) (1) (1) (1) (1).png │ ├── image (1) (1) (1) (1) (1) (1).png │ ├── image (1) (1) (1) (1) (1).png │ ├── image (1) (1) (1) (1).png │ ├── image (1) (1) (1).png │ ├── image (1) (1).png │ ├── image (1).png │ ├── image (10) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (10) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (10) (1) (1) (1) (1) (1) (1).png │ ├── image (10) (1) (1) (1) (1) (1).png │ ├── image (10) (1) (1) (1) (1).png │ ├── image (10) (1) (1) (1).png │ ├── image (10) (1) (1).png │ ├── image (10) (1).png │ ├── image (10).png │ ├── image (11) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (11) (1) (1) (1) (1) (1) (1).png │ ├── image (11) (1) (1) (1) (1) (1).png │ ├── image (11) (1) (1) (1) (1).png │ ├── image (11) (1) (1) (1).png │ ├── image (11) (1) (1).png │ ├── image (11) (1).png │ ├── image (11).png │ ├── image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (12) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (12) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (12) (1) (1) (1) (1) (1) (1).png │ ├── image (12) (1) (1) (1) (1) (1).png │ ├── image (12) (1) (1) (1) (1).png │ ├── image (12) (1) (1) (1).png │ ├── image (12) (1) (1).png │ ├── image (12) (1).png │ ├── image (12).png │ ├── image (13) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (13) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (13) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (13) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (13) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (13) (1) (1) (1) (1) (1) (1).png │ ├── image (13) (1) (1) (1) (1) (1).png │ ├── image (13) (1) (1) (1) (1).png │ ├── image (13) (1) (1) (1).png │ ├── image (13) (1) (1).png │ ├── image (13) (1).png │ ├── image (13).png │ ├── image (14) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (14) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (14) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (14) (1) (1) (1) (1) (1) (1).png │ ├── image (14) (1) (1) (1) (1) (1).png │ ├── image (14) (1) (1) (1) (1).png │ ├── image (14) (1) (1) (1).png │ ├── image (14) (1) (1).png │ ├── image (14) (1).png │ ├── image (14).png │ ├── image (15) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (15) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (15) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (15) (1) (1) (1) (1) (1) (1).png │ ├── image (15) (1) (1) (1) (1) (1).png │ ├── image (15) (1) (1) (1) (1).png │ ├── image (15) (1) (1) (1).png │ ├── image (15) (1) (1).png │ ├── image (15) (1).png │ ├── image (15).png │ ├── image (16) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (16) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (16) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (16) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (16) (1) (1) (1) (1) (1) (1).png │ ├── image (16) (1) (1) (1) (1) (1).png │ ├── image (16) (1) (1) (1) (1).png │ ├── image (16) (1) (1) (1).png │ ├── image (16) (1) (1).png │ ├── image (16) (1).png │ ├── image (16).png │ ├── image (17) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (17) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (17) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (17) (1) (1) (1) (1) (1) (1).png │ ├── image (17) (1) (1) (1) (1) (1).png │ ├── image (17) (1) (1) (1) (1).png │ ├── image (17) (1) (1) (1).png │ ├── image (17) (1) (1).png │ ├── image (17) (1).png │ ├── image (17).png │ ├── image (18) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (18) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (18) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (18) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (18) (1) (1) (1) (1) (1) (1).png │ ├── image (18) (1) (1) (1) (1) (1).png │ ├── image (18) (1) (1) (1) (1).png │ ├── image (18) (1) (1) (1).png │ ├── image (18) (1) (1).png │ ├── image (18) (1).png │ ├── image (18).png │ ├── image (19) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (19) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (19) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (19) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (19) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (19) (1) (1) (1) (1) (1) (1).png │ ├── image (19) (1) (1) (1) (1) (1).png │ ├── image (19) (1) (1) (1) (1).png │ ├── image (19) (1) (1) (1).png │ ├── image (19) (1) (1).png │ ├── image (19) (1).png │ ├── image (19).png │ ├── image (2) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (2) (1) (1) (1) (1) (1) (1).png │ ├── image (2) (1) (1) (1) (1) (1).png │ ├── image (2) (1) (1) (1) (1).png │ ├── image (2) (1) (1) (1).png │ ├── image (2) (1) (1).png │ ├── image (2) (1).png │ ├── image (2).png │ ├── image (20) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (20) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (20) (1) (1) (1) (1) (1) (1).png │ ├── image (20) (1) (1) (1) (1) (1).png │ ├── image (20) (1) (1) (1) (1).png │ ├── image (20) (1) (1) (1).png │ ├── image (20) (1) (1).png │ ├── image (20) (1).png │ ├── image (20).png │ ├── image (21) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (21) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (21) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (21) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (21) (1) (1) (1) (1) (1) (1).png │ ├── image (21) (1) (1) (1) (1) (1).png │ ├── image (21) (1) (1) (1) (1).png │ ├── image (21) (1) (1) (1).png │ ├── image (21) (1) (1).png │ ├── image (21) (1).png │ ├── image (21).png │ ├── image (22) (1) (1) (1) (1) (1) (1).png │ ├── image (22) (1) (1) (1) (1) (1).png │ ├── image (22) (1) (1) (1) (1).png │ ├── image (22) (1) (1) (1).png │ ├── image (22) (1) (1).png │ ├── image (22) (1).png │ ├── image (22).png │ ├── image (23) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (23) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (23) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (23) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (23) (1) (1) (1) (1) (1) (1).png │ ├── image (23) (1) (1) (1) (1) (1).png │ ├── image (23) (1) (1) (1) (1).png │ ├── image (23) (1) (1) (1).png │ ├── image (23) (1) (1).png │ ├── image (23) (1).png │ ├── image (23).png │ ├── image (24) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (24) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (24) (1) (1) (1) (1) (1) (1).png │ ├── image (24) (1) (1) (1) (1) (1).png │ ├── image (24) (1) (1) (1) (1).png │ ├── image (24) (1) (1) (1).png │ ├── image (24) (1) (1).png │ ├── image (24) (1).png │ ├── image (24).png │ ├── image (25) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (25) (1) (1) (1) (1) (1) (1).png │ ├── image (25) (1) (1) (1) (1) (1).png │ ├── image (25) (1) (1) (1) (1).png │ ├── image (25) (1) (1) (1).png │ ├── image (25) (1) (1).png │ ├── image (25) (1).png │ ├── image (25).png │ ├── image (26) (1) (1) (1) (1) (1) (1).png │ ├── image (26) (1) (1) (1) (1) (1).png │ ├── image (26) (1) (1) (1) (1).png │ ├── image (26) (1) (1) (1).png │ ├── image (26) (1) (1).png │ ├── image (26) (1).png │ ├── image (26).png │ ├── image (27) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (27) (1) (1) (1) (1) (1) (1).png │ ├── image (27) (1) (1) (1) (1) (1).png │ ├── image (27) (1) (1) (1) (1).png │ ├── image (27) (1) (1) (1).png │ ├── image (27) (1) (1).png │ ├── image (27) (1).png │ ├── image (27).png │ ├── image (28) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (28) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (28) (1) (1) (1) (1) (1) (1).png │ ├── image (28) (1) (1) (1) (1) (1).png │ ├── image (28) (1) (1) (1) (1).png │ ├── image (28) (1) (1) (1).png │ ├── image (28) (1) (1).png │ ├── image (28) (1).png │ ├── image (28).png │ ├── image (29) (1) (1) (1) (1) (1) (1).png │ ├── image (29) (1) (1) (1) (1) (1).png │ ├── image (29) (1) (1) (1) (1).png │ ├── image (29) (1) (1) (1).png │ ├── image (29) (1) (1).png │ ├── image (29) (1).png │ ├── image (29).png │ ├── image (3) (1) (1) (1) (1) (1).png │ ├── image (3) (1) (1) (1) (1).png │ ├── image (3) (1) (1) (1).png │ ├── image (3) (1) (1).png │ ├── image (3) (1).png │ ├── image (3).png │ ├── image (30) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (30) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (30) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (30) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (30) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (30) (1) (1) (1) (1) (1) (1).png │ ├── image (30) (1) (1) (1) (1) (1).png │ ├── image (30) (1) (1) (1) (1).png │ ├── image (30) (1) (1) (1).png │ ├── image (30) (1) (1).png │ ├── image (30) (1).png │ ├── image (30).png │ ├── image (31) (1) (1) (1) (1) (1) (1).png │ ├── image (31) (1) (1) (1) (1) (1).png │ ├── image (31) (1) (1) (1) (1).png │ ├── image (31) (1) (1) (1).png │ ├── image (31) (1) (1).png │ ├── image (31) (1).png │ ├── image (31).png │ ├── image (32) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (32) (1) (1) (1) (1) (1) (1).png │ ├── image (32) (1) (1) (1) (1) (1).png │ ├── image (32) (1) (1) (1) (1).png │ ├── image (32) (1) (1) (1).png │ ├── image (32) (1) (1).png │ ├── image (32) (1).png │ ├── image (32).png │ ├── image (33) (1) (1) (1) (1) (1) (1).png │ ├── image (33) (1) (1) (1) (1) (1).png │ ├── image (33) (1) (1) (1) (1).png │ ├── image (33) (1) (1) (1).png │ ├── image (33) (1) (1).png │ ├── image (33) (1).png │ ├── image (33).png │ ├── image (34) (1) (1) (1) (1) (1) (1).png │ ├── image (34) (1) (1) (1) (1) (1).png │ ├── image (34) (1) (1) (1) (1).png │ ├── image (34) (1) (1) (1).png │ ├── image (34) (1) (1).png │ ├── image (34) (1).png │ ├── image (34).png │ ├── image (35) (1) (1) (1) (1) (1).png │ ├── image (35) (1) (1) (1) (1).png │ ├── image (35) (1) (1) (1).png │ ├── image (35) (1) (1).png │ ├── image (35) (1).png │ ├── image (35).png │ ├── image (36) (1) (1) (1) (1) (1).png │ ├── image (36) (1) (1) (1) (1).png │ ├── image (36) (1) (1) (1).png │ ├── image (36) (1) (1).png │ ├── image (36) (1).png │ ├── image (36).png │ ├── image (37) (1).png │ ├── image (37).png │ ├── image (38).png │ ├── image (39).png │ ├── image (4) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (4) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (4) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (4) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (4) (1) (1) (1) (1) (1) (1).png │ ├── image (4) (1) (1) (1) (1) (1).png │ ├── image (4) (1) (1) (1) (1).png │ ├── image (4) (1) (1) (1).png │ ├── image (4) (1) (1).png │ ├── image (4) (1).png │ ├── image (4).png │ ├── image (40).png │ ├── image (41).png │ ├── image (42).png │ ├── image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (5) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (5) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (5) (1) (1) (1) (1) (1) (1).png │ ├── image (5) (1) (1) (1) (1) (1).png │ ├── image (5) (1) (1) (1) (1).png │ ├── image (5) (1) (1) (1).png │ ├── image (5) (1) (1).png │ ├── image (5) (1).png │ ├── image (5).png │ ├── image (6) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (6) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (6) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (6) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (6) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (6) (1) (1) (1) (1) (1) (1).png │ ├── image (6) (1) (1) (1) (1) (1).png │ ├── image (6) (1) (1) (1) (1).png │ ├── image (6) (1) (1) (1).png │ ├── image (6) (1) (1).png │ ├── image (6) (1).png │ ├── image (6).png │ ├── image (7) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (7) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (7) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (7) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (7) (1) (1) (1) (1) (1) (1).png │ ├── image (7) (1) (1) (1) (1) (1).png │ ├── image (7) (1) (1) (1) (1).png │ ├── image (7) (1) (1) (1).png │ ├── image (7) (1) (1).png │ ├── image (7) (1).png │ ├── image (7).png │ ├── image (8) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (8) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (8) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (8) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (8) (1) (1) (1) (1) (1) (1).png │ ├── image (8) (1) (1) (1) (1) (1).png │ ├── image (8) (1) (1) (1) (1).png │ ├── image (8) (1) (1) (1).png │ ├── image (8) (1) (1).png │ ├── image (8) (1).png │ ├── image (8).png │ ├── image (9) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (9) (1) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (9) (1) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (9) (1) (1) (1) (1) (1) (1) (1).png │ ├── image (9) (1) (1) (1) (1) (1) (1).png │ ├── image (9) (1) (1) (1) (1) (1).png │ ├── image (9) (1) (1) (1) (1).png │ ├── image (9) (1) (1) (1).png │ ├── image (9) (1) (1).png │ ├── image (9) (1).png │ ├── image (9).png │ ├── image.png │ └── shuffle.gif ├── 01-data-infra ├── 1.1.md ├── 1.2-processing.md ├── 1.2.md ├── 1.3-storage.md └── 1.3.md ├── 02-processing ├── 2.1.md ├── 2.1 │ ├── README.md │ └── untitled.md ├── 2.2-batch.md ├── 2.2-batch │ ├── 2.1.1-spark-intro.md │ ├── 2.1.2-spark-architecture.md │ ├── 2.1.3-spark-concept.md │ ├── 2.1.4-spark-architecture.md │ ├── 2.1.5-spark-memory-management.md │ ├── 2.1.x-spark-cache.md │ ├── 2.1.x-spark-dataframe.md │ ├── 2.1.x-spark-join.md │ ├── 2.1.x-spark-persistence.md │ ├── 2.1.x-spark-sql-and-table.md │ ├── 2.2.2-spark-versions.md │ └── README.md ├── 2.3-workflow.md └── 2.4-stream │ ├── 2.4.1-kafka-intro.md │ ├── 2.4.2-kafka-advanced.md │ ├── 2.4.3-spark-streaming.md │ ├── 2.4.4-streaming-window.md │ ├── 2.4.5-streaming-state.md │ ├── 2.4.6-streaming-sink.md │ └── README.md ├── 04-data-storage ├── 4.2.md ├── 4.3-rdb-mysql.md ├── 4.4.md ├── 4.5-kv-storage-dynamodb.md ├── 4.6-druid.md └── untitled │ ├── 4.1-kafka-concept.md │ ├── 4.2-kafka-advanced.md │ ├── 4.3-kafka-versions.md │ └── README.md ├── 05-data-application ├── 5.2.md ├── 5.3.md ├── 5.4.md └── untitled.md ├── 08-case-study ├── week-1-data-pipeline.md ├── week-2-emr-and-kubernetes.md ├── week-3-metastore.md ├── week-4-kv-and-delta-storage.md ├── week-5-kafka-rebalancing.md └── week-6-ml-pipeline.md ├── 09-installation ├── druid.md ├── dynamodb.md ├── elasticsearch.md ├── flink.md ├── kafka.md ├── mysql.md ├── presto.md └── spark │ ├── README.md │ ├── spark-databricks-saas.md │ ├── spark-emr.md │ ├── spark-kubernetes.md │ ├── spark-local-jupyter.md │ └── spark-local-shell.md ├── README.md ├── SUMMARY.md └── undefined.md /.gitbook/assets/1Qb5RmfVt6XYVYGonYoBiuA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/1Qb5RmfVt6XYVYGonYoBiuA.png -------------------------------------------------------------------------------- /.gitbook/assets/Databricks Shell - Details for Query 48 (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/Databricks Shell - Details for Query 48 (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/Databricks Shell - Details for Query 48 (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/Databricks Shell - Details for Query 48 (1).png -------------------------------------------------------------------------------- /.gitbook/assets/Databricks Shell - Details for Query 48 (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/Databricks Shell - Details for Query 48 (2).png -------------------------------------------------------------------------------- /.gitbook/assets/Databricks Shell - Details for Query 48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/Databricks Shell - Details for Query 48.png -------------------------------------------------------------------------------- /.gitbook/assets/broadcast.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/broadcast.gif -------------------------------------------------------------------------------- /.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (10) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (10) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (10) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (10) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (10) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (10) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (10) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (10) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (10).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (10).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (11) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (11) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (11) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (11) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (11) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (11) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (11) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (11).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (11).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (12).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (12).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (13).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (13).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (14) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (14) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (14) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (14) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (14) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (14) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (14) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (14) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (14) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (14).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (14).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (15) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (15) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (15) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (15) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (15) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (15) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (15) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (15) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (15) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (15).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (15).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (16).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (16).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (17) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (17) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (17) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (17) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (17) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (17) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (17) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (17) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (17) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (17).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (17).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (18).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (18).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (19).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (19).png -------------------------------------------------------------------------------- /.gitbook/assets/image (2) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (2) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (2) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (2) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (2) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (2) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (2) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (2) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (2) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (2) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (2) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (2) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (2) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (2) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (2).png -------------------------------------------------------------------------------- /.gitbook/assets/image (20) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (20) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (20) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (20) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (20) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (20) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (20) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (20) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (20) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (20) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (20) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (20) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (20) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (20) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (20) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (20) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (20).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (20).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (21).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (21).png -------------------------------------------------------------------------------- /.gitbook/assets/image (22) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (22) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (22) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (22) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (22) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (22) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (22) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (22) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (22) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (22) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (22) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (22) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (22).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (22).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (23).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (23).png -------------------------------------------------------------------------------- /.gitbook/assets/image (24) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (24) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (24) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (24) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (24) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (24) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (24) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (24) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (24) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (24) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (24) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (24) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (24) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (24) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (24) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (24) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (24).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (24).png -------------------------------------------------------------------------------- /.gitbook/assets/image (25) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (25) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (25) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (25) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (25) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (25) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (25) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (25) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (25) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (25) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (25) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (25) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (25) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (25) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (25).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (25).png -------------------------------------------------------------------------------- /.gitbook/assets/image (26) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (26) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (26) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (26) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (26) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (26) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (26) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (26) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (26) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (26) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (26) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (26) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (26).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (26).png -------------------------------------------------------------------------------- /.gitbook/assets/image (27) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (27) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (27) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (27) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (27) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (27) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (27) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (27) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (27) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (27) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (27) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (27) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (27) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (27) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (27).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (27).png -------------------------------------------------------------------------------- /.gitbook/assets/image (28) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (28) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (28) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (28) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (28) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (28) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (28) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (28) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (28) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (28) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (28) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (28) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (28) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (28) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (28) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (28) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (28).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (28).png -------------------------------------------------------------------------------- /.gitbook/assets/image (29) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (29) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (29) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (29) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (29) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (29) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (29) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (29) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (29) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (29) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (29) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (29) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (29).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (29).png -------------------------------------------------------------------------------- /.gitbook/assets/image (3) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (3) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (3) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (3) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (3) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (3) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (3) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (3) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (3) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (3) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (3).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (3).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (30).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (30).png -------------------------------------------------------------------------------- /.gitbook/assets/image (31) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (31) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (31) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (31) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (31) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (31) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (31) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (31) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (31) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (31) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (31) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (31) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (31).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (31).png -------------------------------------------------------------------------------- /.gitbook/assets/image (32) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (32) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (32) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (32) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (32) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (32) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (32) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (32) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (32) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (32) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (32) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (32) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (32) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (32) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (32).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (32).png -------------------------------------------------------------------------------- /.gitbook/assets/image (33) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (33) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (33) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (33) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (33) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (33) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (33) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (33) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (33) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (33) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (33) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (33) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (33).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (33).png -------------------------------------------------------------------------------- /.gitbook/assets/image (34) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (34) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (34) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (34) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (34) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (34) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (34) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (34) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (34) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (34) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (34) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (34) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (34).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (34).png -------------------------------------------------------------------------------- /.gitbook/assets/image (35) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (35) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (35) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (35) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (35) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (35) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (35) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (35) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (35) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (35) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (35).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (35).png -------------------------------------------------------------------------------- /.gitbook/assets/image (36) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (36) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (36) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (36) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (36) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (36) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (36) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (36) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (36) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (36) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (36).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (36).png -------------------------------------------------------------------------------- /.gitbook/assets/image (37) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (37) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (37).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (37).png -------------------------------------------------------------------------------- /.gitbook/assets/image (38).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (38).png -------------------------------------------------------------------------------- /.gitbook/assets/image (39).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (39).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (4).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (4).png -------------------------------------------------------------------------------- /.gitbook/assets/image (40).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (40).png -------------------------------------------------------------------------------- /.gitbook/assets/image (41).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (41).png -------------------------------------------------------------------------------- /.gitbook/assets/image (42).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (42).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (5).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (5).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (6).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (6).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (7).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (7).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (8).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (8).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9) (1) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9) (1) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9) (1) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9) (1) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9) (1) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9) (1) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9) (1) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9) (1) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9) (1) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9) (1) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9) (1) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9) (1) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9) (1) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9) (1) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9) (1) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9) (1) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9) (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9) (1).png -------------------------------------------------------------------------------- /.gitbook/assets/image (9).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image (9).png -------------------------------------------------------------------------------- /.gitbook/assets/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/image.png -------------------------------------------------------------------------------- /.gitbook/assets/shuffle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1ambda/practical-data-pipeline/d5cd99938c932e73446746fa3269b9e4d1ca8eb3/.gitbook/assets/shuffle.gif -------------------------------------------------------------------------------- /01-data-infra/1.2-processing.md: -------------------------------------------------------------------------------- 1 | # 1.2 데이터 가공 (Processing) 2 | 3 | Practical AWS Pipeline 의 실습 과정입니다. 4 | -------------------------------------------------------------------------------- /01-data-infra/1.2.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: 리 3 | --- 4 | 5 | # 1.2 데이터 입수 (Ingestion) 6 | 7 | Practical AWS Pipeline 의 실습 과정입니다. 8 | -------------------------------------------------------------------------------- /01-data-infra/1.3-storage.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: 소 3 | --- 4 | 5 | # 1.3 데이터 저장 (Storage) 6 | 7 | Practical AWS Pipeline 의 실습 과정입니다. 8 | -------------------------------------------------------------------------------- /01-data-infra/1.3.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: 석 3 | --- 4 | 5 | # 1.4 데이터 분석 (Analysis) 6 | 7 | Practical AWS Pipeline 의 실습 과정입니다. 8 | -------------------------------------------------------------------------------- /02-processing/2.1.md: -------------------------------------------------------------------------------- 1 | # 2.1 데이터 처리 2 | 3 | 데이터를 처리하기 위한 프레임워크는 다양합니다. 이 글에서는 데이터를 분산처리하기 위해 자주 쓰이는 두 가지 프레임워크에 대해 이야기 할 예정입니다. 4 | 5 | * [Apache Spark ](https://spark.apache.org) 6 | * [Apache Flink](https://flink.apache.org)\ 7 | 8 | 9 | Apache Spark 는 배치 처리를 위해 많이 활용됩니다. 경우에 따라 스트림 처리를 위해 사용되는 경우도 있습니다. 메타스토어로부터 데이터를 테이블 형태로 쉽게 읽어오고 가공하는 것이 가능하며, 사용자의 편의에 따라 다양한 API 수준을 지원합니다. 10 | 11 | * [Spark SQL](https://spark.apache.org/docs/latest/sql-programming-guide.html#sql) 12 | * [Spark Dataframe / DataSet API](https://spark.apache.org/docs/latest/sql-programming-guide.html#datasets-and-dataframes)\ 13 | 14 | 15 | Spark 를 활용하면, 도메인 로직을 모듈로 만들고 배치 및 스트림에서 애플리케이션 (이하 Application) 에서 동일한 로직을 사용할 수 있습니다. 예를 들어 16 | 17 | * Kafka 에서 데이터를 읽어 처리하는 스트림 Application 있을 때 18 | * 장애 등의 이유로 동일한 데이터를 Kafka 가 아닌 S3 등 스토리지에서 읽어 배치처리를 할 경우 19 | * 동일한 모듈을 이용해 가공할 수 있습니다 20 | 21 | Flink 또한 배치 및 스트림 처리를 위한 API 를 지원합니다. 다만 이 글에서는 스트림을 위한 내용을 위주로 설명합니다. 22 | -------------------------------------------------------------------------------- /02-processing/2.1/README.md: -------------------------------------------------------------------------------- 1 | # 2.1 데이터 처리 2 | 3 | 데이터를 처리하기 위한 프레임워크는 다양합니다. 이 글에서는 데이터를 분산처리하기 위해 자주 쓰이는 두 가지 프레임워크에 대해 이야기 할 예정입니다. 4 | 5 | * [Apache Spark ](https://spark.apache.org/) 6 | * [Apache Flink](https://flink.apache.org/) 7 | 8 | Apache Spark 는 배치 처리를 위해 많이 활용됩니다. 경우에 따라 스트림 처리를 위해 사용되는 경우도 있습니다. 메타스토어로부터 데이터를 테이블 형태로 쉽게 읽어오고 가공하는 것이 가능하며, 사용자의 편의에 따라 다양한 API 수준을 지원합니다. 9 | 10 | * [Spark SQL](https://spark.apache.org/docs/latest/sql-programming-guide.html#sql) 11 | * [Spark Dataframe / DataSet API](https://spark.apache.org/docs/latest/sql-programming-guide.html#datasets-and-dataframes) 12 | 13 | Spark 를 활용하면, 도메인 로직을 모듈로 만들고 배치 및 스트림에서 애플리케이션 \(이하 Application\) 에서 동일한 로직을 사용할 수 있습니다. 예를 들어 14 | 15 | * Kafka 에서 데이터를 읽어 처리하는 스트림 Application 있을 때 16 | * 장애 등의 이유로 동일한 데이터를 Kafka 가 아닌 S3 등 스토리지에서 읽어 배치처리를 할 경우 17 | * 동일한 모듈을 이용해 가공할 수 있습니다 18 | 19 | Flink 또한 배치 및 스트림 처리를 위한 API 를 지원합니다. 다만 이 글에서는 스트림을 위한 내용을 위주로 설명합니다. 20 | 21 | -------------------------------------------------------------------------------- /02-processing/2.1/untitled.md: -------------------------------------------------------------------------------- 1 | # Untitled 2 | 3 | -------------------------------------------------------------------------------- /02-processing/2.2-batch.md: -------------------------------------------------------------------------------- 1 | # 2.2 배치 \(Batch\) 처리 2 | 3 | -------------------------------------------------------------------------------- /02-processing/2.2-batch/2.1.1-spark-intro.md: -------------------------------------------------------------------------------- 1 | # 2.1.1 Spark Intro 2 | 3 | [Apache Spark](https://spark.apache.org) 는 데이터 처리를 위한 범용 프레임워크 입니다. 데이터 파이프라인을 위해 많이 사용되며, 산업 표준에 가깝습니다. 4 | 5 | 6 | 7 | 8 | 9 | ### Languages and Libraries 10 | 11 | 12 | 13 | ![Apache Spark Languages and Libraries (https://www.datanami.com/2019/03/08/a-decade-later-apache-spark-still-going-strong/)](<../../.gitbook/assets/image (18) (1) (1) (1) (1) (1) (1) (1) (1).png>) 14 | 15 | 16 | 17 | Scala 이외에도 Python, R 등 다양한 언어를 지원하며 데이터 처리를 위한 라이브러리가 많이 존재합니다. ([Spark 관련 Third Party 프로젝트 목록](https://spark.apache.org/third-party-projects.html)) 18 | 19 | * [PySpark](http://spark.apache.org/docs/latest/api/python/) 20 | * [SparkR (R on Spark)](https://spark.apache.org/docs/latest/sparkr.html) 21 | * [Spark MLLib (머신러닝 라이브러리)](https://spark.apache.org/docs/latest/ml-guide.html) 22 | * [GraphX (그래프 데이터 처리 라이브러리)](https://spark.apache.org/docs/latest/graphx-programming-guide.html) 23 | 24 | 25 | 26 | ### Supported API Levels 27 | 28 | ![Spark APIs (Slide)](<../../.gitbook/assets/image (23) (1) (1) (1) (1) (1) (1) (1).png>) 29 | 30 | Spark SQL / Dataframe / Dataset API 등 다양한 형태의 API 를 제공해 사용자 편의 및 개발 환경에 따라 자유롭게 선택할 수 있습니다. 31 | 32 | 33 | 34 | ### Storage Connectors 35 | 36 | 37 | 38 | ![Spark Integration (https://www.datamechanics.co/apache-spark)](<../../.gitbook/assets/image (11) (1) (1) (1) (1) (1).png>) 39 | 40 | 41 | 42 | 다양한 Storage 와 연동되는 Connector 가 존재합니다. 43 | 44 | * [Kafka Connector](https://spark.apache.org/docs/latest/structured-streaming-kafka-integration.html) 45 | * [ElasticSearch Connector](https://www.elastic.co/guide/en/elasticsearch/hadoop/current/spark.html) 46 | * [MongoDB Connector](https://docs.mongodb.com/spark-connector/current/) 47 | * [Redis Connector](https://github.com/RedisLabs/spark-redis) 48 | * [Cassandra Connector](https://github.com/datastax/spark-cassandra-connector) 49 | 50 | 51 | 52 | 53 | 54 | ### Cluster Managers 55 | 56 | 57 | 58 | ![Spark Cluster Manager (Link)](<../../.gitbook/assets/image (12) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>) 59 | 60 | 61 | 62 | ![Spark Shell - Scala](<../../.gitbook/assets/image (12) (1) (1) (1) (1).png>) 63 | 64 | ![Spark Shell - PySpark](<../../.gitbook/assets/image (15) (1) (1).png>) 65 | 66 | ![Spark Shell - SQL](<../../.gitbook/assets/image (27) (1) (1) (1) (1).png>) 67 | 68 | ![Jupyrer Notebook w/ Spark Kernel](<../../.gitbook/assets/image (28) (1) (1) (1) (1) (1).png>) 69 | 70 | * 다양한 실행 모드 및 환경을 지원해 어느 환경에서나 사용할 수 있습니다. 71 | * Spark Shell / Jupyter Notebook 72 | * Local Mode / Client Mode / Cluster Mode 73 | * Spark Batch / Stream Streaming 74 | * Standalone / Yarn / Kubernetes Environment 75 | 76 | 77 | 78 | ### Summary 79 | 80 | ![Spark Usage (Link)](<../../.gitbook/assets/image (26) (1) (1).png>) 81 | 82 | 83 | 84 | 요약하면 Spark 는 85 | 86 | * 여러 환경과 모드를 지원하며 87 | * 다양한 커넥터를 이용해 데이터를 추출 및 저장이 가능하고 88 | * 사용자 편의에 맞추어 언어와 API, 그리고 라이브러리를 선택해 89 | * 분산처리를 수행할 수 있는 **범용** 데이터 처리 도구입니다. 90 | 91 | 92 | 93 | ```python 94 | spark 95 | .read // 데이터를 읽어옵니다. 96 | .format("jdbc") // "jdbc" 뿐 아니라 "kafka" 등 다양한 Format 을 사용할 수 있습니다 97 | 98 | .join(...) // 다른 데이터와 Join (병합) 합니다. 99 | 100 | .where(...) // 데이터 Row 필터링하거나 101 | .selectExpr(...) // 필요한 Column 만 선택합니다. 102 | 103 | repartition(5, "col1") // 얼마나 / 어떤 기준으로 분산해 처리할지를 정의합니다 104 | .groupBy(...) // 집계 연산을 수행합니다 105 | .agg(...) 106 | 107 | repartition(...) // 얼마나 / 어떤 기준으로 분산해 저장할지를 정의합니다. 108 | .write 109 | .format("kafka") // 데이터를 Parquet Format 110 | .option(...) // 원하는 옵션을 주어 111 | .save(...) // 저장합니다. 112 | 113 | 114 | 115 | ``` 116 | 117 | 118 | 119 | 예를 들어 위 코드에서는 Spark 를 이용해 120 | 121 | * JDBC (MySQL) Driver 로 데이터를 읽어 122 | * 다른 데이터와 Join 하고 123 | * Row 필터링 / Column 선택 등을 수행한 뒤 124 | * 원하는 기준으로 집계 연산 (Group By) 를 수행하고 125 | * 마지막으로는 Kafka 로 내보냅니다. 126 | 127 | 128 | 129 | 이 과정에서 사용자는 Spark 만 알아도 다양한 저장소 (Hive, S3, Kafka, MySQL) 와 다양한 Format (Avro, Parquet, CSV) 을 이용할 수 있고, Pandas 프레임워크 또는 RDB 의 SQL 이 제공하는 거의 유사한 API 와 문법을 이용해 데이터를 가공할 수 있습니다. 130 | 131 | 또한 컴퓨팅은 분산처리되어 발생하므로, 기존의 단일 머신에서 수행되는 Pandas 컴퓨팅 / RDB SQL 컴퓨팅 보다 더 큰 데이터를 빠른 시간 내에 처리할 수 있습니다. 132 | 133 | 134 | 135 | ### Question 136 | 137 | 다음 질문은 전통적인 RDB 와 Spark 의 컴퓨팅 관점에서의 차이를 보여줍니다. 138 | 139 | > RDB 를 사용하는것과 Spark 를 사용하는것은 어떤 차이점이 있나요? RDB 와 다르게 Spark 의 explain() 결과는 충분하지 않은 것 같습니다. 일반적으로 Spark 작업은 어떻게 튜닝하나요? 140 | 141 | ![MySQL vs Spark (Link)](<../../.gitbook/assets/image (21).png>) 142 | 143 | ![MySQL vs Spark (Link)](<../../.gitbook/assets/image (36).png>) 144 | 145 | 146 | 147 | RDB 에서 실행되는 쿼리와 Spark 작업은 다음의 차이점이 있습니다. 148 | 149 | * 서비스로 나가는 RDB 쿼리는 많아야 수개 테이블을 조인하지만, Spark Job 은 수십개의 테이블을 Join 할 수 있습니다. 150 | * 서비스로 나가는 RDB 쿼리는 수십-수백 millis 내로 결과를 내야하지만, Spark Job 은 작업에 따라 짧게는 5분, 머신러닝 집계는 수십 시간까지 걸릴 수 있습니다. 151 | * 서비스로 나가는 RDB 쿼리는 단일머신에서 수행되고 RDB 의 메모리는 많아봐야 ‘인스턴스 전체’ 에서 최대 수백기가지만, Spark 작업은 ‘하나의 Job’ 이 수백기가 / 수테라의 메모리를 사용할 수 있습니다. 152 | * 서비스로 나가는 RDB 쿼리는 단일머신에서 수행되므로, 중간 집계를 위한 네트워크 이동이 없습니다. 반면 Spark 작업은 분산처리가 기본이며, Shuffle 로 인한 네트워크 데이터 이동은 물론 메모리 부족으로 인한 Disk Spill 이 발생할 수 있습니다. 153 | * RDB 는 일반적으로 단일머신에서 고성능을 내기 위한 언어로 만들어졌지만, Spark 는 JVM 위에서 동작합니다. 154 | * RDB 는 ‘쿼리’ 단위로 튜닝이 일반적으로 쿼리 실행 시간이 중요한 요소가 되며, 테이블의 DDL (인덱스) 등을 DBA 와 같이 논의할 수 있습니다. 반면 Spark 는 하나의 작업에 걸리는 소요 시간이 긴 만큼 ‘작업’ 단위로 튜닝이 될 수 있습니다. 작업 내에서의 일부 Spark SQL 의 국소적인 최적화는 큰 의미가 없을수도 있습니다. 155 | * 서비스 백엔드 엔지니어는 QueryDSL / JPQL 등으로 감싸진 ‘쿼리’ 를 수백개 작성하고, 운영할 수 있겠지만 데이터 엔지니어는 개별 Table 에 데이터를 적재하는 ‘Spark Job’ 을 한명의 엔지니어가 수백-수천개 관리할 수 있습니다. 156 | 157 | 158 | 159 | 따라서 다음의 관점으로 튜닝이 진행됩니다. 160 | 161 | 리소스 측면에서 실행하는 컴퓨팅 종류에 따라 Driver 및 Executor 의 CPU / Memory 설정과 인스턴스 타입, 그리고 Network / Disk 등 리소스가 충분한지 확인합니다. 162 | 163 | * Disk Spill / Shuffle Write 등이 메모리에 비해 과다할 경우 혹은 GC 가 너무 잦게 발생할 경우 메모리를 늘립니다. 164 | * 머신러닝 등 컴퓨팅이 많이 필요한 Spark Job 은 CPU 를 늘릴 수 있습니다. 일반적으로는 작업마다 다른 EC2 인스턴스 타입을 사용하게끔 데이터 인프라가 설계됩니다. (머신러닝은 c5.8xlarge, 일반 집계는 r5.4xlarge 등) 165 | * 네트워크 대역폭이 모자랄 경우 c5n, r5n 등 네트워크 전용 인스턴스 타입을 고려할 수 있습니다. 다만 AWS 특정 Region / Zone 에서는 지원되지 않을 수 있습니다. 166 | * Disk 가 모자랄 경우 Spill 이 더이상 불가능해 Executor 가 종료될 수 있으므로 Shuffle Write / Memory 부족으로 인한 Spill 등 Disk 사용량을 모니터링 해 부족하면 Executor 숫자를 늘려 사이즈를 분산하거나, 더 큰 사이즈의 Disk (AWS EBS) 를 사용할 수 있습니다. 필요에 따라 높은 성능의 IO 를 가진 EBS 클래스를 선택할 수 있습니다. 167 | * RDB 는 리소스를 변경하려면 (Spec Up) Downtime 이 필요하지만, Spark 는 Node 를 쉽게 버튼 눌러 추가하면 됩니다. 따라서 리소스를 추가하는데 부담을 갖지 말고, 내 시간을 아끼는 것에 더 집중하는 편이 낫습니다. 168 | 169 | \ 170 | -------------------------------------------------------------------------------- /02-processing/2.2-batch/2.1.4-spark-architecture.md: -------------------------------------------------------------------------------- 1 | # 2.1.4 Spark Architecture 2 | 3 | 이번 챕터에서 사용할 데이터셋은 [Kaggle: Customer Personality Analysis](https://www.kaggle.com/imakash3011/customer-personality-analysis) 입니다. 아래와 같이 데이터를 로딩하고 일부 가공합니다. 4 | 5 | ```python 6 | from pyspark.sql.functions import * 7 | from pyspark.sql.types import * 8 | from pyspark.sql import Row 9 | 10 | # DataBricks 로 실습한다면 경로를 "/FileStore/tables/marketing_campaign.csv" 로 변경합니다 11 | df = spark.read.load("./marketing_campaign.csv", 12 | format="csv", 13 | sep="\t", 14 | inferSchema="true", 15 | header="true") 16 | 17 | dfSelected = df.select( 18 | col("ID").alias("id"), 19 | col("Year_Birth").alias("year_birth"), 20 | col("Education").alias("education"), 21 | col("Kidhome").alias("count_kid"), 22 | col("Teenhome").alias("count_teen"), 23 | col("Dt_Customer").alias("date_customer"), 24 | col("Recency").alias("days_last_login") 25 | ) 26 | 27 | dfConverted = dfSelected.withColumn("date_joined", 28 | add_months(to_date(col("date_customer"), "d-M-yyyy"), 72)) 29 | 30 | # Spark 가 파티션을 5개로 나누어 병렬처리 하도록 설정합니다. 31 | dfPartitioned = dfConverted.repartition(5) 32 | ``` 33 | 34 | 35 | 36 | ### Driver 37 | 38 | \ 39 | Spark 는 크게 두 가지 컴포넌트로 구성되어 있습니다. **Driver** 와 **Executor** 입니다. 40 | 41 | * Driver 는 1개로, 사용자의 Main 함수, 즉 사용자가 작성한 로직을 실행합니다. 이 과정에서 실행 계획을 생성해 Executor 에게 Task 를 할당할 수 있습니다. 42 | * Driver 는 Cluster Manager 와 통신하며 Spark Application 관리합니다. 43 | * Executor 는 여러개가 될 수 있습니다. 분산처리를 위해 Driver 가 요청한 계산 (Task) 을 수행할 수 있습니다. 이 결과는 Action 에 따라 (collect, foreachPartition) Driver 로 다시 돌려 보낼 수 있습니다. 44 | * Executor 는 사용자가 cache() 와 같은 함수 호출시 데이터를 메모리 (또는 디스크) 에 저장할 수 있습니다. 45 | 46 | \ 47 | Cluster Manager 는 본 챕터의 아래 섹션에서 설명하겠지만, 다수개의 Spark 작업을 실행할 수 있도록 리소스를 관리해주는 Hadoop / AWS EMR 의 Yarn 혹은 Kubernetes 와 같은 클러스터를 말합니다.\ 48 | 49 | 50 | ![Spark Cluster Mode Overview (https://spark.apache.org/docs/latest/cluster-overview.html)](<../../.gitbook/assets/image (2) (1) (1) (1) (1) (1) (1).png>) 51 | 52 | \ 53 | \ 54 | Spring Boot 와 같은 단일 머신을 위한 API Framework 와 다르게 Spark 의 코드는 Driver 와 Executor 에서 나누어 돌아갑니다. 지난 챕터에서 다루지 않았던 Action 몇 가지를 살펴보며 이 부분을 알아보겠습니다.\ 55 | 56 | 57 | 지난 챕터 Spark Concept 에서 다루었듯이, 데이터는 Partition 으로 구분되며 Executor 가 나누어 처리할 수 있다고 이야기 했었는데 Spark Dataframe 의 [collect()](https://spark.apache.org/docs/latest/api/python/reference/api/pyspark.sql.DataFrame.collect.html) Action 을 사용하면 Executor 에 분산되어 있던 데이터를 Driver 로 모을 수 있습니다. 58 | 59 | 60 | 61 | ![Spark Collect Overview (Link)](<../../.gitbook/assets/image (26) (1) (1) (1) (1) (1).png>) 62 | 63 | 64 | 65 | ```python 66 | # 'collect()' 는 Executor 에서 파일 내의 데이터를 읽어 Driver 로 전송하는 Action 입니다. 67 | # 만약 cache() 등을 통해 캐싱되어 있다면 메모리에서 데이터를 찾아 보낼 수 있습니다. 68 | collected = dfPartitioned.collect() 69 | 70 | # type(collected) 의 실행 결과 71 | list 72 | 73 | # collected[0] 의 실행 결과 74 | Row(id=7196, year_birth=1950, education='PhD', count_kid=1, count_teen=1, date_customer='08-02-2014', days_last_login=20, date_joined=datetime.date(2020, 2, 8)) 75 | ``` 76 | 77 | \ 78 | [collect()](https://spark.apache.org/docs/latest/api/python/reference/api/pyspark.sql.DataFrame.collect.html) 를 통해 가져온 데이터는 더이상 Spark 의 `DataFrame` 이 아니기에 분산되어 있는 데이터가 아닙니다. 타입도 일반 `list` 이며 Driver 메모리에 존재하는 일반 변수이므로 다른 변수와 같이 연산할 수 있습니다. 79 | 80 | ```python 81 | from pyspark.sql import Row 82 | 83 | missing_days = 10 84 | 85 | # Spark 의 Row 는 read-only 입니다. 따라서 Python 에서 변경하기 위해 Dict 로 변경 후 다시 Row 로 되돌립니다. 86 | # 효율적인 방법이 아니며, 내부 동작의 이해를 돕기 위해 만든 코드입니다. 87 | def updateDaysLastLogin(row): 88 | parsed = row.asDict() 89 | parsed['days_last_login'] = parsed['days_last_login'] + missing_days 90 | 91 | return Row(**parsed) 92 | 93 | updated = list(map(updateDaysLastLogin, collected)) 94 | 95 | # updated[0] 의 출력 결과 96 | Row(id=7196, year_birth=1950, education='PhD', count_kid=1, count_teen=1, date_customer='08-02-2014', days_last_login=30, date_joined=datetime.date(2020, 2, 8)) 97 | ``` 98 | 99 | \ 100 | `missing_days = 10` 는 Python, 즉 메인 로직에만 (Driver) 존재하는 변수이며 이 값을 이용해 `days_last_login` 값을 변경한 것을 알 수 있습니다. 주석에 달린바와 같이 일반적으로는 위와 같은 방식으로 데이터를 가공하지 않습니다. Spark DataFrame 에서 `withColumn` 등을 통해 효율적으로 Executor 에서 분산처리 하는것이 효율적입니다. 101 | 102 | \ 103 | Python 의 경우에는 `toPandas()` Action 을 이용하면 [Pandas DataFrame](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html) 으로 바꾼 후 데이터를 Pandas API 로 변경할 수 있습니다. ([Pandas.Dataframe.add](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.add.html))\ 104 | 105 | 106 | {% hint style="info" %} 107 | 10개 의 Executor 가 나누어 처리하던 총합 100 GB 만큼의 데이터를, Driver 로 가져오려면 어떤일이 발생할까요? Driver 의 메모리가 모자라진 않을지, 데이터를 전송하는 과정에서 네트워크 비용이 비싸진 않을지 생각해봅시다. 108 | 109 | Q. 그렇다면 언제 Driver 로 데이터를 가져와야 할까요? 110 | {% endhint %} 111 | 112 | \ 113 | Driver 는 다음 설정을 통해 리소스를 조절할 수 있습니다. 만약 필요에 의해 `collect()` 등을 사용해 Driver 로 데이터를 가져와 처리한다면 리소스를 처리에 요구되는 만큼 늘려 사용할 수 있습니다. 114 | 115 | * [https://spark.apache.org/docs/latest/configuration.html](https://spark.apache.org/docs/latest/configuration.html) 116 | 117 | ``` 118 | spark.driver.cores # Driver 에서 사용할 CPU Core 숫자 119 | spark.driver.memory # Driver 에서 사용할 메모리 GiB 120 | ``` 121 | 122 | \ 123 | 124 | 125 | ### Executor 126 | 127 | 128 | 129 | ![Spark Executor Overview (Link)](<../../.gitbook/assets/image (14) (1) (1) (1) (1) (1) (1).png>) 130 | 131 | \ 132 | **Executor** 는 Spark Driver 에서 요청한 작업을 분산처리 하거나 cache() 로 데이터를 분산 저장한 값을 들고 있습니다. 사용자 요청에 따라 갯수와 리소스를 조절할 수 있으며, 다음의 옵션을 사용합니다. 133 | 134 | * [https://spark.apache.org/docs/latest/configuration.html](https://spark.apache.org/docs/latest/configuration.html) 135 | 136 | ``` 137 | spark.executor.instances # 하나의 Spark 작업에서 사용할 Executor 수 138 | spark.executor.cores # 개별 Executor 에서 사용할 CPU Core 숫자 139 | spark.executor.memory # 개별 Executor 에서 사용할 Memory GiB 140 | ``` 141 | 142 | \ 143 | `spark.executor.instances` 에 지정된 숫자 만큼 Executor 가 생성됩니다. Driver 는 Executor 를 기다리기 위해 아래에 지정된 `spark.scheduler` 옵션만큼 대기합니다. 80% 의 Executor 가 사용할 수 있는 상태가 되기까지 기다리거나, 아니면 30초가 넘을 경우 Task 를 할당합니다. 144 | 145 | ``` 146 | spark.scheduler.maxRegisteredResourcesWaitingTime = 30s (default) 147 | spark.scheduler.minRegisteredResourcesRatio = 0.8 (for Kuberntes, Yarn) 148 | ``` 149 | 150 | 따라서 Kubernetes 처럼 [Cluster Autoscaler](https://github.com/kubernetes/autoscaler) 로 인해 EC2 가 생성되고, 그 이후에 필요한 Docker Image 를 다운받는 등 대기 시간이 길 경우에는 위 옵션을 조절하면 충분한 시간만큼 대기 후 Executor 가 전부 준비가 되었을때 Task 를 할당해, 데이터가 특정 Executor 로 초기에 몰리는 것을 방지할 수 있습니다. 151 | 152 | \ 153 | Executor 에서 분산 처리된 DataFrame 의 데이터를 Driver 에 데이터를 다시 모으기 위해 collect() 를 사용하는 방법을 다루었는데, 만약 Driver 로 데이터를 모을 필요가 없고, Executor 에서 그대로 데이터를 처리하고 싶다면 [foreach()](https://spark.apache.org/docs/3.1.1/api/python/reference/api/pyspark.sql.DataFrame.foreach.html), [foreachPartition()](https://spark.apache.org/docs/3.1.1/api/python/reference/api/pyspark.sql.DataFrame.foreachPartition.html?highlight=foreachpartition#pyspark.sql.DataFrame.foreachPartition) 함수를 사용할 수 있습니다. 154 | 155 | ```python 156 | dfPartitioned = dfConverted.repartition(5) 157 | 158 | # foreach 함수는 Callback 파라미터로 Spark.DataFrame 의 Row 를 '하나씩' 전달합니다. 159 | def persist(row): 160 | parsed = row.asDict() 161 | # Do something here 162 | 163 | dfPartitioned.foreach(persist) 164 | ``` 165 | 166 | ![foreachRDD 1 (Spark Streaming Programming Techniques)](<../../.gitbook/assets/image (27) (1) (1) (1) (1) (1) (1).png>) 167 | 168 | ![foreachRDD 2 (Spark Streaming Programming Techniques)](<../../.gitbook/assets/image (32) (1) (1) (1) (1) (1) (1).png>) 169 | 170 | \ 171 | \ 172 | \ 173 | 이 때 `foreach()` 로 넘겨주는 커스텀으로 만든 `persist` Callback 함수는 Driver 가 아닌 Executor 에서 동작합니다. 따라서 `persist()` 내에서 `print` 함수를 사용하더라도 Jupyter Notebook 이나 Driver 에서 결과가 출력되지 않습니다. 174 | 175 | \ 176 | Driver 가 아닌 Executor Process 의 로그를 확인해보면 다음과 같은 출력을 확인할 수 있습니다. 177 | 178 | ``` 179 | ... (생략) 180 | Row(id=8397, year_birth=1951, education='Graduation', count_kid=1, count_teen=1, date_customer='10-01-2014', days_last_login=82, date_joined=datetime.date(2020, 1, 10)) 181 | Row(id=1685, year_birth=1967, education='PhD', count_kid=0, count_teen=0, date_customer='17-03-2013', days_last_login=21, date_joined=datetime.date(2019, 3, 17)) 182 | Row(id=5186, year_birth=1955, education='PhD', count_kid=0, count_teen=1, date_customer='12-03-2014', days_last_login=59, date_joined=datetime.date(2020, 3, 12)) 183 | Row(id=5429, year_birth=1948, education='PhD', count_kid=0, count_teen=1, date_customer='20-08-2013', days_last_login=10, date_joined=datetime.date(2019, 8, 20)) 184 | ``` 185 | 186 | `foreach` 함수는 `Dataframe.write` 가 지원되지 않는 경우 혹은 더 세밀히 조절하기 위한 경우에 사용할 수 있는 Row-level API 로 일반적으로 [DynamoDB](https://aws.amazon.com/ko/dynamodb/) 등 외부 스토리지로 데이터를 내보내기 위해 사용할 수 있습니다.\ 187 | `DataFrame.write` 함수는 추후에 다루겠지만, 다양한 형식으로 데이터를 내보낼때 사용합니다. [Spark Data Sources](https://spark.apache.org/docs/latest/sql-data-sources.html) 문서에서 빌트인으로 저장 가능한 형식을 확인할 수 있습니다. 188 | 189 | [spark-redis](https://github.com/RedisLabs/spark-redis/blob/master/doc/dataframe.md) 처럼 벤더가 `DataFrame.write` 를 위한 라이브러리를 관리하는 경우도 있습니다. 아래에 몇개 스토리지에 대해 `DataFrame.write` 사용 가능한 경우를 정리해 봤습니다. 190 | 191 | * [Kafka Dataframe.write](https://spark.apache.org/docs/latest/structured-streaming-kafka-integration.html) (Spark Docs) 192 | * [ElasticSearch DataFrame.write](https://www.elastic.co/guide/en/elasticsearch/hadoop/current/spark.html#spark-sql-write) (ElasticSearch Docs) 193 | * [Cassandra DataFrame.write](https://github.com/datastax/spark-cassandra-connector) (Datastax Github) 194 | 195 | 196 | 197 | {% hint style="info" %} 198 | 만약 여러 Row 묶어서 처리하는 경우 더 효율적이라면, foreach() 함수를 사용하는 것이 좋은지 논의해 봅시다. 199 | 200 | * Kafka 로 데이터를 보낼 때 묶어서 보낸다면 네트워크 비용을 아낄 수 있습니다. (10개, 20개 등) 201 | * MySQL 로 데이터를 Insert 할 때 Bulk 로 Insert 할 수 있다면 Connection 과 네트워크 비용을 아낄 수 있습니다. 202 | 203 | 204 | 205 | 또한 데이터를 전송할 때 '순서' 를 보존해야 하는 경우를 생각해 봅시다. 206 | 207 | * 사용자 A 의 로그는 이벤트 시간 순서대로 전송해야 합니다. foreach() 를 통해서 각각 보낸다면 순서를 보장할 수 있을까요? 208 | {% endhint %} 209 | 210 | 211 | 212 | \ 213 | `foreach()` 함수가 DataFrame.Row (한 줄) 만큼 받아 처리할 수 있는 옵션을 제공한다면 `foreachPartition()` 함수는 Partition 단위로 데이터를 다룰 수 있는 Action 입니다. 우리는 이미 `DataFrame.repartition()` 함수를 통해 파티션을 적절히 나누어 놓았기 때문에 Partition 숫자만큼 `foreachPartition()` callback 이 호출됩니다. 214 | 215 | ```python 216 | def persistPartition(partitionedRows): 217 | for row in partitionedRows: 218 | parsed = row.asDict() 219 | # DO something here 220 | 221 | dfPartitioned.foreachPartition(persistPartition) 222 | ``` 223 | 224 | [foreachPartition()](https://spark.apache.org/docs/latest/api/python/reference/api/pyspark.sql.DataFrame.foreachPartition.html) 은 데이터를 뭉텅이로, 즉 Partition 단위로 사용자에게 줍니다. 따라서 사용자는 외부 저장소로 보낼때 묶음 단위 로 보낼 수 있고 외부 저장소로 보내는 커넥션 비용이 비싼 경우에 `foreach()` 보다 `foreachPartition` 을 유용하게 사용할 수 있습니다. 225 | 226 | 227 | 228 | {% hint style="info" %} 229 | 만약 Partition 숫자가 적어 하나의 Partition 내의 데이터가 너무 크다면, foreachPartition 을 실행하는 Executor 에겐 어떤 일이 발생할까요? 메모리 관점에서 논의해 봅시다. 230 | 231 | 232 | 233 | 더 많은 파티션으로 나눌때, 만약 사용자를 기준으로 순서를 정렬해서 전송해야 한다면 어떻게 할 수 있을까요? 234 | 235 | * repartition(200, "id").foreachPartition() 은 어떤 결과를 만들어낼지 논의해 봅시다. 236 | {% endhint %} 237 | 238 | 239 | 240 | ### Cluster Manager 241 | 242 | ![Spark Cluster Mode Overview (https://spark.apache.org/docs/latest/cluster-overview.html) ](<../../.gitbook/assets/image (1) (1) (1) (1) (1).png>) 243 | 244 | 245 | 246 | Cluster Manager 는 Spark 가 실행될 수 있는 리소스를 제공합니다. Driver 가 관리하는 SparkContext 는 어떤 Cluster Manager 에 연결할지에 대한 정보를 포함해 다양한 내용을 담고 있습니다. 247 | 248 | Driver 를 통해 Spark 가 Cluster Manager 에 연결되면 Executor 실행에 필요한 리소스를 얻어올 수 있습니다. 249 | 250 | Spark 는 다양한 Cluster Manager 를 지원합니다. 251 | 252 | * Standalone 253 | * Apache Mesos 254 | * Hadoop Yarn 255 | * Kubernetes 256 | 257 | 이 일반적으로 Yarn 과 Kubernetes 가 많이 쓰입니다. AWS 환경에서는 [AWS EMR](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-release-components.html) 을 통해 Spark 를 위한 Yarn 클러스터를 쉽게 세팅할 수 있습니다. 258 | 259 | AWS EMR 은 사용자에게 여러가지 편리성을 제공합니다. Hadoop Yarn 을 쓸 경우 HDFS 에 데이터로 관리하곤 하는데, AWS EMR 의 [emrfs](https://github.com/awsdocs/amazon-emr-management-guide/blob/main/doc\_source/emr-plan-file-systems.md) 를 이용하면 AWS S3 를 스토리지로 쓸 수 있습니다. 따라서 컴퓨팅과 데이터 보관을 분리해 클러스터 운영자가 용이하게 관리할 수 있을뿐만 아니라 S3 의 [Storage Class](https://aws.amazon.com/ko/s3/storage-classes/) 를 이용해 비용 절감을 하는 등 S3 의 다양한 기능을 활용할 수 있습니다. 비용 측면에서도 '머신' 을 유지하며 데이터를 보관하는 것이 아니기 때문에 (Data Node) 저렴합니다. 260 | 261 | 다만 Cloud 의 오브젝트 스토리지는 파일 시스템이 아니기 때문에 Spark 문서 가이드를 따라 추가적인 옵션 설정이 필요합니다. 262 | 263 | * [https://spark.apache.org/docs/latest/cloud-integration.html](https://spark.apache.org/docs/latest/cloud-integration.html) 264 | 265 | {% hint style="info" %} 266 | 오브젝트 스토리지와 파일 시스템은 무엇이 다를까요? 그리고 그 차이점이 Spark 를 사용할 때 어떤 영향을 미칠까요? 267 | 268 | * [https://stackoverflow.com/questions/14925791/difference-between-object-storage-and-file-storage](https://stackoverflow.com/questions/14925791/difference-between-object-storage-and-file-storage) 269 | {% endhint %} 270 | 271 | 272 | 273 | Kubernetes 는 Spark 3.1+ 부터 GA 로 지원되는 Cluster Manager 입니다. Kubernetes 에 존재하는 Cluster Autoscaler Addon 이나 [Prometheus Stack](https://github.com/prometheus-operator/kube-prometheus) 등 모니터링 레이어를 그대로 활용할 수 있습니다. 274 | 275 | 만약 AWS 를 사용한다면 [AWS EKS (Managed Kubernetes)](https://aws.amazon.com/ko/eks/) 를 통해 손쉽게 Kubernetes Cluster 를 띄우고 관리할 수 있습니다. 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | ### Mode, Interface 284 | 285 | Spark 는 사용자의 환경에 맞추어 여러가지 실행 모드를 지원합니다. 286 | 287 | * 실행 위치 기준으로는 Local / Client / Cluster 모드를 지원하고 288 | * 인터페이스 기준으로는 Shell / Notebook / Application (Jar Submit) 을 제공합니다. 289 | 290 | 우선 실행 위치 기준의 분류 부터 살펴보면\ 291 | 292 | 293 | Local 모드는 현재 머신에서만 Spark 를 실행합니다. 1개의 머신만 사용하므로 머신 여러대로 수행하는 분산처리는 되지 않습니다. 개발 및 테스트 용도로 많이 사용합니다. 아래 사진은 Local 모드로 실행한 Spark 의 구조를 나타냅니다. 하나의 JVM (= Java Process) 안에 Driver 와 Executor 가 같이 위치해 있는것을 볼 수 있습니다. 294 | 295 | {% hint style="info" %} 296 | 만약 Spark 를 단일 머신에서 Local 모드로 사용한다면, 똑같은 리소스를 여러대로 나누어 분산처리 하는 케이스에 비해 어떤 이점이 있을까요? 297 | 298 | * Case 1) 30 vCPU, 250 GiB 단일 머신 299 | * Case 2) Driver 5 vCPU, 50 GiB 1개, Executor 5 vCPU, 40 GiB 5개 300 | 301 | \ 302 | 리소스 활용 측면에서의 차이 뿐만 아니라, 알고리즘이나 라이브러리 활용 측면에서는 어떨까요?\ 303 | 만약 우리가 사용해야 하는 모델의 학습이 분산처리가 되지 않는다면 어떤 모드를 선택해야 할지 어떨지 고민해 봅시다. 304 | {% endhint %} 305 | 306 | 307 | 308 | ![Spark Local Mode Overview (출처 표기)](https://files.gitbook.com/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lmdl6Kr60tPfvS6xNHH%2Fuploads%2FsgmjiEgCLyCNzzBQ5a0s%2Fimage.png?alt=media\&token=e96fcd6c-62b3-476c-9c05-31b72c1e8704) 309 | 310 | \ 311 | \ 312 | Client 모드와 Cluster 는 다음처럼 구분할 수 있습니다. 작업의 여요청은 둘 다 사용자가 Submit 명령을 실행하는 위치에서 발생하나, Driver 의 동작 위치가 다릅니다. 313 | 314 | * Client 모드는 Submit 이 요청된 위치에서 동작합니다. 따라서 한 머신에서 여러개의 Spark Application 으로 실행하는 경우 수 많은 Driver 로 인해 Submit 을 요청하는 머신의 리소스가 전부 소모되어 문제가 발생할 수 있습니다. 315 | * 반면 Cluster 모드는 Submit 이 요청된 이후에 Driver 가 요청된 위치가 아니라 Cluster 에서 돌아갑니다. 따라서 요청과 실제 Driver 가 분리되며, `spark.yarn.submit.waitAppCompletion` 를 통해 Submit 요청하는 커맨드나 스트립트가 Driver 종료까지 대기할지, 아니면 바로 종료할지 선택할 수 있습니다. 316 | 317 | 아래 사진을 통해 Spark Client 모드와 Spark Cluster 모드를 비교해 볼 수 있습니다. 318 | 319 | ![Spark Client Mode vs Cluster Mode Overview (출처 표기)](<../../.gitbook/assets/image (1) (1) (1) (1) (1) (1) (1).png>) 320 | 321 | ![Spark Client Mode (출처 표기)](<../../.gitbook/assets/image (4) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>) 322 | 323 | ![Spark Cluster Mode (출처 표기)](<../../.gitbook/assets/image (5) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>) 324 | 325 | 326 | 327 | {% hint style="info" %} 328 | Cluster 모드는 왜 필요한걸까요? 만약 EC2 위에 설치한 Airflow 에서 [Local Executor](https://airflow.apache.org/docs/apache-airflow/stable/executor/local.html) 로 Spark Submit 을 Client 모드로 수 없이 많이 하면 어떤 문제가 생길지 고민해 봅시다. 329 | {% endhint %} 330 | 331 | 332 | 333 | Spark 를 Cluster 모드로 Submit 할 경우 AWS EMR 을 이용한다면, 더 엄밀하는 AWS EMR 이 제공하는 Yarn 을 Cluster Manager 로 사용한다면 EMR 5 버전에서는 Spark Driver 가 EMR Core 에서 동작합니다. 334 | 335 | * EMR 은 Master / Core / Task 로 나누어지며 Core 는 HDFS 를 관리하는 Data Node 역할을 합니다. 반면 Task 는 HDFS 를 관리하지 않고 컴퓨팅만 수행하는 Compute Node 역할을 합니다. 336 | * https://docs.aws.amazon.com/ko\_kr/emr/latest/ManagementGuide/emr-master-core-task-nodes.html 337 | 338 | EMR 6 를 사용한다면 Core 대신 Driver 가 어디서든 동작할 수 있습니다. 혹은 EMR 5 를 사용하더라도 아래 옵션을 변경해 Spark Cluster Mode 로 요청된 Driver 의 실행 노드 타입을 결정할 수 있습니다. 339 | 340 | ``` 341 | yarn.node-labels.enabled: true 342 | yarn.node-labels.am.default-node-label-expression: 'CORE' 343 | ``` 344 | 345 | 여기서 `am` 은 **Yarn Appliaction Master**, 즉 Spark 의 Driver 를 말합니다. Yarn 은 범용 리소스 매니저로 설계되었으므로 Flink 사용시 am 은 Flink Job Manager 가 됩니다. 346 | 347 | 348 | 349 | ![Spark Yarn Cluster Mode (LInk)](<../../.gitbook/assets/image (8) (1) (1) (1) (1) (1).png>) 350 | 351 | 352 | 353 | ![Flink Yarn Cluster Mode (LInk)](<../../.gitbook/assets/image (29) (1) (1) (1) (1) (1).png>) 354 | 355 | 356 | 357 | ![AWS EMR Node Types (Link)](<../../.gitbook/assets/image (1) (1) (1).png>) 358 | 359 | {% hint style="info" %} 360 | EMR 에 대해 조금 더 고민해 봅시다. 361 | 362 | EMR 은 Master / Core / Task 노드로 구분이 되고 일반적으로 Yarn Cluster 모드로 Submit 시에 Spark Driver 는 Core 에서 동작한다고 이야기를 나누었습니다. 363 | 364 | * Driver 를 이렇게 Core 에서 묶어서 관리하는 것의 장점은 무엇일까요? 365 | * Executor 는 반면 Core 가 아니라 Task 에서 돌아갈텐데, Driver 와 Executor 가 사용하는 리소스의 양은 차이가 있을까요? 366 | * 차이가 있다면 Core 와 Task 를 분리해서 다른 타입의 EC2 머신을 사용한다면 리소스 관리에서 어떤 이점이 있을까요? 367 | {% endhint %} 368 | 369 | 370 | 371 | ![AWS EMR UI - Hardwares](<../../.gitbook/assets/image (31) (1) (1) (1) (1).png>) 372 | 373 | 374 | 375 | ### Practice 376 | 377 | 실습 과제입니다. 378 | 379 | 380 | 381 | 로컬 환경에서 Spark Cluster 를 띄우고 Spark 작업을 Submit 해 봅니다. 아래의 레포지토리 내의 코드를 참조할 수 있습니다. 382 | 383 | * [https://github.com/1ambda/practical-data-pipeline-code](https://github.com/1ambda/practical-data-pipeline-code) 384 | 385 | 386 | 387 | Client 모드로 Submit 하는 것과 Cluster 모드로 Submit 하는 것은 각각 어떻게 하는 것인지 다음 문서를 통해 찾아보고 실행해봅시다. 388 | 389 | * [https://spark.apache.org/docs/latest/submitting-applications.html](https://spark.apache.org/docs/latest/submitting-applications.html) 390 | 391 | 392 | 393 | {% hint style="info" %} 394 | Cluster 모드로 작업을 Submit 한다면, Driver 가 Cluster 내에서 실행되므로 Submit 하는 프로세스가 바로 종료될 수 있습니다. 395 | 396 | * 바로 종료되지 않도록 하려면 어떤 옵션을 사용해야 할까요? 397 | * [https://spark.apache.org/docs/latest/running-on-yarn.html](https://spark.apache.org/docs/latest/running-on-yarn.html) 문서에서 다음 옵션을 찾아봅시다. `spark.yarn.submit.waitAppCompletion` 398 | 399 | `` 400 | 401 | Spark 작업이 단순히 '종료' 된 것과 실제로 데이터를 잘 생성하고 적재했음을 어떻게 파악할 수 있을까요? 402 | 403 | * [Digdag 의 S3 Wait Plugin ](https://docs.digdag.io/operators/s3\_wait.html)이나 Airflow 의 [S3 Key Sensor](https://airflow.apache.org/docs/apache-airflow-providers-amazon/stable/\_api/airflow/providers/amazon/aws/sensors/s3\_key/index.html#module-airflow.providers.amazon.aws.sensors.s3\_key) 를 찾아봅시다. 404 | * 왜 `SELECT count(*) FROM X > 0` 처럼 Row 숫자를 비교하지 않을까요? Hive Metastore 부담 측면에서도 같이 고민해 봅시다. 405 | {% endhint %} 406 | 407 | 408 | 409 | 410 | 411 | ### Summary 412 | 413 | 아래는 이번 챕터에서 다룬 핵심 키워드입니다. 414 | 415 | * Driver 416 | * Executor 417 | * collect(), foreach(), foreachPartition() 418 | * Spark Local / Client / Cluster 모드 419 | * AWS EMR Master / Core / Task 420 | 421 | -------------------------------------------------------------------------------- /02-processing/2.2-batch/2.2.2-spark-versions.md: -------------------------------------------------------------------------------- 1 | # 2.2.2 Spark Versions 2 | 3 | 이 챕터에서는 Spark 버전별 변경 사항에 대해서 다룹니다. 기본적인 내용은 아래의 두 문서에서 확인할 수 있습니다. 4 | 5 | * [Spark SQL Migration Guide](https://spark.apache.org/docs/latest/sql-migration-guide.html) 6 | * [Spark Release Note](https://spark.apache.org/news/index.html) 7 | 8 | 9 | 10 | ### [Spark 0.6.0 (2012. 10)](https://spark.apache.org/releases/spark-release-0-6-0.html) 11 | 12 | * Java API 가 추가되었습니다. 13 | * Spark Standalone Cluster 모드를 사용할 수 있게 되었고, Yarn Cluster 위에서 동작하는 기능이 실험 (Experimental) 기능으로 지원되었습니다. 14 | * 당시 시점에서는 Mesos 클러스터 위에서 사용하는 패턴이 주류였습니다. 15 | * [persist()](https://spark.apache.org/docs/0.6.0/scala-programming-guide.html#rdd-persistence) 함수가 추가되었고 이로인해 캐싱을 메모리 넘어 Disk 에 저장할 수 있게 되었습니다. 16 | 17 | 18 | 19 | ### [Spark 0.7.0 (2013. 02)](https://spark.apache.org/releases/spark-release-0-7-0.html) 20 | 21 | * Python API 가 추가되었습니다. 22 | * 알파 단계의 스트리밍 기능이 지원되기 시작했습니다. ([Technical Report](https://www2.eecs.berkeley.edu/Pubs/TechRpts/2012/EECS-2012-259.pdf)) 23 | 24 | 25 | 26 | ### [Spark 0.8.0 (2013. 09)](https://spark.apache.org/releases/spark-release-0-8-0.html) 27 | 28 | * [Spark UI](2.2.2-spark-versions.md#spark-0.6.0-2012.-10.-15) 가 지금과 같은 형식으로 제공되기 시작했습니다. 29 | * Machine Learning Library 인 [MLlib](http://spark.apache.org/mllib/) 이 Spark 프로젝트의 구성요소로 개발되기 시작했습니다. 30 | * Hadoop Yarn Support 가 Experimental 이 아니라 공식적으로 지원되기 시작했습니다. 31 | 32 | 33 | 34 | ### [Spark 0.9.0 (2014. 02)](https://spark.apache.org/releases/spark-release-0-9-0.html) 35 | 36 | * Spark Streaming 부분에 많은 개선이 있었습니다. 37 | * GraphX 가 그래프 연산을 위한 Spark 의 컴포넌트로 개발되기 시작했습니다. 38 | 39 | 40 | 41 | ### [Spark 1.0.0 (2014. 05)](https://spark.apache.org/releases/spark-release-1-0-0.html) 42 | 43 | * Spark SQL 이 추가되었습니다. 44 | * ML / Streaming / GraphX 등 라이브러리 부분에서 많은 개선이 있었습니다. 45 | 46 | 47 | 48 | ### [Spark 1.1.0 (2014. 09)](https://spark.apache.org/releases/spark-release-1-1-0.html) 49 | 50 | * 캐싱된 Partition 이 너무 클 경우 Disk 에 Spill 하는 기능이 추가되었습니다. 이전까지 Spark 는 특정 파티션이 너무 클 경우 전체를 읽다가 (Skew) OOM 이 발생하곤 했습니다. ([SPARK-1777](https://issues.apache.org/jira/browse/SPARK-1777)) 51 | * 정렬 (Sort) 기반의 Shuffle 이 추가되었습니다. 52 | 53 | > A simple idea is to periodically check the size of the buffer as we are unrolling and see if we are over the memory limit. If we are we could prepend the existing buffer to the iterator and write that entire thing out to disk. 54 | 55 | 56 | 57 | ### [Spark 1.2.0 (2014. 12)](https://spark.apache.org/releases/spark-release-1-2-0.html) 58 | 59 | * 대규모의 셔플을 처리할 수 있는 Sort 기반의 Shuffle 전략이 기본으로 채택되었습니다. ([SPARK-3280](https://issues.apache.org/jira/browse/SPARK-3280)) 60 | * 런타임에 동적으로 Executor 수를 조절할 수 있는 Dynamic Allocation 기능이 추가되었습니다. ([SPARK-3174](https://issues.apache.org/jira/browse/SPARK-3174)) 61 | * Spark SQL 에서는 Dynamic Partition Insert 가 추가되었습니다 ([SPARK-3007](https://issues.apache.org/jira/browse/SPARK-3007)) 62 | * Spark Streaming 에서 Python API 가 추가되었고 Driver 의 데이터 손실을 Write Ahead Log 를 통해 방지할 수 있게 되었습니다. ([SPARK-3129](https://issues.apache.org/jira/browse/SPARK-312)) 63 | 64 | ![Spark Streaming HA Design Doc](<../../.gitbook/assets/image (1).png>) 65 | 66 | 67 | 68 | ### [Spark 1.3.0 (2015. 03)](https://spark.apache.org/releases/spark-release-1-3-0.html) 69 | 70 | * DataFrame API 가 Spark 1.3 에 추가되었습니다. 71 | * 하나의 Table 을 위한 Parquet 파일이 스키마가 변경될 수 있도록 Parquet 를 위한 Schema Evoluation 기능이 지원되었습니다. (e.g., 하나의 컬럼에 대해 이전에는 nullable = false, 이후에는 nullable = true 등) 72 | * [https://spark.apache.org/docs/latest/sql-data-sources-parquet.html#schema-merging](https://spark.apache.org/docs/latest/sql-data-sources-parquet.html#schema-merging) 73 | 74 | 75 | 76 | ### [Spark 1.4.0 (2015. 11)](https://spark.apache.org/releases/spark-release-1-4-0.html) 77 | 78 | * Spark 에서 R 을 사용할 수 있게 되었습니다. 79 | * Python 3 을 지원하기 시작했습니다. 80 | * DataFrame 및 Spark SQL 에서는 ORC 파일 (Columnar) 지원이 되었고, Wnidow Function 을 포함해 각종 유용한 함수들이 추가되었습니다. 81 | 82 | 83 | 84 | ### [Spark 1.5.0 (2015. 09)](https://spark.apache.org/releases/spark-release-1-5-0.html) 85 | 86 | * Spark Core 에서는 Memory + Local Disk 를 섞어서 Checkpoint 를 만들 수 있는 옵션이 추가되었습니다. 이 방법은 HDFS 등 복제 저장소에 Checkpoint 를 만드는 것보다 덜 안정적이지만 속도는 빠릅니다. ([SPARK-1855](https://issues.apache.org/jira/browse/SPARK-1855)) 87 | * RDD 의 persist() 는 RDD Lineage 를 보존하지만 checkpoint 는 RDD 의 Lineage 를 보존하지 않고 현재까지의 결과를 HDFS 등에 저장합니다. 더 자세한 내용은 [What is the difference between spark checkpoint and persist to a disk](https://stackoverflow.com/questions/35127720/what-is-the-difference-between-spark-checkpoint-and-persist-to-a-disk) 과 [RDD Checkpointing](https://thebook.io/006908/part01/ch04/04/03/) 에서 살펴볼 수 있습니다. 88 | * Spark RDD 의 Checkpoint 와 Spark Streaming 의 Checkpoint 는 다른 기능입니다. 89 | * Spark DataFarme / SQL 부분에서는 Shuffle Join 시에 Hash Join (Memory) 대신 Sort-merge (External, Disk 사용) 을 활용함으로써 데이터 사이즈가 메모리가 아니라 디스크 (일반적으로 더 큼) 에 의해 제약되도록 하였습니다. 90 | * Hive 의존성이 1.2 로 업그레이드 되었고 Metastore 에 대한 Partition Pruning Pushdown 기능이 추가되었습니다. (spark.sql.hive.metastorePartitionPruning) 91 | * Parquet 파일 포맷의 Predicate Pushdown 이 기본으로 활성화 되기 시작했습니다. 92 | 93 | 94 | 95 | ### [Spark 1.6.0 (2016. 01)](https://spark.apache.org/releases/spark-release-1-6-0.html) 96 | 97 | * Dataset API 가 추가되었습니다. RDD 의 함수형 API 와 Spark SQL 엔진의 최적화를 둘 다 사용할 수 있는 API 로서 도입되었습니다. 98 | * Unified Memory Management ([SPARK-10000](https://issues.apache.org/jira/browse/SPARK-10000)) 로 사용자들은 Execution Memory / Storage Memory 를 좀 더 유연하게 쓸 수 있게 되었습니다. 99 | 100 | 101 | 102 | ### [Spark 2.0.0 (2016. 07)](https://spark.apache.org/releases/spark-release-2-0-0.html) 103 | 104 | * DataFrame 과 Dataset API 가 통합되었습니다. Spark 2.0 부터 `DataFrame` 은 `Dataset[Row]` 타입이며, Dataset 은 DataFrame 의 API 를 이용할 수 있습니다. 105 | * 신규로 추가된 SparkSession 클래스를 활용해 기존의 SQLContext, HiveContext 를 대체할 수 있게 되었습니다. 이제 SparkSession 으로 사용하는 API 에 상관 없이 단일화된 설정 방식을 가져갈 수 있습니다. 106 | * CSV 데이터 소스가 Built-in 으로 지원되기 시작했습니다. (이전에는 외부의 [spark-csv](https://github.com/databricks/spark-csv) 모듈을 사용했었습니다) 107 | * 캐싱 및 런타임 집계에서 Off-heap 을 사용하는 Memory 관리 기능이 지원되기 시작했습니다. 108 | * Streaming 부분에서는 [Structured Streaming](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html) 이 추가되었고 이제 사용자는 DataFrame / Dataset API 를 이용해 Spark SQL 과 Catalyst Optimizer 이점을 누리면서 Streaming Application 을 작성할 수 있게 되었습니다. 109 | * Spark SQL 을 위한 Code Generation 옵션이 기본으로 활성화 되었습니다.(`spark.sql.codegen.wholeStage`) Spark 는 Whole-stage Codegen 기법을 통해 사용자의 실행 요청 (다수의 Stage) 를 하나의 최적화된 Function 으로 만들어 Virtual Function Call 을 줄이고, CPU Register 이용율을 높이는 등 실행 속도 개선을 이루었습니다. 110 | 111 | > This question led us to fundamentally rethink the way we build Spark’s physical execution layer. When you look into a modern data engine (e.g. Spark or other MPP databases), **majority of the CPU cycles are spent in useless work, such as making virtual function calls or reading/writing intermediate data to CPU cache or memory.** Optimizing performance by reducing the amount of CPU cycles wasted in these useless work has been a long time focus of modern compilers. 112 | > 113 | > Spark 2.0 ships with the second generation Tungsten engine. This engine builds upon ideas from modern compilers and MPP databases and applies them to data processing**. The main idea is to emit optimized bytecode at runtime that collapses the entire query into a single function, eliminating virtual function calls and leveraging CPU registers for intermediate data. We call this technique “whole-stage code generation.”** 114 | 115 | 116 | 117 | ### [Spark 2.1.0 (2016. 12)](https://spark.apache.org/releases/spark-release-2-1-0.html) 118 | 119 | * Spark SQL 부분에 [from\_json](https://spark.apache.org/docs/latest/api/python/reference/api/pyspark.sql.functions.from\_json.html), [to\_json](https://spark.apache.org/docs/latest/api/python/reference/api/pyspark.sql.functions.to\_json.html?highlight=to\_json#pyspark.sql.functions.to\_json) 함수가 추가되었습니다. 120 | * Structured Streaming 에서 Kafka 0.10 과 Event Time 을 지원하기 시작했습니다. 121 | 122 | 123 | 124 | ### [Spark 2.2.0 (2017. 07)](https://spark.apache.org/releases/spark-release-2-2-0.html) 125 | 126 | * Spark SQL 에서 `LATERAL VIEW OUTER` 구문과 `explode()` 함수를 지원하기 시작했습니다. 127 | * 특정 Executor 의 반복적인 실패가 전체 Job 에 대한 실패로 번지는 것을 막기 위해 Task Scheduling 에 Blacklist 컨셉이 도입되었습니다 ([SPARK-8425](https://issues.apache.org/jira/browse/SPARK-8425)) 128 | * 현재는 `spark.excludeOnFailure` 옵션을 통해 조절 가능합니다. 129 | 130 | 131 | 132 | ![Spark UI - Black Listing (Link)](<../../.gitbook/assets/image (20) (1) (1) (1).png>) 133 | 134 | 135 | 136 | > After encountering the failure repeatedly, the driver decides that this executor and/or this node is unreliable. The driver removes the executor or node from the pool of available compute resources, and retries the task somewhere else. It likely succeeds and the user’s job continues transparently. 137 | 138 | ### [Spark 2.3.0 (2018. 02)](https://spark.apache.org/releases/spark-release-2-3-0.html) 139 | 140 | * Spark on Kubernetes 기능이 실험적으로 추가되었습니다. 141 | * Spark History Server 가 V2 로 개선되었습니다. 142 | * Structured Streaming 부분에서 Continuous Processing 모드가 추가되었습니다. 이제 Micro Batch 보다 더 촘촘한 처리 속도를 위해 이 모드를 사용할 수 있습니다. 이외에도 Stream-Stream Join 기능이 추가되었고 Streaming API V2 가 도입되었습니다. 143 | 144 | 145 | 146 | ![Spark Structured Streaming Modes (Link)](<../../.gitbook/assets/image (16) (1) (1) (1) (1).png>) 147 | 148 | ![Spark Structured Streaming Micro Batch (Link)](<../../.gitbook/assets/image (13) (1) (1) (1).png>) 149 | 150 | ![Spark Structured Streaming Micro Batch (Link)](<../../.gitbook/assets/image (6) (1) (1).png>) 151 | 152 | 153 | 154 | ![Spark Structured Streaming Continuous Processing (Link)](<../../.gitbook/assets/image (9) (1) (1) (1) (1).png>) 155 | 156 | 157 | 158 | ### [Spark 2.4.0 (2018. 11)](https://spark.apache.org/releases/spark-release-2-4-0.html) 159 | 160 | * Avro 데이터 소스가 Built-int 으로 지원되기 시작했습니다. 161 | * Coalesce, Repartition 힌트가 SQL 에서 사용 가능해졌습니다. 162 | * Hive Metastore 2.3 이 지원되기 시작헀고, 이 버전은 현재 [EMR 5](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-5331-release.html) 를 포함해 많은 환경에서 기본 버전입니다. 163 | * Kubernetes Cluster Manager 에서 PySpark, R 바인딩이 지원되고 Client 모드와 볼륨 마운팅을 사용할 수 있게 되었습니다. 164 | * Bucket Pruning 기능이 추가되었습니다. Spark 에서는 bucketBy, sortBy 등의 함수를 통해 데이터를 미리 분할 정렬된 형태로 저장해 다음 시점에 읽어 사용할 때 Shuffle 을 최소화 할 수 있습니다. 165 | * [https://jaceklaskowski.gitbooks.io/mastering-spark-sql/content/spark-sql-bucketing.html](https://jaceklaskowski.gitbooks.io/mastering-spark-sql/content/spark-sql-bucketing.html) 166 | * [https://spark.apache.org/docs/latest/sql-data-sources-load-save-functions.html#bucketing-sorting-and-partitioning](https://spark.apache.org/docs/latest/sql-data-sources-load-save-functions.html#bucketing-sorting-and-partitioning) 167 | * JDBC Connector 에서 Date / Timestamp 를 Partition 컬럼으로 사용이 가능해졌습니다. 이외에도 Parquet, ORC, JSON 등 다양한 커넥터가 개선되었습니다. 168 | * Structured Streaming 에서는 Kafka Client 버전이 0.1.0.1 에서 2.0.0 으로 업그레이드 되었습니다. 이외에도 Micro Batch 모드에서 `foreachBatch` 함수가 추가되는 등 일부 개선이 있었습니다. 169 | 170 | 171 | 172 | Spark 와 Hive 의 Bucket Semantic 은 다르긴 하나, 이해를 돕기 위해 Hive 의 Partition vs Bucket 사진을 첨부합니다.ra 173 | 174 | ![Hive Partition vs Bucket](<../../.gitbook/assets/image (19) (1) (1) (1) (1).png>) 175 | 176 | 177 | 178 | ### [Spark 3.0.0 (2020. 01)](https://spark.apache.org/releases/spark-release-3-0-0.html) 179 | 180 | * Adaptive Query Execution (AQE) 이 추가되었습니다. 181 | * ANSI SQL 호환성 부분에서 많은 개선사항이 있었습니다. 182 | * [Structured Streaming UI](https://github.com/apache/spark/pull/26201) 가 Spark UI 에 추가되었습니다. 183 | * Python 사용자들을 위해 Pandas UDF API 가 개선되었습니다. 184 | * Hadoop 3 및 Hive Metastore 3.1 이 지원되고 Hive 2.3 버전을 기본 의존성 및 실행 엔진으로 사용합니다. 185 | * Hadoop 3.1 에서는 S3A Commiter 가 추가되었고, Spark 는 S3A Commiter 를 활용하는 PathOutputCommiter 를 구현하였습니다. 이를 통해 S3 를 사용할 때 기존의 FileOutputCommitter V1, V2 대신 더 빠른 성능을 얻게 되었습니다. 186 | 187 | 188 | 189 | ### [Spark 3.1.1 (2021. 03)](2.2.2-spark-versions.md#spark-0.6.0-2012.-10) 190 | 191 | * Spark on Kubernetes 가 GA 되었습니다. 192 | * Node Decommisioning 기능이 Kubernetes 및 Standalone Cluster 를 대상으로 실험적으로 추가되었습니다. 이 기능을 통해 Node 가 Shutdown 되기 전에 S3 등으로 Node 내의 Shuffle, Cache 데이터 등을 옮겨 다시 계산하는 것을 피할 수 있습니다. ([SPARK-20624](https://issues.apache.org/jira/browse/SPARK-20624)) 193 | * [https://www.waitingforcode.com/apache-spark/what-new-apache-spark-3.1-nodes-decommissioning/read](https://www.waitingforcode.com/apache-spark/what-new-apache-spark-3.1-nodes-decommissioning/read) 194 | * Hadoop 3.2.0 이 기본 환경으로 채택되었습니다. 195 | 196 | 197 | 198 | 199 | 200 | ### [Spark 3.2.0 (2021. 10)](https://spark.apache.org/releases/spark-release-3-2-0.html) 201 | 202 | * 기존에 [https://github.com/databricks/koalas](https://github.com/databricks/koalas) 라는 이름으로 분리되어 있던 Pandas API 가 PySpark 에 통합되었습니다. 203 | * AQE 가 기본으로 활성화 됩니다. 204 | * Hadoop 3.3.1 이 기본 환경으로 채택되었습니다. 205 | * Structured Streaming 에서는 RocksDB 가 State 저장소로 추가되었고, Kafka Client 가 2.8.0 으로 업그레이드 되었습니다. 206 | * Push-based Shuffle 기능이 추가되었습니다. ([SPARK-30602](https://issues.apache.org/jira/browse/SPARK-30602)) 207 | * 구현에 대한 자세한 내용은 Linkedin 블로그 [A scalable and performant shuffle architecture for Apache Spark](https://engineering.linkedin.com/blog/2020/introducing-magnet) 에서 볼 수 있습니다. 208 | 209 | 210 | 211 | External Shuffle Service 를 이용하면 Shuffle File 을 Executor 가 아니라 Exeternal Shuffle Service 가 관리하므로 Executor 다운 등에도 문제가 없습니다. 212 | 213 | * 단, External Shuffle Service 는 공유 자원이므로 병목이 될 수 있습니다. 214 | * Spark on Kubernetes 는 3.2.0 기준으로 External Shuffle Service 를 Built-in 지원하지 않습니다. 별도 배포를 통해 커뮤니티 사용자가 제작한 ESS 를 사용할 수 있습니다. 215 | * [https://medium.com/@rachit1arora/apache-spark-shuffle-service-there-are-more-than-one-options-c1a8e098230e](https://medium.com/@rachit1arora/apache-spark-shuffle-service-there-are-more-than-one-options-c1a8e098230e) 216 | 217 | 218 | 219 | ![Shuffle without External Shuffle Service (Link)](<../../.gitbook/assets/image (33) (1) (1) (1) (1).png>) 220 | 221 | 222 | 223 | ![Shuffle with External Shuffle Service (Link)](<../../.gitbook/assets/image (4) (1).png>) 224 | 225 | ![Shuffle with Push-based External Shuffle Service (Link)](<../../.gitbook/assets/image (7) (1) (1).png>) 226 | 227 | 228 | 229 | 외부의 (Reducer-side) ESS 가 Shuffle File 을 읽어갈 때는 요청이 랜덤하게 들어오므로 Local (Mapper-side) 의 ESS 에서 Random Disk IO 가 발생합니다. Push 형태로 직접 전송함으로써 이 부분을 개선하고, 아주 작고 많은 Shuffle File 을 병합함으로써 성능을 개선할 수 있습니다. 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /02-processing/2.2-batch/README.md: -------------------------------------------------------------------------------- 1 | # 2.2 배치 \(Batch\) 처리 2 | 3 | 배치 \(Batch\) 처리는 비교적 긴 주기로, 데이터를 처리하는 것을 말합니다. 4 | 5 | 개념을 설명하는 특정 문서에서는 배치 처리는 데이터를 특정 기간동안 모아서 처리하는 것을 말하고, 스트림 처리는 매 건마다 개별로 처리한다고 구별하는 경우도 있습니다. \[1\] 그러나 프레임워크에 따라 스트림 처리라 하더라도 Native Processing / Micro Batch 등 구현 방법이 다른 경우도 있어 6 | 7 | 이 글에서는 프레임워크가 어떻게 구현되었는지 보다는 Application 이 실행되는 패턴에 따라 분류하여 파이프라인 관점에서 그 용도에 따라 구분합니다. 예를 들어 8 | 9 | * Application 이 실행되고 데이터를 처리한 후 종료되며 비교적 긴 주기 \(1시간, 1일 등\) 마다 실행될 경우를 배치 처리로 설명합니다 10 | * 반면 Application 이 실행되어 있는 상태로 계속 유지되며, 비교적 짧은 주기 \(수백 milils, 수초 등\) 마다 데이터를 반복적으로 읽어 처리하는 경우를 스트림 처리로 설명합니다. 11 | 12 | 배치 처리를 위해 사용되는 Framework 는 다양하나, 이 글에서는 Spark 를 위주로 설명합니다. 13 | 14 | 15 | 16 | \[1\] [https://www.precisely.com/blog/big-data/big-data-101-batch-stream-processing](https://www.precisely.com/blog/big-data/big-data-101-batch-stream-processing) 17 | 18 | -------------------------------------------------------------------------------- /02-processing/2.3-workflow.md: -------------------------------------------------------------------------------- 1 | # 2.3 워크플로우 (Workflow) 관리 2 | 3 | Practical AWS Pipeline 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /02-processing/2.4-stream/2.4.1-kafka-intro.md: -------------------------------------------------------------------------------- 1 | # 2.4.1 Kafka Intro 2 | 3 | 4 | 5 | 이번 챕터에서는 Streaming 컴퓨팅의 데이터 소스로 활용되는 Kafka 에 대해 알아보겠습니다. 실시간 데이터는 주로 Kafka / Kinesis 등의 스토리지에 저장되어 있으며, Spark 에서는 Kafka 가 Built-in 데이터 소스로 지원됩니다. 6 | 7 | 8 | 9 | ### Kafka Architecture 10 | 11 | ![Apache Kafka Cluster (Link)](<../../.gitbook/assets/image (36) (1) (1) (1).png>) 12 | 13 | 14 | 15 | Kafka 는 Clustering 이 가능한 Message Broker 입니다. 16 | 17 | * Clustering 이 가능하므로 Broker 를 더 붙여 확장 (Scaling) 이 가능합니다. 18 | * Clustering 을 한다는 의미는 데이터를 여러벌로 복제하거나 (Replication) 19 | * 다양한 Broker 에서 나누어 읽고 쓸 수 있다는 뜻입니다. (Distributed) 20 | * Clustering 을 위한 추가적인 컴포넌트인 Zookeeper (ZK) 를 사용합니다. 21 | 22 | 23 | 24 | {% hint style="info" %} 25 | Kafka 2.8+ 부터 Zookeeper 없이 테스트 모드로 실행해 볼 수 있습니다. 26 | 27 | 그러나 2021년 기준으로 아직 대부분의 기업에서는 Production 환경에서 Zookeeper 를 같이 사용합니다. 28 | 29 | * Confluent: [Apache Kafka Made Simple: A First Glimpse of a Kafka Without ZooKeeper](https://www.confluent.io/blog/kafka-without-zookeeper-a-sneak-peek/) 30 | * [KIP-500: Replace ZooKeeper with a Self-Managed Metadata Quorum](https://cwiki.apache.org/confluence/display/KAFKA/KIP-500%3A+Replace+ZooKeeper+with+a+Self-Managed+Metadata+Quorum) 31 | {% endhint %} 32 | 33 | 34 | 35 | Kafka 를 통해 여러 Application 들은 메세지를 주고 받을 수 있습니다. 36 | 37 | * 데이터를 전송하는 Application 을 Kafka Procucer 38 | * 데이터를 받아서 처리하는 Application 을 Kafka Consumer 라 부릅니다. 39 | * Kafka 가 제공하는 API 를 이용해 다양한 언어 / 프레임워크의 Producer / Consumer 가 존재합니다. 40 | * Kafka Golang Library ([confluent-kafka-go](https://github.com/confluentinc/confluent-kafka-go)) 41 | * Spark SQL Kafka Integration ([github/spark/external/kafka-0-10-sql](https://github.com/apache/spark/tree/master/external/kafka-0-10-sql/src/main/scala/org/apache/spark/sql/kafka010)) 42 | * Spark Streaming Kafka Integration ([github/spark/external/kafka-0-10](https://github.com/apache/spark/tree/0494dc90af48ce7da0625485a4dc6917a244d580/external/kafka-0-10/src/main/scala/org/apache/spark/streaming/kafka010)) 43 | 44 | 45 | 46 | ![Kafka Topic (Link)](<../../.gitbook/assets/image (33) (1) (1).png>) 47 | 48 | Kafka 에서 Producer 와 Consumer 는 데이터를 구분하기 위해 '**Topic**' 을 지정합니다. 다른 종류의 메세지는 다른 Topic 으로 보낼 수 있습니다. 49 | 50 | 51 | 52 | ![Kafka Topic Partition (Link)](<../../.gitbook/assets/image (19) (1) (1) (1).png>) 53 | 54 | ![Kafka Topic Partition (Link)](<../../.gitbook/assets/image (18) (1) (1) (1).png>) 55 | 56 | 57 | 58 | 59 | 60 | ### Kafka Partition 61 | 62 | 하나의 Topic 을 나누어 Partition 을 여러개 만들 수 있습니다. Spark DataFrame 의 Partition 과 유사하게, 데이터를 나누어 처리하는 단위입니다. 63 | 64 | * Spark 에서 Partition 수를 조절해 Executor 에서 분산 처리 할 수 있고 65 | * Spark 에서 Partition 수를 조절해 Executor 내 메모리에 캐싱할 수 있습니다. 66 | * Kafka 에서 Topic 의 Partition 수를 조절해 Broker 내에서 나누어 저장할 수 있고 67 | * Kafka 에서 Topic 의 Partition 수를 조절해 Producer / Consumer 에서 병렬성을 조절할 수 있습니다. 68 | 69 | 70 | 71 | ![Kafka Multiple Partitions for a Single Topic (Link)](<../../.gitbook/assets/image (35) (1) (1) (1).png>) 72 | 73 | 74 | 75 | 76 | 77 | ![Kafka Replicated Topic (Link)](<../../.gitbook/assets/image (13) (1) (1).png>) 78 | 79 | 80 | 81 | 82 | 83 | 파티션을 복제 (Replication) 하는 것도 가능합니다. 이를 통해 Broker 2 가 다운되어 (Topic B - Partition 0) 와 (Topic B - Partition 1) 를 잃어버려도 다른 Broker 에 복제되어 있으므로 복구가 가능합니다. 84 | 85 | * **Leader**: 복제된 동일한 여러 Partition 소유한 Broker 중 하나의 Broker 가 Leader 로 선택됩니다. Leader 는 모든 Write / Read 에 대한 요청을 처리합니다. 86 | * **Follower**: Leader 의 Partition 에 Write 되는 데이터를 지속적으로 복제하며 따라갑니다. 만약 Leader 에 문제가 생겨 사용할 수 없는 상태가 되면, 여러 Follower 중 하나가 선택되어 Leader 가 됩니다. 이 과정을 Leader Election 이라 부릅니다. 87 | 88 | 89 | 90 | {% hint style="info" %} 91 | 분산 스토리지에서는 대부분 복제 (Replication) 라는 컨셉을 가지고 있습니다. 92 | 93 | * HDFS 에서는 `dfs.replication` 을 통해 복제본 숫자를 지정할 수 있습니다. 94 | * Kafka 에서는 replication.factor 라는 이름의 옵션으로 파티션이 복제됩니다. 3 일 경우 원본을 포함해 3개입니다. 95 | * ElaticSerach 에서는 데이터의 분할 단위가 Shard 이며 `number_of_replicas` 옵션을 통해 Shard 를 복제할 수 있습니다. 특이하게도 replica 3 일 경우 원본과 3개의 복제본을 만듭니다. 96 | {% endhint %} 97 | 98 | {% hint style="info" %} 99 | 안전성과 처리량 관점에서 다음을 생각해 봅시다. 100 | 101 | 102 | 103 | 만약 Replication Factor (복제본 숫자) = 3 일때 104 | 105 | * Producer 가 메세지를 Partition Leader 에게 보내고, Partition Follower 가 복제하기 전에 다음 메세지를 보낸다면 처리량은 어떨까요? 106 | * Producer 가 메세지를 Partition Leader 에게 보낸 후 Partition Follow 가 전부 복제한 후에야 다음 메세지를 보낼 수 있다면 안전성은 어떨까요? 107 | 108 | 109 | 110 | 아래의 옵션들을 찾아보며 각 설정에 따라 어떻게 동작할지 논의해 봅시다. 111 | 112 | * (Producer) acks = 0, 1, all 113 | * (Broker) min.insync.replicas 114 | {% endhint %} 115 | 116 | 117 | 118 | ![Unbalanced Leaders (Link)](<../../.gitbook/assets/image (29) (1) (1).png>) 119 | 120 | ![Unbalanced Leaders (Link)](<../../.gitbook/assets/image (12) (1) (1) (1).png>) 121 | 122 | ![Unbalanced Leaders (Link)](<../../.gitbook/assets/image (30) (1) (1) (1) (1).png>) 123 | 124 | ![Unbalanced Leaders (Link)](<../../.gitbook/assets/image (14) (1) (1).png>) 125 | 126 | 127 | 128 | 129 | 130 | 위 그림에서는 Broker 1, 3 가 이 죽을경우 각 파티션별 Leader 가 Broker 2 번이 되는 경우를 보여줍니다.\ 131 | 이 경우 Broker 2번이 죽으면 전체 Partition 에 문제가 생길텐데, Partitoin Leader 를 변경할 수 있는 방법이 있을까요? 132 | 133 | * Kafka 에서 제공하는 도구인 [kafka-reassign-partitions](https://docs.confluent.io/platform/current/kafka/post-deployment.html#increasing-replication-factor) 를 살펴봅시다. 134 | * 사내에서 UI 도구 (Kafka Manager 등) 을 제공한다면 편리하게 파티션 재할당 을 수행할 수 있습니다. 135 | 136 | ```json 137 | {"version":1, 138 | "partitions": 139 | [{"topic":"mytopic1","partition":3,"replicas":[4,5],"log_dirs":["any","any"]}, 140 | {"topic":"mytopic1","partition":1,"replicas":[5,4],"log_dirs":["any","any"]}, 141 | {"topic":"mytopic2","partition":2,"replicas":[6,5],"log_dirs":["any","any"]}] 142 | } 143 | ``` 144 | 145 | 언제 파티션을 다시 Re-assign 할 수 있을까요? Partition 이 늘어나는 경우도 고려해봅시다. 146 | 147 | 148 | 149 | 150 | 151 | ### **Partition Offset** 152 | 153 | 154 | 155 | ![Partition Offset (Link)](<../../.gitbook/assets/image (31) (1) (1) (1).png>) 156 | 157 | ![Partition Offset and Consumer (Link)](<../../.gitbook/assets/image (10) (1) (1).png>) 158 | 159 | 160 | 161 | 162 | 163 | **Topic** 은 여러개 **Partition** 으로 나뉘어 여러 Broker 에서 분산으로 Write 되고 Read 될 수 있습니다. 164 | 165 | * 이때 하나의 Partition 은 메세지가 증가할 때 마다 **Offset** 값을 늘려가며 메세지를 저장합니다. 166 | * 그리고 Consumer 는 Offset 을 따라가며 메세지를 처리하고, 자신이 어디까지 처리했는지를 보관합니다. 167 | * Offset 을 일종의 '메세지 번호' 로 생각할 수 있습니다. 168 | 169 | 170 | 171 | 172 | 173 | ### Consumer Group 174 | 175 | 176 | 177 | ![Kafka Consumer Group (Link)](<../../.gitbook/assets/image (17) (1) (1).png>) 178 | 179 | 180 | 181 | 하나의 **Consumer Group** = `app-db-updates-consumer` 내에서 보면 위 그림과 같습니다. 182 | 183 | * **Consumer** A, B 모두 동일한 Topic 을 처리합니다. 184 | * **Partition** 숫자가 4개이므로 **Consumer** A, B 가 파티션을 나누어 할당 받을 수 있습니다. 185 | * **Broker** 숫자는 나와있지 않으나 **Broker** 는 1개일수도, 여러개일 수도 있습니다. 이에 따라 Read / Write 요청이 여러 **Broker** 에 분산될 수 있습니다. 186 | 187 | 188 | 189 | Java 기준으로 그림상 1개의 Consumer 는 1개의 Thread 라고 보아도 좋습니다. Partition Read 1 Thread, Processing N Thread 처럼 Partition 당 N 개의 스레드를 가져갈 수 있으나 여기서는 논의하지 않습니다. ([Multi-Threaded Message Consumption with the Apache Kafka Consumer](https://www.confluent.io/blog/kafka-consumer-multi-threaded-messaging/)) 190 | 191 | 192 | 193 | ![Kafka Consumer Group (Link)](<../../.gitbook/assets/image (20) (1) (1).png>) 194 | 195 | 196 | 197 | 198 | 199 | 위 그림에서는 동일한 Topic / Partition 을 2 개의 Consumer A, B 가 나누어 읽는 것을 보여줍니다. 이는 Consumer Group 이 다르기 때문입니다. 200 | 201 | * 하나의 서비스를 위해 Consumer A 가 Topic 1 내 Partition 1 번을 할당 받고 (consumer group = X) 202 | * 또 다른 서비스를 위해 Consumer B 가 Topic 1 내 Partition 1 번을 다시 다른 용도로 할당 받을 수 있습니다 (consumer group Y) 203 | * **Consumer Group 별로 Partition 들의 Offset 이 관리됩니다** 204 | 205 | 206 | 207 | {% hint style="info" %} 208 | Consumer Group 내 Consumer 숫자가 추가되면 무슨 일이 발생할까요? 209 | 210 | 211 | 212 | 예를 들어 213 | 214 | * Partition 10개의 Topic A 에 대해 215 | * Consumer Group G1 에서 5개의 Consumer 를 이용해 Partition 10개를 할당 받아 처리하다가 216 | * Consumer Group G1 에 5개의 새로운 Consumer 를 추가합니다 (e.g, 별도 프로세스 추가 등) 217 | 218 | 219 | 220 | 다음은 Confluent 문서 내 Kafka Consumer 에 대한 설명 중 일부입니다. 이 부분을 읽어보며 생각해 봅시다. 221 | 222 | > A consumer group is a set of consumers which cooperate to consume data from some topics. The partitions of all the topics are divided among the consumers in the group. As new group members arrive and old members leave, _**the partitions are re-assigned so that each member receives a proportional share of the partitions. This is known as rebalancing the group.**_ 223 | {% endhint %} 224 | 225 | 226 | 227 | 228 | 229 | ### Kafka Overview 230 | 231 | ![Kafka Overview 1 (Link)](<../../.gitbook/assets/image (34) (1) (1) (1) (1).png>) 232 | 233 | 234 | 235 | Topic 과 Producet, Consumer 관점에서 살펴보면 236 | 237 | * 하나의 Kafka Topic 기준으로 여러 Producer 가 나누어 메세지를 보낼 수 있습니다. 238 | * 하나의 Kafka Topic 을 기준으로 한 Consumer Group 내 여러 Consumer 가 메세지를 읽어 처리할 수 있습니다. 239 | * 하나의 Kafka Topic 을 기준으로 두개 이상의 Consumer Group 이 동일한 메세지를 읽어 처리할 수 있습니다. 240 | * 위 그림에는 나와있지 않으나, 필요하다면 Consumer Group 내에서 두개 이상의 Topic 을 읽어 처리할 수 있습니다. 241 | 242 | 243 | 244 | ![Kafka Overview 2 (Link)](<../../.gitbook/assets/image (16) (1) (1).png>) 245 | 246 | 247 | 248 | 한 Topic 내에서 Partition 숫자는 병렬성을 조절하는 역할을 합니다. 249 | 250 | * Topic 내 Partition 숫자를 높이면 데이터가 여러 Broker 에 분산될 수 있습니다. 251 | * 그리고 나누어진 Partition 을 여러 Producer / Consumer 에서 메세지를 보내고, 읽어 처리할 수 있습니다. 252 | * 위 그림에서는 3개의 Partition 이 2개의 Consumer 에 할당되는 것을 볼 수 있습니다. 253 | 254 | 255 | 256 | Partition 별로 하나의 Consumer Group 내 Consumer 를 최대 한개까지 할당 할 수 있습니다. 그림으로 보면 아래와 같습니다. ([Kafka Partitions and Consumers](https://www.oreilly.com/library/view/kafka-the-definitive/9781491936153/ch04.html)) 257 | 258 | ![](<../../.gitbook/assets/image (15) (1).png>)![](<../../.gitbook/assets/image (28) (1) (1) (1) (1).png>) 259 | 260 | ![](<../../.gitbook/assets/image (32) (1) (1) (1).png>)![](<../../.gitbook/assets/image (11) (1) (1).png>) 261 | 262 | ![](<../../.gitbook/assets/image (23) (1) (1) (1).png>) 263 | 264 | 265 | 266 | {% hint style="info" %} 267 | Consumer 와 Partition 숫자에 대해 논의해 봅시다.\ 268 | 269 | 270 | 1. Consumer 숫자보다 Partition 숫자가 많으면 어떤 일이 발생할까요? 271 | 2. Partition 숫자보다 Consumer 숫자가 많으면 어떤 일이 발생할까요? 272 | 273 | \ 274 | 또한 Consumer 를 Process / Thread 관점에서도 생각해 봅시다. 275 | 276 | * JVM 언어 기준으로 1 Consumer = 1 Thread 로 이해해도 괜찮다는 이야기를 위에서 언급 했습니다. (1 Read Consumer Thread / N Processing Thread 전략 제외) 277 | * 그렇다면 Partition = 12 인 Topic 을 기준으로 인프라 리소스 할당 및 운영 관점에서 어떤 차이가 있을까요? 278 | * 1 개의 JVM Appliaction Process 내에서 12개의 Consumer Thread 를 실행하는 것 279 | * 4 개의 JVM Application Process 내에서 각 3개의 Consumer Thread 를 실행하는 것 280 | {% endhint %} 281 | 282 | 283 | 284 | 285 | 286 | ### Practice 287 | 288 | 실습 과제입니다. 289 | 290 | 291 | 292 | Practical Spark 클래스에서는 Spark 를 이용해 Kafka 를 사용하게 됩니다. 그런데 Spark Executor 는 JVM Process 입니다. Kafka Consumer 와는 어떤 관계가 있을까요? 293 | 294 | 295 | 296 | 다음 문서를 통해 살펴봅시다. 297 | 298 | * (Spark Streaming, DStream) https://spark.apache.org/docs/3.2.0/streaming-kafka-0-10-integration.html#consumerstrategies 299 | * (Spark Structured Streaming) [https://jaceklaskowski.gitbooks.io/spark-structured-streaming/content/spark-sql-streaming-kafka-data-source.htm](https://jaceklaskowski.gitbooks.io/spark-structured-streaming/content/spark-sql-streaming-kafka-data-source.html) 300 | 301 | 302 | 303 | ### Summary 304 | 305 | * Broker 306 | * Topic 307 | * Partition 308 | * Offset 309 | * Consumer 310 | * Producer 311 | * Consumer Group 312 | 313 | -------------------------------------------------------------------------------- /02-processing/2.4-stream/2.4.3-spark-streaming.md: -------------------------------------------------------------------------------- 1 | # 2.4.3 Spark Streaming 2 | 3 | Spark Streaming API 를 이용해 사용자는 실시간 데이터 처리를 수행할 수 있습니다. 이번 챕터에서는 Spark Streaming 의 기본적인 개념과 사용법에 대해 알아봅니다. 4 | 5 | 6 | 7 | ![Spark Streaming Concept (Link)](<../../.gitbook/assets/image (20) (1).png>) 8 | 9 | 10 | 11 | 아래는 Structured Streaming API 를 이용해 작성된 Word Count (단어 수 세기) 예제 입니다. 챕터들을 지나며 아래의 주제들을 하나씩 알아보겠습니다. 12 | 13 | ```scala 14 | val stream = 15 | 16 | // Source 17 | spark.readStream 18 | .format("kafka") 19 | .option("subscribe", "input-text") 20 | .load() 21 | 22 | // Transformation 23 | .groupBy(col("value").cast("string").as("key")) 24 | .agg("count(*).as("value")) 25 | 26 | // Sink 27 | .writeStream 28 | .format("kafka") 29 | .option("output-wordcount") 30 | 31 | // Trigger, Output Mode 32 | .trigger("1 minute") 33 | .outputMode("update") 34 | 35 | // Checkpoint 36 | .option("checkpointLocation", "s3://...") 37 | .start() 38 | 39 | stream.awaitTermination() 40 | ``` 41 | 42 | ### Spark Streaming API 43 | 44 | ![ APIs (Link)](<../../.gitbook/assets/image (19) (1).png>) 45 | 46 | Spark 3.2.0 기준으로 현재 두 가지 종류의 API 를 지원합니다. 47 | 48 | * [Spark Streaming](https://spark.apache.org/docs/latest/streaming-programming-guide.html) (Low-Level API, DStream) 49 | * [Spark Structured Streaming](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html) (High-Level API) 50 | 51 | 52 | 53 | Spark Streaming (Low-Level API, DStream) 은 Low-level API 로서 다음과 같은 특징이 있습니다. 54 | 55 | * Micro Batch 모드로 동작합니다. 즉, 입력 데이터를 일정 시간동안 데이터를 모아 사용자가 처리할 수 있도록 RDD 로 제공합니다. 56 | * 사용자는 RDD 로 들어오는 데이터를 RDD API 를 이용해 처리합니다. 57 | 58 | 아래는 DStream API 를 이용한 코드 샘플입니다. 59 | 60 | ```scala 61 | // Kafka 등으로부터 데이터를 읽어들이는 Stream 을 정의합니다. 아직 실행되지 않습니다. 62 | streamUservent = ... 63 | 64 | streamUserEvent.foreachRDD { rdd => 65 | val connection = createNewConnection() // executed at the driver 66 | rdd.foreach { record => 67 | connection.send(record) // executed at executor 68 | } 69 | } 70 | 71 | ssc.start() // 작업을 시작합니다. (ssc = Spark Streaming Context) 72 | ssc.awaitTermination() // 작업이 종료되길 대기합니다. 일반적으로 Streaming Application 의 종료는 SIGTERM (사용자 지정 종료) 또는 오류 등에 의해 발생할 수 있습니다. 73 | ``` 74 | 75 | 76 | 77 | Spark Structured Streaming 은 High-level API 로서 다음과 같은 특징이 있습니다. 78 | 79 | * RDD 를 직접 다루지 않고, Spark SQL 의 최적화 등 이점을 누리며 편리한 DataFrame / Dateset API 를 사용할 수 있습니다. 80 | * Micro Batch 이외에도 [Continuous Processing](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html#continuous-processing) 을 지원합니다 (Experimental) 81 | 82 | 83 | 84 | 아래는 Structured Streaming API 를 이용한 코드 샘플입니다. 85 | 86 | ```scala 87 | case class UserProfile(userId: String, eventType: EventType, productId: String, productPrice: Double) 88 | 89 | // Kafka Topic 을 읽어 DataFrame 으로 사용 90 | val dfRaw = spark 91 | .readStream 92 | .format("kafka") 93 | .option("kafka.bootstrap.servers", "kafka-broker-01:9092,kafka-broker-02:9092,kafka-broker-03:9092") 94 | .option("subscribe", "user-activity") 95 | .load() 96 | 97 | // Dataset 으로 변경 98 | val dsConverted = dfRaw.as[UserProfile] 99 | 100 | // 가공 및 집계 101 | val dfTransformed = dfConverted.map(...).filter(...).groupBy(...) 102 | 103 | // 가공한 데이터를 다시 Kafka 에 Write 104 | val dfWritten = dfTransformed 105 | .selectExpr("topic", "CAST(key AS STRING)", "CAST(value AS STRING)") 106 | .writeStream 107 | .format("kafka") 108 | .option("kafka.bootstrap.servers", "host1:port1,host2:port2") 109 | .start() 110 | 111 | dfWritten.awaitTermination() 112 | ``` 113 | 114 | 115 | 116 | 만약 Streaming 이 아니라 Batch (1회 적재 후 종료) 를 패턴으로 사용하고 싶다면 writeStream 대신 [Generic Load / Save API](https://spark.apache.org/docs/latest/sql-data-sources-load-save-functions.html) 와 동일한 write 및 save 를 사용할 수 있습니다. Spark 는 Batch 와 Streaming 의 Sink 로 Kafka 를 지원합니다. 117 | 118 | ```scala 119 | // Batch Source 로 부터 (S3 등) 데이터를 읽어 Kafka Sink 로 1회 적재 합니다. 120 | val dfPersisted = df... 121 | .selectExpr("topic", "CAST(key AS STRING)", "CAST(value AS STRING)") 122 | .write 123 | .format("kafka") 124 | .option("kafka.bootstrap.servers", "host1:port1,host2:port2") 125 | .save() 126 | ``` 127 | 128 | 129 | 130 | ![Dead Letter Queue (LInk)](<../../.gitbook/assets/image (34) (1) (1).png>) 131 | 132 | ![Dead Letter Queue (LInk)](<../../.gitbook/assets/image (27) (1).png>) 133 | 134 | 135 | 136 | {% hint style="info" %} 137 | Spark Structured Streaming 을 이용하면 Batch / Stream 데이터 적재를 동일한 가공 API (DataFrame, Dataset) 을 이용해서 수행할 수 있습니다. API 의 통합이 사용자에게 언제 유용할까요? 138 | 139 | 140 | 141 | 다음 경우를 가정해 봅시다. 142 | 143 | 144 | 145 | (A) Kafka Topic 의 Message 를 읽어 가공한 후 다른 Storage 로 적재합니다 (S3, Dynamo, Kafka 등) 146 | 147 | (B) Processing 과정에서 실패한 Kafka Topic 내 Message 는 추후 다시 처리하기 위해 Dead Letter Queue (DLQ, 또 다른 Kafka Topic) 으로 보냅니다. 148 | 149 | (C) DLQ Kafka Topic 내 Message 는 Retention 에 의해 삭제될 수 있기 때문에, DLQ 에 쌓인 메세지는 S3 에 적재합니다. 150 | 151 | \ 152 | 시간이 지나 S3 에 쌓인 데이터를 (Batch Source) 읽어 문제를 해결한 후 (A) 에서 보내려고 했던 Storage 에 다시 보낼 수 있습니다. 이 때 두 가지 옵션이 있을 수 있습니다. 153 | 154 | 1. S3 데이터를 Spark Batch Application 에서 읽어 최종 Storage 인 (A) 로 직접 적재합니다. 155 | 2. 만약 (A) 에서 사용되는 Spark Streaming 에서 메모리에 State 등을 활용한다면, S3 데이터를 읽어 (A) Kafka Topic 으로 데이터를 흘려 보내고 Spark Streaming 이 이 메세지를 다시 처리하게끔 할 수 있습니다. 156 | 157 | 158 | 159 | 즉, (2) 번 옵션은 Spark Batch Application 이 S3 데이터를 읽어 원본 Kafka Topic 으로 다시 보내고, 이것을 기존의 Spark Steraming Application 이 처리합니다. 160 | 161 | 단, 원본 Kafka Topic 이 다른 Consumer 들에 의해 공유되는 경우 (Inventory 등) 별도 작업 복구를 위한 Kafka Topic 을 만들고 Spark Streaming Application 이 이것을 사용할 수 있습니다. 162 | {% endhint %} 163 | 164 | 165 | 166 | ### Processing Mode 167 | 168 | ![Spark Processing Modes (Link)](<../../.gitbook/assets/image (35) (1).png>) 169 | 170 | Spark Streaming (DStream API) 또는 Structured Streaming 에서는 Micro-batch Processing 모드를 기본적으로 지원합니다. Structured Streaming 의 경우에는 Micro-batch Processing 모드 이외에도 Continuous Processing 을 실험적으로 (Experimental) 지원합니다.\ 171 | 두 가지 프로세싱 모드의 차이점은 다음과 같습니다. 172 | 173 | * Micro-batch Processing 모드의 경우 들어오는 데이터를 일정 기간 동안 모았다가 (Batch) 처리합니다. 174 | * Continuous Processing 모드의 경우 지연 없이 바로바로 처리합니다. 175 | 176 | \ 177 | 아래 그림을 통해 두 가지 Processing 모드의 차이점을 살펴볼 수 있습니다. 178 | 179 | ![Micro-batch Processing Mode (Link)](<../../.gitbook/assets/image (8) (1).png>) 180 | 181 | ![Continuous Processing Mode (Link)](<../../.gitbook/assets/image (17) (1).png>) 182 | 183 | ![Micro-batch Processing Mode (Link)](<../../.gitbook/assets/image (9) (1).png>) 184 | 185 | ![Continuous Processing Mode (Link)](<../../.gitbook/assets/image (11) (1).png>) 186 | 187 | 188 | 189 | {% hint style="info" %} 190 | Micro-batch Processing 모드와 Continuous Processing 모드의 차이점은 무엇일까요? 191 | 192 | * 개별 Record 의 Latency 관점에서 생각해보고 193 | * 또 다른 Streaming Framework 인 [Flink](https://nightlies.apache.org/flink/flink-docs-master/docs/dev/datastream/execution\_mode/) 는 어떤 Processing 모드를 지원하는지 찾아봅시다. 194 | {% endhint %} 195 | 196 | 197 | 198 | 199 | 200 | ### Streaming Patterns 201 | 202 | ![Spark Streaming Patterns (Link)](<../../.gitbook/assets/image (18) (1).png>) 203 | 204 | Streaming Application 은 Kafka 로 부터 데이터를 받아 다양한 곳에 적재할 수 있습니다. 위 그림과 같이 S3 에 데이터를 적재할 수도 있고, 다시 Kafka 로 보내 다른 실시간 처리를 위해 사용할 수도 있습니다. 205 | 206 | 207 | 208 | ![](<../../.gitbook/assets/image (28) (1) (1).png>) 209 | 210 | 이 챕터에서는 크게 결과 저장소의 종류를 기준으로 4 가지 사례로 나누어 알아봅니다. 211 | 212 | 1. S3 에 데이터를 적재합니다. 가장 기본적인 적재 방식으로서 Client / Server 의 이벤트 데이터나 CDC (Storage) 로 부터 온 데이터를 S3 에 내려 Query Engine 을 통해 조회하거나 추가적인 가공을 위해 보관합니다. 213 | 2. 하나 이상의 Kafka Topic 에서 데이터를 읽어 (Join) 처리 후 다른 Kafka Topic 으로 전송합니다. 때로는 다른 Kafka Cluster 의 Topic 으로 데이터를 전송할 수도 있습니다. Druid 와 같은 스토리지에서 이 Topic 의 데이터를 읽어 SQL 형태로 사용할 수 있습니다. Druid 는 기본적인 가공은 가능하나 복잡한 Join 및 Unnesting 등은 수행하기 어려우므로 Streaming Application 에서 가공하고 이것을 결과 Topic 에 저장한 뒤 Druid 와 같은 Storage 에서 읽어 사용합니다. 214 | 3. Kafka Topic 데이터를 읽어 External Key-Value 저장소에 지속적으로 '상태' 를 업데이트 합니다. (e.g., 상품의 재고 상태 등) 이 경우 '상태' 는 Stream Application 외부에 존재합니다. 경우에 따라 Stream (Event) 과 Batch (Meta) 데이터를 Join 할 수 있습니다. Batch 데이터는 1일 1회 갱신하며, 실시간으로 인입되는 Stream 데이터와 Join 해 결과를 만듭니다. 215 | 4. Kafka Topic 데이터를 읽어 Stream Application 내에 In-memory '상태' (State) 를 만든뒤 이 상태 값을 바탕으로 연산을 수행하고 결과를 내보냅니다. Output 은 다른 Kafka Topic 일 수 있습니다. 단, In-memory State 는 '메모리' 에 저장하므로 사이즈 제한이 있고, Checkpoint 등에 저장되어 안전하게 보일지라도 외부에서 사용 가능한 데이터가 아니므로 단일 Streaming Application 내에서만 활용 가능해, 범용성이 크게 집니다. 216 | 217 | > 일반적으로 Streaming 의 결과물이 다른 팀에 의해서 소비된다면 Latency 가 매우 중요하므로 ([@torreswoo](https://github.com/torreswoo)) Streaming Application 의 Output 은 Storage 가 아니라 Kafka Topic 인 경우가 많습니다. 218 | 219 | 220 | 221 | {% hint style="info" %} 222 | Stream Processing 은 실시간 데이터를 처리할 수 있지만 매우 물리 / 노동 비용 관점에서 고비용입니다. 다음 측면을 고려해 봅시다. 223 | 224 | * 지속적으로 Streaming Appilcation 이 떠있어야 합니다. 특성상 Streaming Application 은 트래픽이 튀는 상황에서도 '안전성' 을 보장해야 하므로 일정량 이상의 여분 리소스가 필요합니다. (경우에 따라 Auto Scaling 을 사용할 수도 있습니다.) 225 | * 지속적으로 Streaming Application 이 떠 있다는 말은 새벽에 문제가 생길 경우에도 담당자가 대응을 해야한다는 의미입니다. 자동 복구 등의 프로세스를 갖출 수 있겠지만, 예외적인 경우에는 사람의 간섭이 필요한 복구가 존재할 수 있습니다. (정책적 결정이 필요한 경우 등) Streaming Application 의 숫자가 늘어날수록 노동 인력에게 가해지는 부하가 늘어납니다. 226 | * Streaming Application 을 위한 기반 데이터 인프라가 필요합니다. Kafka / Zookeeper 등이 필요하고 Spark / Flink Streaming 을 위해 Cluster Manager 가 필요합니다. 227 | * 단일 Streaming Application 을 위해 복구용 Topic 과 Batch Application, Dead Letter 큐를 S3 에 내리기 위한 보존용 Application 등 여러 Application 필요할 수 있습니다. 228 | 229 | \ 230 | 따라서 Streaming Application 은 일반적으로 '실시간 데이터' 를 사용해 효과가 혹은 혜택이 있는 경우에만 사용하는게 바람직합니다. 231 | {% endhint %} 232 | 233 | 234 | 235 | 이제 각 패턴을 하나씩 살펴봅시다. 236 | 237 | ![](<../../.gitbook/assets/image (23) (1).png>) 238 | 239 | #### Pattern 1 ) Kafka Topic Relay 240 | 241 | Kafka Topic 에서 데이터를 읽어 어디론가 저장하는 단순한 패턴입니다. 242 | 243 | * Kafka Topic 을 Spark 읽어 S3 (HDFS, GCS) 로 저장할 수 있습니다. 244 | * Kafka Topic 을 다른 Kafka Broker 로 Relay 하거나 Kinesis To Kafka Relay 일 수 있습니다. 245 | 246 | \ 247 | Client Event 에 Session ID 발급 / Event 전처리 등 추가적인 가공이 들어갈 수 있기 때문에 Kafka Connect 처럼 단순 Relay 를 제공하는 프레임워크보다는 가공 로직을 사내 기준에 맞추어 자유롭게 변경할 수 있는 Spark / Flink 프레임워크가 선호됩니다. 248 | 249 | ```scala 250 | val dfRaw = spark 251 | .readStream 252 | .format("kafka") 253 | .option("kafka.bootstrap.servers", "kafka-broker-01:9092,kafka-broker-02:9092,kafka-broker-03:9092") 254 | .option("subscribe", "client-event") 255 | .load() 256 | 257 | 258 | val dfWithSessionId = dfRaw.withColumn(...) 259 | 260 | val dfWritten = dfWithSessionId 261 | .selectExpr("topic", "CAST(key AS STRING)", "CAST(value AS STRING)") 262 | .writeStream 263 | .format("kafka") 264 | .option("kafka.bootstrap.servers", "host1:port1,host2:port2") 265 | .start() 266 | 267 | dfWritten.awaitTermination() 268 | ``` 269 | 270 | 271 | 272 | 273 | 274 | ![](<../../.gitbook/assets/image (31) (1) (1).png>) 275 | 276 | #### **Pattern 2 ) Kafka Topic Converting** 277 | 278 | Kafka Topic 을 용도에 맞추어 가공해 사용하는 패턴입니다. 279 | 280 | * 여러 Topic 을 Union / Join 할 수 있습니다. 예를 들어 Client Web / Client App 이벤트의 포맷이 서로 다르며, 각기 다른 Kafka Topic 으로 전송될 때 두개의 Kafka Stream 을 공통 포맷으로 변환한 뒤 Spark DataFrame 에서 Join 할 수 있습니다. 281 | * 이렇게 가공된 통합 Client Event 는 Kafka 로 보내져 Druid 등에서 소비되거나 직접 Storage 로 적재될 수 있습니다 282 | 283 | ```scala 284 | val dfWebRaw = spark. 285 | .readStream 286 | .format("kafka") 287 | ... 288 | .option("subscribe", "client-event-web") 289 | .load() 290 | 291 | val dfWebRaw = spark 292 | .readStream 293 | .format("kafka") 294 | ... 295 | .option("subscribe", "client-event-app") 296 | .load() 297 | 298 | // 최초에 공용 Client Format 으로 Event 로그를 정의할 수 있습니다. 299 | // 이 예제에서는 Union 을 샘플로 보여주기 위해 아래와 같이 이벤트 포맷이 플랫폼별로 다르다는 가정을 가지고 있습니다. 300 | case class UserEventWeb(userId: String, eventType: EventType, browser: String, ...) 301 | case class UserEventApp(userId: String, eventType: EventType, platform: String, ...) 302 | 303 | val dsEventWeb = dfWebRaw.as[UserEventWeb] 304 | val dsEventApp = dfWebRaw.as[UserEventApp] 305 | 306 | val dsEventCommonWeb = dsEventWeb.map(e => e.convertToEventCommon()) 307 | val dsEventCommonApp = dsEventApp.map(e => e.convertToEventCommon()) 308 | 309 | val dsEventCommonAll = dsEventCommonWeb.union(dsEventCommonApp) 310 | 311 | // write into kafka 312 | ``` 313 | 314 | 또 다른 가공 패턴으로는 메타 테이블 + 이벤트 스트림을 Join 하는 케이스입니다. (**Stream-Static Join**) 315 | 316 | * 상품의 메타를 Batch 를 통해 읽어오고 317 | * 상품의 사용자 이벤트를 Stream 을 통해 읽어 Join 해 사용하는 방식입니다. 318 | 319 | 다만 상품의 메타 데이터는 일별로 갱신될 수 있으므로 매번 즉시 쿼리하기 보다는 캐싱 후 어떻게 읽어온 배치 데이터를 갱신할것인지 주의해야 합니다. 320 | 321 | 322 | 323 | [Stream-Stream Join](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html#stream-stream-joins) 을 이용하면 다음과 실시간 Attribution 집계와 같은 작업을 해낼 수 있습니다. 324 | 325 | ![Stream - Stream Join Case (Link)](<../../.gitbook/assets/image (13) (1).png>) 326 | 327 | ![Stream - Stream Join Case (Link)](<../../.gitbook/assets/image (36) (1).png>) 328 | 329 | ```scala 330 | val dfImprRaw = spark.readStream(...) 331 | val dfClickRaw = spark.readStream(...) 332 | 333 | val dfImprWatermarked = dfImprRaw 334 | .selectExpr("product_id as pid_impr", "adid AS adid_impr", "ts_impr") 335 | .withWatermark("ts_impr", "10 seconds ") 336 | 337 | val dfClickWatermarked = dfClickRaw \ 338 | .selectExpr("product_id as pid_click", "adid AS adid_impr", "ts_click") 339 | .withWatermark("ts_click", "20 seconds") 340 | 341 | # inner join with time range conditions 342 | dfImprWatermarked.join( 343 | dfClickWatermarked, 344 | expr(""" 345 | adid_click = adid_impr AND 346 | pid_click = pid_impr AND 347 | ts_click >= ts_impr AND 348 | ts_click <= ts_impr + interval 5 minutes 349 | """ 350 | ) 351 | ) 352 | ``` 353 | 354 | 355 | 356 | 357 | 358 | ![](<../../.gitbook/assets/image (12) (1) (1).png>) 359 | 360 | #### Parttern 3) 가공 후 Dynamo, HBase, Redis 등 API 에서 조회가 가능한 Storage 에 적재 361 | 362 | Kafka Topic 에서 데이터를 Streaming Application 읽어 원하는 형태로 가공 후 원하는 Write / Read Capacity 와 Latency 를 제공하는 Storage 를 골라 데이터를 적재할 수 있습니다. 363 | 364 | * (User Profile) 사용자 마다의 최근 이벤트 N 개 (검색, 상품 뷰, 주문 등) 를 시간순으로 정렬해 State 로 만들어 최신의 State 를 Dynamo 등에 Write 할 수 있습니다. 365 | * (Product Profile) 상품의 재고 변동이나 상품 기준의 집계 메트릭 (주문, 조회 수, 범위 기간당 노출 대비 클릭률 등) 을 계산해 Storage 에 적재할 수 있습니다. 366 | * 사용하는 Storage 의 Latency 및 Transaction, Upsert 등 구문 지원 여부에 따라 Streaming State 를 사용하지 않고 외부 저장소를 State 로 쓸 수 있습니다. (Get 후 Upsert) 367 | 368 | 369 | 370 | 아래 그림은 [mapGroupsWithState](https://jaceklaskowski.gitbooks.io/spark-structured-streaming/content/spark-sql-streaming-KeyValueGroupedDataset-mapGroupsWithState.html) 또는 [flatMapGroupsWithState](https://jaceklaskowski.gitbooks.io/spark-structured-streaming/content/spark-sql-streaming-KeyValueGroupedDataset-flatMapGroupsWithState.html) 를 사용해 Structured Streaming 에서 State 를 만드는 것을 도식화 한 그림입니다. 371 | 372 | ![Arbitrary Stateful Processing (Link](<../../.gitbook/assets/image (19).png>) 373 | 374 | ```scala 375 | val dsUserEvent = dfUserEvent.as[UserEvent] 376 | 377 | def stateFunc(userId:String, 378 | inputs: Iterator[UserEvent], 379 | oldState: GroupState[UserState]): UserState = { 380 | ... 381 | } 382 | 383 | val dsGrouped = dsUserEvent 384 | .groupByKey(u => u.userId) 385 | .mapGroupsWithState(timeoutSpec)(stateFunc) 386 | ``` 387 | 388 | 389 | 390 | ![](<../../.gitbook/assets/image (28) (1).png>) 391 | 392 | #### Pattern 4) In-memory State 393 | 394 | Spark Application 은 분산 처리를 수행하며 Executor 의 경우 N 개가 될 수 있으므로, 이 N 개 Executor 의 Memory 를 활용해 State 를 만들어 계산에 활용할 수 있습니다. 395 | 396 | * 즉 Spark Executor 내 Memory 를 State 저장소로 활용해 외부 저장소 조회 없이 빠른 집계를 수행할 수 있습니다. 397 | * 빠른 집계를 위해 In-memory State 를 쓰는 만큼 주된 Output 은 Kafka Topic 입니다. 398 | 399 | 다만 Memory 사이즈에 제한이 있으므로 Key 는 TTL 등을 통해 무한히 늘어나지 않도록 지정해야 합니다. 400 | 401 | 402 | 403 | ### Summary 404 | 405 | 이번 챕터에서 나온 개념 또는 용어 대한 정리입니다. 406 | 407 | * Micro-batch Processing Mode 408 | * Continuous Processing Mode 409 | * Dead Letter Queue 410 | * Flink (Streaming Framework) 411 | * AWS Kinesis 412 | * Key Value Storage (Dynamo, HBase, ...) 413 | -------------------------------------------------------------------------------- /02-processing/2.4-stream/2.4.4-streaming-window.md: -------------------------------------------------------------------------------- 1 | # 2.4.4 Streaming Window 2 | 3 | 4 | 5 | 이번 챕터에서는 Streaming 시스템에서 사용되는 Window 의 개념과 사용법에 대해서 배웁니다. API 별 Window 관련 내용은 다음 Spark 공식 문서에서 살펴볼 수 있습니다. 6 | 7 | * [Spark Direct Streaming: Window](https://spark.apache.org/docs/latest/streaming-programming-guide.html#window-operations) 8 | * [Spark Structured Streaming: Window](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html#window-operations-on-event-time) 9 | 10 | 11 | 12 | 13 | 14 | Streaming Application 에서 데이터는 실시간으로 들어옵니다. 이 때 '시간' 은 두 가지로 분류됩니다. 15 | 16 | * Event Timestamp: 이벤트 (데이터) 에 남은 시간 값입니다. App / Web 의 경우 OS 에 세팅된 시간일 수 있습니다. 17 | * Processing Timestamp: Streaming Application (Spark) 이 해당 데이터를 처리하는 시간입니다. 아래 그림과 같이 Event Time 과 Processing Time 은 크게 차이날 수 있습니다. 18 | 19 | ![Processing Time vs Event Time (Link)](<../../.gitbook/assets/image (23).png>) 20 | 21 | 22 | 23 | ![Event Time vs Processing Time (Link)](<../../.gitbook/assets/image (32) (1).png>) 24 | 25 | 26 | 27 | 이러한 개념은 Spark 뿐만 아니라 다른 프레임워크인 Flink 에서도 볼 수 있듯이 일반적입니다. 28 | 29 | * [Flink: Event Timestamp vs Processing Timestamp](https://nightlies.apache.org/flink/flink-docs-master/docs/concepts/time/) 30 | 31 | 32 | 33 | {% hint style="info" %} 34 | Client 에 남는 Event Timestamp 는 부정확하거나 적시에 데이터가 들어오지 않을 수 있습니다.\ 35 | 다음 경우를 생각해봅시다. 36 | 37 | * Client (Browser, App 등) 에서 시간 세팅이 제대로 되어있지 않을 경우 과거나 미래 데이터가 들어올 수 있을지 38 | * Client 의 종료나 Network 오류로 인해 어제 발생한 이벤트가 다음날 또는 몇분 뒤에 들어올 수 있을지, 39 | * 혹은 전송 과정에서 통신 망의 이슈로 특정 로그의 순서가 뒤바뀌어 올 수 있을지 (Click 이 먼저 들어오고 Impression 로그가 나중에 들어옴) 40 | {% endhint %} 41 | 42 | 43 | 44 | ### Window 45 | 46 | ![Window Types (Link)](<../../.gitbook/assets/image (14).png>) 47 | 48 | 49 | 50 | Streaming Application 는 **Window** 통해 데이터를 어느 기간동안 모아서 처리할지 지정합니다. 일반적으로 3 종류의 Window 로 나눕니다. 51 | 52 | * Fixed Window (Tumbling Wnidow) 는 겹치는 기간 없이 지정된 기간동안의 데이터만 처리합니다. 53 | * Sliding Window : 현재 기간과 과거 기간의 일부를 겹쳐서 처리합니다. 과거 기간의 일부를 포함해 상태를 만들거나 판별할 때 사용할 수 있습니다. 54 | * Session Window: 특정 Key (주로 사용자 ID 등) 를 중심으로 이벤트의 발생 유무에 따라 기간을 처리합니다. 즉 이벤트가 연속적으로 (지정된 Gap 이하의 시간동안) 들어오면 Window 기간이 늘어날 수 있습니다. 55 | * Spark 3.2.0+ 부터 Structured Streaming 에서 지원됩니다. 56 | 57 | 이제 Window 타입을 하나씩 살펴보겠습니다. 58 | 59 | 60 | 61 | #### Tumbling / Fixed Window 62 | 63 | ![](<../../.gitbook/assets/image (13).png>) 64 | 65 | Tumbling Window 는 지정된 간격 동안의 데이터를 처리합니다. [window](https://jaceklaskowski.gitbooks.io/spark-structured-streaming/content/spark-sql-streaming-window.html) 함수의 파라미터중 slideDuration 을 주지 않을 경우 Tumbling Window 가 됩니다. 66 | 67 | ```scala 68 | window( 69 | timeColumn: Column, 70 | windowDuration: String): Column (1) 71 | 72 | window( 73 | timeColumn: Column, 74 | windowDuration: String, 75 | slideDuration: String): Column (2) 76 | 77 | window( 78 | timeColumn: Column, 79 | windowDuration: String, 80 | slideDuration: String, 81 | startTime: String): Column (3) 82 | ``` 83 | 84 | 아래는 groupBy 함수 내에서 Tumbling Window 를 사용하는 예제입니다. 85 | 86 | ```scala 87 | val streamUserActivity = spark.readStream(...) 88 | 89 | val = streamWindowed 90 | .groupBy(window(col("timestamp"), "5 minutes")) 91 | ... 92 | ``` 93 | 94 | 95 | 96 | 97 | 98 | #### Sliding Window 99 | 100 | ![Sliding Window (Link)](<../../.gitbook/assets/image (15).png>) 101 | 102 | 103 | 104 | Sliding Window 는 Window Duration (Triggering 시점) 기준으로 좌우로 Sliding Duration 만큼의 Event Time 을 가진 데이터를 처리합니다. 105 | 106 | ```scala 107 | val streamWindowed = streamUserActivity 108 | .groupBy(window(col("timestamp"), "10 minutes", "5 minutes")) 109 | ... 110 | ``` 111 | 112 | 113 | 114 | #### Session Window 115 | 116 | ![User Event](<../../.gitbook/assets/image (25) (1).png>) 117 | 118 | ![Tumbling Window vs Session Window (Link)](<../../.gitbook/assets/image (16) (1).png>) 119 | 120 | ![Tumbling Window vs Session Window (Link)](<../../.gitbook/assets/image (30) (1).png>) 121 | 122 | 123 | 124 | Windowing 을 사용하면 Window 값을 가진 컬럼이 추가됩니다. (아래 예제에서는 session 이라는 이름으로 변경) 125 | 126 | _**따라서 Windowding 을 단순히 컬럼을 추가하고 해당 컬럼에 맞는 이벤트만 뽑아내 Group By 하는것으로 단순화 해 생각할 수 있습니다.**_ 127 | 128 | ```objectpascal 129 | val streamUserActivity = spark.readStream(...) 130 | 131 | val streamWindowed = streamUserActivity 132 | .groupBy( 133 | session_window(col("timestamp"), "5 minutes").as("session"), 134 | col("userId").as("user") 135 | ) 136 | ... 137 | ``` 138 | 139 | 140 | 141 | ![Session Window Details (Link)](<../../.gitbook/assets/image (24) (1).png>) 142 | 143 | 144 | 145 | 위 그림에서는 5분 단위 Gap 을 가진 사용자 ID 기준의 Session Window 를 사용했고, 이로 인해 10:12 데이터가 포함된 윈도우에는 기존 Window 에서 집계된 Count 가 없음을 볼 수 있습니다. 146 | 147 | 148 | 149 | {% hint style="info" %} 150 | Structured Streaming 에서 Session Window 는 3.2.0+ 부터 지원되었습니다. 151 | 152 | 153 | 154 | 그 이전에는 사용자 Session 을 어떻게 구현했을까요? 다음 Github Code 와 Article 읽어보며 논의해 봅시다. 155 | 156 | * [Spark 3.1 Example: StructuredSessionization.scala](https://github.com/apache/spark/blob/branch-3.1/examples/src/main/scala/org/apache/spark/examples/sql/streaming/StructuredSessionization.scala) 157 | * [Arbitrary Stateful Processing in Apache Spark’s Structured Streaming](https://databricks.com/blog/2017/10/17/arbitrary-stateful-processing-in-apache-sparks-structured-streaming.html) 158 | 159 | 160 | 161 | ``` 162 | val sessionUpdates = events 163 | .groupByKey(event => event.sessionId) 164 | .mapGroupsWithState[SessionInfo, SessionUpdate](GroupStateTimeout.ProcessingTimeTimeout) { 165 | 166 | case (sessionId: String, events: Iterator[Event], state: GroupState[SessionInfo]) => 167 | 168 | // If timed out, then remove session and send final update 169 | if (state.hasTimedOut) { 170 | val finalUpdate = 171 | SessionUpdate(sessionId, state.get.durationMs, state.get.numEvents, expired = true) 172 | state.remove() 173 | finalUpdate 174 | } else { 175 | // Update start and end timestamps in session 176 | val timestamps = events.map(_.timestamp.getTime).toSeq 177 | val updatedSession = if (state.exists) { 178 | val oldSession = state.get 179 | SessionInfo( 180 | oldSession.numEvents + timestamps.size, 181 | oldSession.startTimestampMs, 182 | math.max(oldSession.endTimestampMs, timestamps.max)) 183 | } else { 184 | SessionInfo(timestamps.size, timestamps.min, timestamps.max) 185 | } 186 | state.update(updatedSession) 187 | 188 | // Set timeout such that the session will be expired if no data received for 10 seconds 189 | state.setTimeoutDuration("10 seconds") 190 | SessionUpdate(sessionId, state.get.durationMs, state.get.numEvents, expired = false) 191 | } 192 | } 193 | ``` 194 | {% endhint %} 195 | 196 | 197 | 198 | 이제 Window 를 Key 별로 시각화 해서 정리해 보면 아래와 같이 표현할 수 있습니다. 199 | 200 | ![Window Strategies (Link)](<../../.gitbook/assets/image (12) (1).png>) 201 | 202 | 203 | 204 | ### Watermark 205 | 206 | ![Spark Structured Streaming: Handling Late Event (Link)](../../.gitbook/assets/image.png) 207 | 208 | 209 | 210 | Watermark 는 Streaming Framework 에서 "늦은" 데이터를 어떻게 처리할지를 (얼마나 늦게 들어온 이벤트를 Drop 할지) 지정할 수 있는 기능입니다. Processing Timestamp 를 사용하면 데이터의 '시간' 이 처리 시점이 되어서 늦는 경우가 없지만, 만약 Event Timestamp 를 사용할 경우 위에서 논의한 바와 같이 '늦게' 들어오는 이벤트가 생길 수 있습니다. 211 | 212 | * [Spark Structured Streaming: Watermark](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html#handling-late-data-and-watermarking) 213 | * [Flink Streaming: Watermark](https://nightlies.apache.org/flink/flink-docs-master/docs/concepts/time/#event-time-and-watermarks) 214 | 215 | > Streaming Watermark of a stateful streaming query is **how long to wait for late and possibly out-of-order events** until a streaming state can be considered final and not to change. Streaming watermark is used to mark events (modeled as a row in the streaming Dataset) that are older than the threshold as "too late", and not "interesting" to update partial non-final streaming state. ([Streaming Watermark: Spark Internals](https://jaceklaskowski.gitbooks.io/spark-structured-streaming/content/spark-sql-streaming-watermark.html)) 216 | 217 | 218 | 219 | [withWatermark](https://jaceklaskowski.gitbooks.io/spark-structured-streaming/content/spark-sql-streaming-Dataset-withWatermark.html) 를 통한 Watermark 지정은 Structured Streaming 에서 다음 두 가지 경우에 지원됩니다. 220 | 221 | * window 함수를 사용한 `groupBy` 집계 연산 **(주의! groupByKey 가 아님)** 222 | * [mapGroupsWithState](https://jaceklaskowski.gitbooks.io/spark-structured-streaming/content/spark-sql-streaming-KeyValueGroupedDataset-mapGroupsWithState.html) / [flatMapGroupsWithState](https://jaceklaskowski.gitbooks.io/spark-structured-streaming/content/spark-sql-streaming-KeyValueGroupedDataset-flatMapGroupsWithState.html) 를 사용한 사용자 관리 State 연산 (일반적으로 `groupByKey` 와 같이 사용 223 | 224 | 225 | 226 | ![Late Event Handling w/ Wartermark (Link)](<../../.gitbook/assets/image (31) (1).png>) 227 | 228 | 위 그림에서 분홍색의 케이스의 경우 (동일 상품 및 동일 사용자) 229 | 230 | * Click 이벤트는 12:06 시각에 발생했으나 (Event Time 기준) 231 | * Impr 이벤트가 12:09 에 발생했습니다 (Event Time 기준) 232 | * 일반적으로는 Impr (상품 노출) 이벤트가 Click (상품 클릭) 이벤트 보다 먼저 발생하기 때문에 순서가 뒤집어 진 경우임을 볼 수 있습니다. 233 | 234 | \ 235 | 만약 (Processing Timestamp 기준으로) 현재 시간이 12:10 이라고 하고 두 이벤트가 지금 Kafka 에서 Streaming Application 으로 들어왔다고 할 때 236 | 237 | * Click 이벤트는 12:06 시간에 발생했으나 12:10 에 처리가 되고 238 | * Impr 이벤트는 1209 시간에 발생했으나 12:10 에 처리가 되는 상황입니다. 239 | 240 | \ 241 | 이 때 아래와 같이 withWatermark 함수를 사용하면 두 이벤트 모두 버려지게 됩니다. 242 | 243 | * (Tumbling Window 를 사용한다 가정했을때) Click 이벤트는 Window 시간 대비 Event Time 이 최대 2분이 지나면 버려집니다. 244 | * (Tumbling Window 를 사용한다 가정했을때) Impr 이벤트는 Window 시간 대비 Event Time 이 최대 3분이 지나면 버려집니다. 245 | 246 | ```scala 247 | val dfImprRaw = spark.readStream(...) 248 | val dfClickRaw = spark.readStream(...) 249 | 250 | val dfImprWatermarked = dfImprRaw 251 | ... 252 | .withWatermark("ts_impr", "2 minutes") 253 | 254 | 255 | val dfClickWatermarked = dfClickRaw \ 256 | ... 257 | .withWatermark("ts_click", "3 minutes") 258 | ``` 259 | 260 | 261 | 262 | {% hint style="info" %} 263 | Sliding Window 와 Watermark 는 어떤 관점에서 다른걸까요? 264 | 265 | Sliding Window 를 사용하면 윈도우 기간내에 이전 Window 기간을 일부 포함할 수 있으므로 Late Event 를 처리할 수 있는 것처럼 보입니다. 266 | 267 | \ 268 | 다음 경우를 고려해봅시다. 269 | 270 | * Sliding Window 만 사용하고 Watermark 를 사용하지 않는 경우 271 | * Sliding Window 와 Watermark 를 모두 사용하는 경우 272 | {% endhint %} 273 | 274 | 275 | 276 | 아래 그림은 시각적으로 Processing / Event Timestamp 에 대해 어떤 이벤트가 Drop 되는지를 보여줍니다. 277 | 278 | ![Spark Structured Streaming: Handling Late Event (Link)](<../../.gitbook/assets/image (9).png>) 279 | 280 | 281 | 282 | 위 그림에서 사용한 코드는 아래와 같습니다. 283 | 284 | * withWatermark 함수를 통해 최대 10 분까지 늦은 Event Time 을 가진 데이터까지만 사용할 것을 지정하고 285 | * groupBy 내에서 10분 간격으로 좌우 5분의 Sliding Window 간격을 지정합니다. 286 | * groupBy 내에 Window 뿐만 아니라 word 컬럼이 있으므로 이 기준으로 Executor 에서 분산처리 되어 집계를 수행합니다. 287 | 288 | ```pascaligo 289 | val windowedCounts = words 290 | .withWatermark("timestamp", "10 minutes") -- 최대 10분까지 늦은 Event Time 을 가진 데이터 허용 291 | .groupBy( 292 | window($"timestamp", "10 minutes", "5 minutes"), -- 5분마다 10분 Sliding 293 | col("word") 294 | ) 295 | .count() 296 | ``` 297 | 298 | [Output Mode](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html#output-modes) 에 따라 결과 (Result) 테이블의 업데이트 시점이 달라지는데, 이 부분은 Streaming Sink 챕터에서 다루겠습니다. 299 | 300 | 301 | 302 | ![Spark Structured Streaming State (Link)](<../../.gitbook/assets/image (35).png>) 303 | 304 | {% hint style="info" %} 305 | 왜 Watermark 가 필요할까요? 메모리 관점에서 생각해 봅시다. 306 | 307 | * Spark Structured Streaming 은 Micro-batch 로 동작하고 매 배치마다 Window 는 State 가 됩니다. 308 | * 늦게 들어온 데이터를 무한히 처리해야 한다면, State 는 영원히 커질 수 있습니다 (OOM) 309 | * Watermark 를 통해 늦게 들어오는 데이터의 시간을 제한해 State 가 업데이트 되지 않도록 합니다. 310 | {% endhint %} 311 | 312 | 313 | 314 | ### Summary 315 | 316 | 이번 챕터에서 나온 개념 또는 용어 대한 정리입니다. 317 | 318 | * Event Timestamp 319 | * Processing Timestamp 320 | * Tumbling Window (Fixed Window) 321 | * Sliding Window (Slide Duration) 322 | * Session Window 323 | * Watermark 324 | 325 | -------------------------------------------------------------------------------- /02-processing/2.4-stream/2.4.6-streaming-sink.md: -------------------------------------------------------------------------------- 1 | # 2.4.6 Streaming Sink 2 | 3 | 4 | 5 | 이번 챕터에서는 Spark Structured Streaming 의 Output Sink (저장소) 와 Output Mode 에 대해 알아봅니다. 6 | 7 | * [Structured Streaming: Output Mode](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html#output-modes) 8 | * [Structured Steaming: Output Sink](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html#output-sinks) 9 | 10 | 11 | 12 | ### Output Mode 13 | 14 | 3 가지의 **Output Mode** 가 존재합니다. **Output Mode** 는 Spark Structured Streaming 의 결과가 Micro-batch 로 만들어지는 '테이블' 형태라는 가정하에 이해하면 쉽습니다. 15 | 16 | * Append (Default) 모드는 지난번 Micro-batch 에는 없었던 신규 데이터인 경우에 Row 를 추가해 테이블을 만듭니다. 17 | * Update (2.1.1+) 모드는 지난번 Micro-batch 에서 수정되었거나 혹은 신규 데이터인 경우에만 Row 를 추가해 테이블을 만듭니다. 18 | * **Complete** 모드는 전체 결과를 가진 테이블을 만듭니다. 19 | 20 | \ 21 | 그림으로 표현하면 아래와 같습니다. 22 | 23 | ![Spark Output Mode (Link)](<../../.gitbook/assets/image (30).png>) 24 | 25 | 26 | 27 | Output Mode 에 따라 지원되는 연산이 달라집니다. 아래 표는 Spark 3.2.0 기준으로 Output Mode 와 지원되는 연산을 보여줍니다. 28 | 29 | ![Spark Structured Streaming Output Mode (Link)](<../../.gitbook/assets/image (32).png>) 30 | 31 | 32 | 33 | 사용하는 연산에 따라 지정할 수 있는 Output Mode 가 달라집니다. 34 | 35 | * Aggregation (Group By 등) 을 Event Time 기준의 Watermark 와 사용할 경우에는 **Append / Update / Complete** 전부 사용 가능합니다. 36 | * Aggregation 에 Watermark 가 없을 경우에는 Append 를 지원해야 하는데 기간 제한이 없어 Update 가 발생할 수 있으므로 이 경우에는 Append 모드가 불가능해집니다. 따라서 지원하지 않습니다. 37 | * mapGroupsWithState 는 Update 모드만을, flatMapGroupsWithState 는 Function 파라미터로 지정되는 모드에 따라 Append / Update 를 사용할 수 있고 이를 바탕으로 Aggregation 지원 여부를 결정합니다. (Update = Aggregation 가능) 38 | * **Join 연산을 사용한다면 Append 모드만 사용 가능합니다.** 39 | 40 | 41 | 42 | 코드에서는 Output 모드를 다음과 같이 지정할 수 있습니다. (Scala) 43 | 44 | ```scala 45 | val streaming = dfConverted.writeStream 46 | .queryName("...") 47 | .format("...") 48 | .outputMode("update") // "append", "complete" 49 | ``` 50 | 51 | 52 | 53 | 54 | 55 | ### Output Sink 56 | 57 | Output Sink 를 통해 가공한 Streaming 데이터를 내보낼 수 있습니다. 아래는 Spark 3.2.0 기준으로 지원되는 Output Sink 입니다. 58 | 59 | 60 | 61 | ![Kafka as Central Event Broker (Link)](<../../.gitbook/assets/image (10).png>) 62 | 63 | 64 | 65 | ![Structured Streaming Sink Patterns (Link - Practical Spark)](<../../.gitbook/assets/image (25).png>) 66 | 67 | 68 | 69 | 주로 Kafka, Foreach, File (Parquet) Sink 가 사용됩니다. 70 | 71 | * **Kafka Sink** 를 통해 다른 Topic 으로 결과 데이터를 실시간으로 내보낼 때 사용할 수 있습니다. 72 | * **File Sink** 를 통해 CDC 등의 데이터를 S3 로 Parquet 등의 Format 으로 적재할 수 있습니다. 73 | * **Foreach Sink** 를 통해 Structured Streaming 이 지원하지 않는 저장소 (e.g., Dynamo) 등으로 전송할 수 있습니다. 74 | 75 | 76 | 77 | ![Spark Structured Streaming Output Sink (Link)](<../../.gitbook/assets/image (24).png>) 78 | 79 | 80 | 81 | 82 | 83 | foreach 와 foreachBatch Sink 의 경우 차이점은 다음과 같습니다. 84 | 85 | * foreach 는 단건씩 처리할 수 있는 반면 86 | * foreachBatch 는 하나의 Micro-batch 의 전체 결과 데이터를 DataFrame 으로 받아 사용할 수 있습니다. 87 | 88 | 89 | 90 | foreach Sink 의 open 과 close 는 Micro-batch 마다 한번씩 호출됩니다. open 에서 true 를 리턴해야 하며 JDBC Connection 을 여는등 비싼 자원을 위한 연산을 여기서 수행할 수 있습니다. 91 | 92 | 93 | 94 | ```scala 95 | streamingDatasetOfString.writeStream.foreach( 96 | new ForeachWriter[String] { 97 | 98 | def open(partitionId: Long, version: Long): Boolean = { 99 | // Open connection 100 | } 101 | 102 | def process(record: String): Unit = { 103 | // Write string to connection 104 | } 105 | 106 | def close(errorOrNull: Throwable): Unit = { 107 | // Close the connection 108 | } 109 | } 110 | ).start() 111 | ``` 112 | 113 | 114 | 115 | 116 | 117 | ### Trigger 118 | 119 | 120 | 121 | **Trigger** 를 이용해 얼마의 주기마다 Output Sink 로 데이터를 보낼지를 결정할 수 있습니다. Trigger 를 지정하지 않으면 Micro-batch 가 가장 빨리 수행될 수 있는 주기로 실행됩니다. 122 | 123 | * `Trigger.ProcessingTime` 를 사용하는 경우, 이전 작업이 끝나지 않으면 다음 Micro-batch 를 수행하지 않습니다. 이전 작업이 끝난 뒤에야 수행 됩니다. 만약 이전 작업이 일찍 끝났다면 Interval 이 만료 되기까지 대기한 후 실행합니다. 124 | * `Trigger.Continuous` 는 **Continuous Processing Mode** 를 지원하기 위한 Trigger 입니다. 실험 단계이며 일부 제약조건이 있을 수 있습니다. 125 | 126 | 127 | 128 | ```scala 129 | // ProcessingTime trigger with two-seconds micro-batch interval 130 | df.writeStream 131 | .format("console") 132 | .trigger(Trigger.ProcessingTime("2 seconds")) 133 | .start() 134 | 135 | // One-time trigger 136 | df.writeStream 137 | .format("console") 138 | .trigger(Trigger.Once()) 139 | .start() 140 | 141 | // Continuous trigger with one-second checkpointing interval 142 | df.writeStream 143 | .format("console") 144 | .trigger(Trigger.Continuous("1 second")) 145 | .start() 146 | ``` 147 | 148 | 149 | 150 | ### Summary 151 | 152 | 이번 챕터에서 나온 개념 또는 용어 대한 정리입니다. 153 | 154 | * Output Mode 155 | * Append / Update / Complete 156 | * Output Sink 157 | * File / Kafka / Foreach / Foreach Batch 158 | * Trigger (Micro-batch Interval) 159 | -------------------------------------------------------------------------------- /02-processing/2.4-stream/README.md: -------------------------------------------------------------------------------- 1 | # 2.4 스트림 (Stream) 처리 2 | 3 | 이 챕터에서는 Stream 을 사용하기 위한 이론과 Kafka 등 스토리지에 알아보고 Spark 와 Flink 를 사용하 스트림 데이터를 다루어봅니다. 4 | -------------------------------------------------------------------------------- /04-data-storage/4.2.md: -------------------------------------------------------------------------------- 1 | # 4.2 Redis 2 | 3 | Practical AWS Pipeline 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /04-data-storage/4.3-rdb-mysql.md: -------------------------------------------------------------------------------- 1 | # 4.3 RDB (MySQL) 2 | 3 | Practical AWS Pipeline 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /04-data-storage/4.4.md: -------------------------------------------------------------------------------- 1 | # 4.4 ElasticSearch 2 | 3 | Practical AWS Pipeline 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /04-data-storage/4.5-kv-storage-dynamodb.md: -------------------------------------------------------------------------------- 1 | # 4.5 KV Storage (DynamoDB) 2 | 3 | Practical AWS Pipeline 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /04-data-storage/4.6-druid.md: -------------------------------------------------------------------------------- 1 | # 4.6 Druid 2 | 3 | Practical AWS Pipeline 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /04-data-storage/untitled/4.1-kafka-concept.md: -------------------------------------------------------------------------------- 1 | # 4.1 Kafka Concept 2 | 3 | 이번 챕터에서는 Kafka 의 구성 요소와 아키텍쳐에 대해 이야기를 나눕니다. 4 | 5 | 6 | 7 | 8 | 9 | ### Broker 10 | 11 | 12 | 13 | ### Consumer 14 | 15 | 16 | 17 | ### Producer 18 | 19 | 20 | 21 | ### Topic 22 | 23 | 24 | 25 | ### Partition and Offset 26 | 27 | 28 | 29 | ### Segment 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ### Practice 38 | 39 | TBD 40 | 41 | ### Summary 42 | 43 | TBD 44 | -------------------------------------------------------------------------------- /04-data-storage/untitled/4.2-kafka-advanced.md: -------------------------------------------------------------------------------- 1 | # 4.2 Kafka Advanced 2 | 3 | ### Log Compaction 4 | 5 | TBD 6 | 7 | 8 | 9 | ### Async Producing 10 | 11 | TBD 12 | 13 | 14 | 15 | ### Transaction 16 | 17 | TBD 18 | 19 | 20 | 21 | ### Leader Election 22 | 23 | TBD 24 | 25 | 26 | 27 | ### Consumer Rebalancing 28 | 29 | TBD 30 | 31 | 32 | 33 | ### 34 | -------------------------------------------------------------------------------- /04-data-storage/untitled/4.3-kafka-versions.md: -------------------------------------------------------------------------------- 1 | # 4.3 Kafka Versions 2 | 3 | 미공개 챕터입니다. 4 | 5 | -------------------------------------------------------------------------------- /04-data-storage/untitled/README.md: -------------------------------------------------------------------------------- 1 | # 4.1 Kafka 2 | 3 | Practical AWS Pipeline 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /05-data-application/5.2.md: -------------------------------------------------------------------------------- 1 | # 5.2 통계 서비스 2 | 3 | Practical Spark 의 실습 과정입니다. 4 | -------------------------------------------------------------------------------- /05-data-application/5.3.md: -------------------------------------------------------------------------------- 1 | # 5.3 추천 서비스 2 | 3 | Practical Spark 의 실습 과정입니다. 4 | -------------------------------------------------------------------------------- /05-data-application/5.4.md: -------------------------------------------------------------------------------- 1 | # 5.4 A/B 테스팅 2 | 3 | Practical AWS Pipeline 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /05-data-application/untitled.md: -------------------------------------------------------------------------------- 1 | # 5.1 데이터 서비스 2 | 3 | -------------------------------------------------------------------------------- /08-case-study/week-1-data-pipeline.md: -------------------------------------------------------------------------------- 1 | # Week 1 - Data Pipeline 2 | 3 | Practical Spark 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /08-case-study/week-2-emr-and-kubernetes.md: -------------------------------------------------------------------------------- 1 | # Week 2 - EMR & Kubernetes 2 | 3 | Practical Spark 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /08-case-study/week-3-metastore.md: -------------------------------------------------------------------------------- 1 | # Week 3 - Metastore 2 | 3 | Practical Spark 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /08-case-study/week-4-kv-and-delta-storage.md: -------------------------------------------------------------------------------- 1 | # Week 4 - KV & Delta Storage 2 | 3 | Practical Spark 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /08-case-study/week-5-kafka-rebalancing.md: -------------------------------------------------------------------------------- 1 | # Week 5 - Kafka Rebalancing 2 | 3 | Practical Spark 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /08-case-study/week-6-ml-pipeline.md: -------------------------------------------------------------------------------- 1 | # Week 6 - ML Pipeline 2 | 3 | Practical Spark 의 이론 과정입니다. 4 | -------------------------------------------------------------------------------- /09-installation/druid.md: -------------------------------------------------------------------------------- 1 | # Druid 설치 및 환경 구성 2 | 3 | -------------------------------------------------------------------------------- /09-installation/dynamodb.md: -------------------------------------------------------------------------------- 1 | # DynamoDB 사용을 위한 환경 구성 2 | 3 | -------------------------------------------------------------------------------- /09-installation/elasticsearch.md: -------------------------------------------------------------------------------- 1 | # ElasticSearch 설치 및 환경 구성 2 | 3 | -------------------------------------------------------------------------------- /09-installation/flink.md: -------------------------------------------------------------------------------- 1 | # Flink 설치 및 환경 구성 2 | 3 | -------------------------------------------------------------------------------- /09-installation/kafka.md: -------------------------------------------------------------------------------- 1 | # Kafka 설치 및 환경 구성 2 | 3 | -------------------------------------------------------------------------------- /09-installation/mysql.md: -------------------------------------------------------------------------------- 1 | # MySQL 설치 및 환경 구성 2 | 3 | -------------------------------------------------------------------------------- /09-installation/presto.md: -------------------------------------------------------------------------------- 1 | # Presto 설치 및 환경 구성 2 | 3 | -------------------------------------------------------------------------------- /09-installation/spark/README.md: -------------------------------------------------------------------------------- 1 | # Spark 설치 및 환경 구성 2 | 3 | -------------------------------------------------------------------------------- /09-installation/spark/spark-databricks-saas.md: -------------------------------------------------------------------------------- 1 | # Spark - Databricks 환경 (SaaS) 2 | 3 | -------------------------------------------------------------------------------- /09-installation/spark/spark-emr.md: -------------------------------------------------------------------------------- 1 | # Spark - EMR 환경 2 | 3 | 작성중입니다 4 | -------------------------------------------------------------------------------- /09-installation/spark/spark-kubernetes.md: -------------------------------------------------------------------------------- 1 | # Spark - Kubernetes 환경 2 | 3 | 작성중입니다 4 | -------------------------------------------------------------------------------- /09-installation/spark/spark-local-jupyter.md: -------------------------------------------------------------------------------- 1 | # Spark - Local Jupyter 환경 2 | 3 | 작성중입니다 4 | -------------------------------------------------------------------------------- /09-installation/spark/spark-local-shell.md: -------------------------------------------------------------------------------- 1 | # Spark - Local Shell 환경 2 | 3 | 작성중입니다 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Practical Data Pipeline 2 | 3 | All content is written in Korean. 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [Practical Data Pipeline](README.md) 4 | * [시작 전에 드리는 당부의 말](undefined.md) 5 | 6 | ## 01 - 데이터 인프라 7 | 8 | * [1.1 데이터 파이프라인](01-data-infra/1.1.md) 9 | * [1.2 데이터 입수 (Ingestion)](01-data-infra/1.2.md) 10 | * [1.2 데이터 가공 (Processing)](01-data-infra/1.2-processing.md) 11 | * [1.3 데이터 저장 (Storage)](01-data-infra/1.3-storage.md) 12 | * [1.4 데이터 분석 (Analysis)](01-data-infra/1.3.md) 13 | 14 | ## 02 - 데이터 처리 15 | 16 | * [2.1 데이터 처리](02-processing/2.1.md) 17 | * [2.2 배치 (Batch) 처리](02-processing/2.2-batch/README.md) 18 | * [2.1.1 Spark Intro](02-processing/2.2-batch/2.1.1-spark-intro.md) 19 | * [2.1.2 Spark Tutorial](02-processing/2.2-batch/2.1.2-spark-architecture.md) 20 | * [2.1.3 Spark Concept](02-processing/2.2-batch/2.1.3-spark-concept.md) 21 | * [2.1.4 Spark Architecture](02-processing/2.2-batch/2.1.4-spark-architecture.md) 22 | * [2.1.5 Spark DataFrame](02-processing/2.2-batch/2.1.x-spark-dataframe.md) 23 | * [2.1.6 Spark Persistence](02-processing/2.2-batch/2.1.x-spark-persistence.md) 24 | * [2.1.7 Spark Cache](02-processing/2.2-batch/2.1.x-spark-cache.md) 25 | * [2.1.8 Spark SQL & Table](02-processing/2.2-batch/2.1.x-spark-sql-and-table.md) 26 | * [2.1.9 Spark Join](02-processing/2.2-batch/2.1.x-spark-join.md) 27 | * [2.2.1 Spark Memory](02-processing/2.2-batch/2.1.5-spark-memory-management.md) 28 | * [2.2.2 Spark Versions](02-processing/2.2-batch/2.2.2-spark-versions.md) 29 | * [2.3 워크플로우 (Workflow) 관리](02-processing/2.3-workflow.md) 30 | * [2.4 스트림 (Stream) 처리](02-processing/2.4-stream/README.md) 31 | * [2.4.1 Kafka Intro](02-processing/2.4-stream/2.4.1-kafka-intro.md) 32 | * [2.4.2 Kafka Advanced](02-processing/2.4-stream/2.4.2-kafka-advanced.md) 33 | * [2.4.3 Spark Streaming](02-processing/2.4-stream/2.4.3-spark-streaming.md) 34 | * [2.4.4 Streaming Window](02-processing/2.4-stream/2.4.4-streaming-window.md) 35 | * [2.4.5 Streaming State](02-processing/2.4-stream/2.4.5-streaming-state.md) 36 | * [2.4.6 Streaming Sink](02-processing/2.4-stream/2.4.6-streaming-sink.md) 37 | 38 | ## 04 - 데이터 스토리지 39 | 40 | * [4.1 Kafka](04-data-storage/untitled/README.md) 41 | * [4.1 Kafka Concept](04-data-storage/untitled/4.1-kafka-concept.md) 42 | * [4.2 Kafka Advanced](04-data-storage/untitled/4.2-kafka-advanced.md) 43 | * [4.3 Kafka Versions](04-data-storage/untitled/4.3-kafka-versions.md) 44 | * [4.2 Redis](04-data-storage/4.2.md) 45 | * [4.3 RDB (MySQL)](04-data-storage/4.3-rdb-mysql.md) 46 | * [4.4 ElasticSearch](04-data-storage/4.4.md) 47 | * [4.5 KV Storage (DynamoDB)](04-data-storage/4.5-kv-storage-dynamodb.md) 48 | * [4.6 Druid](04-data-storage/4.6-druid.md) 49 | 50 | ## 05 - 데이터 애플리케이션 51 | 52 | * [5.1 데이터 서비스](05-data-application/untitled.md) 53 | * [5.2 통계 서비스](05-data-application/5.2.md) 54 | * [5.3 추천 서비스](05-data-application/5.3.md) 55 | * [5.4 A/B 테스팅](05-data-application/5.4.md) 56 | 57 | ## 08 - Case Study 58 | 59 | * [Week 1 - Data Pipeline](08-case-study/week-1-data-pipeline.md) 60 | * [Week 2 - EMR & Kubernetes](08-case-study/week-2-emr-and-kubernetes.md) 61 | * [Week 3 - Metastore](08-case-study/week-3-metastore.md) 62 | * [Week 4 - KV & Delta Storage](08-case-study/week-4-kv-and-delta-storage.md) 63 | * [Week 5 - Kafka Rebalancing](08-case-study/week-5-kafka-rebalancing.md) 64 | * [Week 6 - ML Pipeline](08-case-study/week-6-ml-pipeline.md) 65 | 66 | ## 09 - 설치 및 환경 구성 67 | 68 | * [Spark 설치 및 환경 구성](09-installation/spark/README.md) 69 | * [Spark - Local Shell 환경](09-installation/spark/spark-local-shell.md) 70 | * [Spark - Local Jupyter 환경](09-installation/spark/spark-local-jupyter.md) 71 | * [Spark - Kubernetes 환경](09-installation/spark/spark-kubernetes.md) 72 | * [Spark - EMR 환경](09-installation/spark/spark-emr.md) 73 | * [Spark - Databricks 환경 (SaaS)](09-installation/spark/spark-databricks-saas.md) 74 | * [Flink 설치 및 환경 구성](09-installation/flink.md) 75 | * [Kafka 설치 및 환경 구성](09-installation/kafka.md) 76 | * [MySQL 설치 및 환경 구성](09-installation/mysql.md) 77 | * [DynamoDB 사용을 위한 환경 구성](09-installation/dynamodb.md) 78 | * [ElasticSearch 설치 및 환경 구성](09-installation/elasticsearch.md) 79 | * [Presto 설치 및 환경 구성](09-installation/presto.md) 80 | * [Druid 설치 및 환경 구성](09-installation/druid.md) 81 | -------------------------------------------------------------------------------- /undefined.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Disclaimer 3 | --- 4 | 5 | # 시작 전에 드리는 당부의 말 6 | 7 | 이 책은 Fully-opinionated 된 내용을 담고 있습니다. 8 | 9 | * 한 개인의 경험을 기반으로 씌여졌으며 10 | * AWS 클라우드를 이용해 물리 비용을 적게들여 데이터 시스템을 구성하거나 11 | * 일부 경우에는 물리 비용을 내더라도 노동 비용을 줄일 수 있는 방법에 대해이야기 합니다. 12 | 13 | 내용의 작성 시점과 보는 시점의 차이로 인해 일부 내용이 잘못되었을 수 있으며, 피드백을 댓글 또는 아래의 Repository 내의 이슈로 생성해 주시면 공개된 장소에서 논의를 거쳐 내용을 수정할 수 있습니다. 14 | 15 | * [Github Repository - Practical Data Pipeline](https://github.com/1ambda/practical-data-pipeline/issues) 16 | 17 | --------------------------------------------------------------------------------