<@UP0NUJHSA> 안녕하세요? 오늘 저녁에 GraphQL Korea에 처음 들어와서 ...
# 질문
m
@SinYooDong 안녕하세요? 오늘 저녁에 GraphQL Korea에 처음 들어와서 늦었습니다 ^^; 양해부탁드립니다 🙂 장문이라 화면 폭이 좁은 쓰레드에 작성하면 화면이 너무 길어질까 싶어 채널에 바로 썼는데, 자리를 너무 차지한다고 하시면 쓰레드로 옮기겠습니다. [Prisma 2 = Prisma Framework] > 1. 기존 Prisma와 같이 db schema와 resolve 생성 및 관리 네, 아키텍처와 성능, 동작구조, 디테일이 바뀌었지만, 사용자 입장에서 high level로 바라볼 때, Photon, Lift, Studio 모두 논리적으로 기존 Prisma를 계승합니다. 다만, 각각의 관심사를 더 명확히 나눠, 필요에 따라 개별/통합 사용을 모두 원할히 하려는 의도로 볼 수 있습니다. 물론 단순히 사용자 편의만의 고려는 아니고 (그간 많이 제기된 요청처럼) 실제 아키텍쳐도 Prisma에 같이 있던 것을 모두 다른 위치로 나누었기 때문이기도 합니다. Prisma Framework로 이름이 불리는 이유는 데이터 모델과 CLI 를 중심으로 같이 잘 융화되기 때문입니다. 말씀해주신 "db schema 생성 및 관리"는 개발자가 작성한 데이터 모델을 보고 Lift가 수행합니다. 다만, Prisma 2(Prisma Framework)가 "resolver 생성 및 관리"(nexus, nexus-prisma 몫)를 자동으로 해주지는 않습니다. 사용 언어별(e.g. js, ts, go)로 language-specfic 한 generator가 있고, generator가 데이터 모델을 보고(정확히 말하면 Core 가 노출한 SchemaDefinition 을 보고) Photon 을 생성해줍니다. 여기서, Prisma 1은 자동으로(노출시키는 결정은 개발자 몫) GraphQL을 생성해줬지만, Photon은 오직 data access 만 담당합니다(Prisma 1의 client 역할). > 2. 요청된 Graphql Query에 맞게 db쿼리 재조합 및 1:N관계의 쿼리 요청 최적화 Photon 은 Query Engine(Prisma 2의 4가지 "Engine" 중 하나입니다) 에 의존하고, Query Engine은 Core 와 Connector 로 구성되어 있습니다. Core는 단 하나의 (Rust로 쓰인) 바이너리고, Connector는 Data Source 와 DataSource-specfic 한 상호작용(e.g. RDB의 SQL, FaunaDB의 FQL, ElasticSearch의 REST 등)을 담당합니다. Prisma 2는 Virtual Database 를 모토로 하기 때문에 여러 Connector를 하나의 Core에 연결하고, 사용자는 Photon으로 여러 DB를 하나처럼 추상화된 방식으로 상호작용할 수 있습니다. 여기서 주목할 점은 Core가 Query Optimization 을 수행하고 Connector가 Query Creation 을 수행한다는 것입니다. 저는 처음에 Data Source와 관계가 없는 Core가 어떻게 Query Optimization 을 수행한다는 것인지 의문이었는데, Batch (dataloader 역할) 를 해주는 것이었습니다. 이때, Photon call 하나에 Data Source별로 Connector가 각각 한번씩만(e.g. SQL이 한번에 Join) 호출되는 것이 아니라, Core가 Photon call을 여러개의 작은 논리적 조각으로 나눠서 Connector를 호출합니다. 마치 GraphQL resolver 가 각 node마다 따로 동작하는 것과 유사합니다. 그래서 "완전한" 최적화는 아니라고 할 수 있습니다. > 3. 개발되는 서비스 API 서버안에서 Graphql 관련해서 사용되는 느낌. 맞습니다. Hasura랑 반대입니다. Prisma는 개발되는 서버 "안에"(Prisma 1에선 "뒤에") 있고, Hasura는 "앞에" 있습니다 (물론 Hasura를 "뒤에" 놓을 수도 있고, 실제 사례도 있습니다. 아키텍쳐는 요구사항에 따라, trade-off 에 따라 다르니까요.). Prisma 2의 지향은 "Stack-free" (여러 언어 사용가능) + "Virtual Database client"(여러 database 를 하나처럼 사용가능) + "DataModel-driven backend"(Datamodel 중심 API/migration) 이고 서비스 중심/서버중심 접근이라고 생각합니다. [Hasura] > 1. 요청된 Graphql Query에 맞게 db쿼리 재조합 및 1:N관계의 쿼리 요청 최적화 네, 맞습니다. 다만 어떤 Query던 (어떤 관계던) 최적화합니다. 단순히 Join해서 Query/Mutation을 하나의 SQL로 대응하는 것을 넘어서, Postgres에 최적화 된 방법들(그 중 예가 발표 당시 Json 변환과 PreparedStatement 였습니다.)을 사용합니다. (여담으로 MySQL 도 나온다고 합니다. 지금까지 성능(CPU, RAM, Response Time, Parallelism, Simple/Deep Query)을 상당히 중시하는 모습을 보였기 때문에 MySQL도 최적화된 설계로 나올 것 같습니다.) > 2. 개발되는 서비스 API 서버와 별개로 backend, frontend 상관없이 최적의 Query로 data 사용(read,write)을 할 수 있는 서버, 그 외 서비스적 처리(알림전송, 정산금액계산등...)는 microservices단위 개발이 더 효율적 Hasura는 Backend as a Service 처럼 볼 수 있다고 생각합니다. 동기적인 API 를 개발할 때는 서비스에 따라 "microservices 단위 개발이 더 효율적"일 수도 있고, Event Trigger에 의한 webhook 과 "Actions"(Preview) 를 사용해 비동기 API 를 개발하면 Serverless 단위 개발이 더 효율적일 수 있습니다. Generated GraphQL 에 추가적인 Logic이 필요할 때, Hasura의 Auth 시스템으로 커버가 어려운 복잡한 rule 이 있는 상황, MicroService 등, Custom Business Logic/API 을 어떻게 작성하는지 보고 Hasura의 접근 방식을 생각해 볼 수 있다고 생각하는데요, 총 6가지가 있습니다. 1. View: "GraphQL type 에 Computed/Derived Field 를 추가하고 싶을때", Postgres에 View를 작성합니다. View도 하나의 GraphQL Type 이 되어, table 에 의한 Type과 "Relationship" 을 맺어줍니다. 이때 Relationship 은 마치 SQL Join 에 비유할 수 있습니다. 문서: https://docs.hasura.io/1.0/graphql/manual/queries/derived-data.html 2. Function: 이번엔 "Custom GraphQL Query/Subscription를 추가하고 싶을 때", Postgres 에 Function 을 작성합니다. 저는 Mutation 도 되게했으면 했었는데, Mutation 은 "Actions" 에서 지원할 예정입니다. 문서: https://docs.hasura.io/1.0/graphql/manual/queries/custom-functions.html 3. Remote Schema: 외부 GraphQL API를 (직접 개발 또는 3rd party SaaS, microservice, 또 다른 Hasura 등) Hasura와 합치는 기능입니다. 서로 의존하지 않는 스키마를 통째로 합칠때 특히 더 유용합니다 (물론 의존하는 경우도 됩니다). (Hasura 가 "앞에" 있습니다. 그 부가 효과로 Authentication 은 따로 안해도 됩니다.) 4. Remote Join: 외부 GraphQL API 를 SQL 처럼 "JOIN" 하는 방식입니다. 역시 Hasura가 "앞에" 있습니다. 이때도 "Relationship"을 맺어줍니다. 현재 Release 가 아닌 Preview 상태 입니다. 링크: https://blog.hasura.io/remote-joins-a-graphql-api-to-join-database-and-other-data-sources/) 5. Actions: SDL로 mutation schema 를 작성하고 (이때 Hasura가 제공하는 type을 바로 명시가능합니다.), Action Handler 로 실제 Logic 을 작성합니다. 이때 (특히 긴 작업의 경우) async 한 API로도 활용하기 좋습니다. Hasura 가 Action 의 결과를 볼 수 있는 Query/Subscription 을 모두 만들어 주므로 Client는 Promise 처럼 API 를 호출합니다. 현재 Preview 상태 입니다. 링크1: https://deploy-preview-3042--hasura-docs.netlify.com/graphql/manual/actions/index.html 링크 2: https://deploy-preview-3042--hasura-docs.netlify.com/graphql/manual/actions/index.html PR: https://github.com/hasura/graphql-engine/pull/3042 6. Webhook(Event Trigger): Event(
INSERT
,
UPDATE
,
DELETE
등) 발생시 Hasura가 webhook(serverless 에 좋겠죠) 을 호출해 줍니다. (Hasura 없이 Postgres 대상으로 직접 구현하실 분들은 https://github.com/hasura/skor 참조하시면 어떨까 합니다.) Async 한 business logic/backend 에 쓰일 수 있습니다. 링크: https://docs.hasura.io/1.0/graphql/manual/event-triggers/index.html 심플하게 말하면 View, Function 은 Database-level 이고, Remte Schema, Remote Join 은 GraphQL-level로 볼 수 있습니다. Actions는 GraphQL-level(Schema 확장)에 Http-level(Handler), Database-level(Handler) 모두 해당(Action Handler로 Http, Postgres 모두 가능합니다.)되고(+Async), Webhook 은 Http-level(+Async) 로 볼 수 있습니다. Hasura의 접근방식은 Database 또는 GraphQL, Http 레벨에서 해결하는 것입니다. SaaS/micro/nanoservice 는 상황에 맞게 배합하면 됩니다. 결론적으로 Hasura 의 지향은 "(Datasource-specific/Engine) Optimization" + "Data(base)-driven backend/API" + "BaaS" 와 GraphQL 중심 접근(Remote Schema/Join 등)에 있다고 생각합니다.
👍 4
🙇‍♂️ 2
🤩 2
s
@MARU 먼저 정확하고 깊이 있는 답변을 해주셔서 감사드립니다. 각 서비스들의 기본 설명들을 해석하면서 공부했지만, 언어적 차이 때문에 모호하게 이해했던 점을 확실하게 잡을 수 있었습니다. 감사합니다 😍 [prisma2] 1. 기존 Prisma와 같이 db schema와 resolve 생성 및 관리 => prisma2에서 소개하는 3가지 서비스에 대해서 서로 통합 또는 연동에 대해서 어느정도 가능한지와 퀄리티는 어떤지 확인을 해야겠다는 생각이 드는 답변이였습니다. 독립적으로 지원하는것에 장점은 확실하게 있으나, 나눠진만큼 앞으로의 업데이트를 통해 '어쩔수없는' 연동 불가가 생길 수 있으니깐요. 2. 요청된 Graphql Query에 맞게 db쿼리 재조합 및 1:N관계의 쿼리 요청 최적화 => 설명해주신대로는 진짜 꿈같은 이야기입니다 ㅎㅎ 하나의 큰 서비스는 단일 DB로는 불가능한게 현실이도 서로 통합한다는 것 자체가 이슈 덩어리에 개발요소가 들어갈수밖에 없는 요소인데 이걸 해결해준다는 것에 감격할 수 밖에없네요. 말씀해주신 Photon의 행보를 추척해 나아가겠습니다. 3. 개발되는 서비스 API 서버안에서 Graphql 관련해서 사용되는 느낌. => 답변 해주신거에 hasura와 차이점을 통해 아키텍처 구상에 도움이 되었습니다. 감사합니다. [Hasura] 1. 요청된 Graphql Query에 맞게 db쿼리 재조합 및 1:N관계의 쿼리 요청 최적화 => 최적화에 너무나도 맘에 들고 Main이됬든 Sub가 됬든 하나의 독립적인 서비스를 위한 선택에 대해서는 과감하게 선택할만 한 것 같습니다 ㅎㅎ... (private성 강하게 하려면 Docker로 해야되는것만 빼면...) 2. 개발되는 서비스 API 서버와 별개로 backend, frontend 상관없이 최적의 Query로 data 사용(read,write)을 할 수 있는 서버, 그 외 서비스적 처리(알림전송, 정산금액계산등...)는 microservices단위 개발이 더 효율적 =>설명해주신 6가지의 지원 기능에 대해서 설명해주셔서 감사드립니다. 좀 더 명확한 아키텍터 구상에 도움이 됩니다 ㅠㅠ 제가 serverless 또는 microservies 단위 개발로 넘어가지 못한 이유가 '솔로'개발이기 때문에 개발효율 면에서 큰 이득 을 못가진점을 가장 크게 가졌었는데... 코드의 신뢰성, 데이터의 신뢰성을 어느정도 보장해줄 수 있는 기능이라고 생각되기에 충분한 검토를 해야되겠다는 생각이 드는 설명이였습니다. 다시 한번 질좋은 답변에 감사드립니다. 😀