기본 콘텐츠로 건너뛰기

microservice 기반 meteor application 설계 /w DDP

특정 업무가 장애가 일어나도 전체가 다운되지 않는 서비스를 Meteor 로 만들 수 있지 않을까 라는 생각을 하고 있었는데 실제로 한번 해보았다.

로긴 서버와 N개의 업무서버가 하나의 DB를 바라보고 클라이언트에서 로긴 서버에 계정생성/접속 후 토큰을 꺼내와서 나머지 서버에 접속하는 그림을 그려보았다.

업무 서버의 경우 웹앱에서 접근 문제가 있기 때문에 CORS를 열어준다.

Meteor.startup ->
  WebApp.rawConnectHandlers.use (req, res, next)->
    res.setHeader "Access-Control-Allow-Origin", "*"
    next()

iOS/Android 앱의 경우는 사실 상관이 없지만 webApp인 경우엔 꼭 필요.

반대로 webApp 인 경우는 client 폴더에만 작업하면 되는데
가장 먼저 실행하는 파일(ex. client/lib) 에 DDP와 Collection 연결하는 부분을 만들어 준다.

# global namespace
@ddps =
  loginDDP : DDP.connect "http://localhost:4100"
  chatDDP : DDP.connect "http://localhost:4200"

# models
@Chats = new Mongo.Collection 'chats', ddps.chatDDP

그리고 Meteor App 이 시작하는 시점에 아래와 같이 구성한다.

Meteor.startup ->
  Meteor.connetion = ddps.loginDDP
  Tracker.autorun ->
    if Meteor.user()?
      unless Meteor.loggingIn()
        console.log Meteor.user()?.username
        ddps.chatDDP.call "login",
         resume: Accounts._storedLoginToken()
        , (e, r)->
          unless e
            console.log "chatDDP login", r
          else
            throw e
    else
      ddps.chatDDP.call "logout", (e)->
        console.log "chatDDP logout" unless e
      console.log "out"

Meteor.connection을 login의 DDP로 지정해놓으면 마치 자기 서버인것 처럼 쓸 수 있어서 편리하다.
그리고 Meteor.user() 가 Reactive Datasource 이므로 Tracker.autorun 안에서 로그인 서버에서 로그인/아웃시 다른 업무 서버도 로그인/아웃 하도록 DDP.call "login" method를 불러준다.

단,  DDP 로그인 시 Accounts 패키지의 _storedLoginToken()을 통해 token값을 꺼내서 로그인 방식과 상관없이 동일하게 처리하면 편리하다.

헬퍼나 템플릿 안에서 쓸때도 기존 방식과 거의 같다.

Template.chatroom.onCreated ->
  ddps.chatDDP.subscribe 'getChats', {}

onCreated 에선 this.subscribe (혹은 @subscribe) 대신 DDP.subscribe를 사용하고 Method.call도 같은 방식으로 ddps.chatDDP.call "addChat", params 와 같이 사용한다.

이와 같은 방식으로 개발 중인데 장단점을 따져보면
장점.
  1. 작게 나눠서 독립적인 서버를 개발하므로 단인 서비스의 복잡도가 낮다.
  2. 오류와 서버다운에 대해 독립적이고 스케일 아웃도 간편
  3. 싼 클라우드 호스팅을 여러개 나눠서 쓸 수 있다.
  4. I/O 부담을 분산한다.
단점.
  1. 개인 개발 서버 환경이 매우 무겁다.(......)
정도인데 꼭 Meteor 가 아닌 다른 프레임웍(Horizon이라던가 Phoenix라던가 혹은 기타 레거시 웹서비스등등)하고 연동도 자유로와서 꽤 연구 가치가 있다.

이 블로그의 인기 게시물

Mac 주의 - 약간 빡치는 git 대소문자 변환 파일명 변환(renaming)하는 법

Mac에서 종종 화나는 일 중 하나가 파일 시스템이 대소문자를 구분하지 않는 점이다.
가령, A.png를 a.png로 바꿔야할 경우 HFS 기준으론 전혀 바뀐 점이 없는 걸로 인식하는데 다소 화가난다.
하지만, 방법이 없는 것은 아닌데

A.png를 임의의 다른 파일로 바꾼다. (ex. A_.png)1에서 바꾼 상태에서 staging 한다. (git add A_.png)1의 파일을 다시 원래 바꾸려고 했던 파일로 바꾼다. (mv A_.png a.png)3을 다시 staging 한다. (git add a.png)commit 한다.https://stackoverflow.com/a/40307511/880991 에서 답변해준 Chris Barr 님에게 감사를.
* 추가

실제로 해보니 git mv --force A.png a.png 가 더 간단하다. 이는 바로 staging 영역에 add까지 해준다.

즐거운 Online Prototyping Tool 들

jsbin, codepen, jsfiddle 이런 것들은 일단 생략. 너무 유명한 것들이라.

https://launchpad.graphql.com - node.js 기반 graphQL 연습장. 이것만으로도 충분히 훌륭한 백엔드
https://codesandbox.io/ npm 사용이 가능한 클라이언트 사이드 연습장. webpackbin이 너무 문제가 많아서 찾아본 것.

https://scrimba.com 이건 codesandbox+ asciinema(https://asciinema.org/) 같은 느낌인데 키 녹화와 음성 녹화 기능이 추가되었다. 다 좋은데 화살표 키로 빨리감기 뒤로감기 기능이 안되고 익스포트(youtube등)으로 지원이 없는게 아쉽다.

이 둘이 만나면? https://codesandbox.io/s/jvlrl98xw3?from-embed
뭐야 이거 무서워 하지마 ㄷㄷ;  graphql+react-native-web(부왘ㅋㅋ)

https://repl.it/languages 전통을 자랑하는 REPL 도구. 지원 언어 종류가 -_-;;;;;

https://tio.run/# repl.it? 장난함? 얘는 지원 언어가 무려 386종류. J랑 아희도 있다.

https://play.golang.org/ 즐거운 go playground. 소스 포멧팅 넘 좋아.

http://decaffeinate-project.org/repl/ 최고의 coffeescript REPL. 원래 용도는 coffee를 ecma6코드로 바꾸는 것이지만...

https://scaphold.io
https://www.graph.cool/ graphql backend service. scaphold.io는 설치도 필요없는 클라우드. graphcool은 호스팅+클라우드 다있음. 둘 다 막상막하. 푸쉬서버도 되고 뭐 미친득.

https://glitch.com/ gomix에서 결국 glitch로 안착.  node.js

https://www.shadertoy.com 잘하고 싶다! 쉐이다! 오디오도 된다!

http:/…

graphql 연습 /w launchpad

https://launchpad.graphql.com/mw9wkzv99
단순 전체쿼리+조건쿼리+추가

http://graphql.org/graphql-js/passing-arguments/
참고. random ID는 crypto 1.0.1 사용
  type Query {
    Members: [member]
    getMember(id: ID!): member
  }
  type member {
    id: ID!
    text: String
  }
  input memberInput {
    text: String
  }
  type Mutation {
    addMember(member: memberInput): member
  } SQL 정의. facebook 쪽은 스트링에 지지는 거 진짜 좋아하네. *.gql 파일이 있다고 하니 이해해주자.
resolver는 var buffer = [];
const resolvers = {
  Query: {
    Members: (root, args, context) => {
      return buffer;
    },
    getMember: (id)=> {
      return buffer.find(o=>o.id)
    }
  },
  Mutation: {
    addMember(_, {member}) {
      const mm = { ...member, id:randomBytes(10).toString('hex') };
      buffer.push(mm);
      return mm;
    }
  }
}; 평범 평범.
https://dev-blog.apollodata.com/tutorial-graphql-subscriptions-server-side-e51c32dc2951 다음으로 pub/sub 연습.
https://launchpad.graphql.com/xvn94n3ql   type Subscription {
    memberAdded: member
  } member가 added되는 순간을 감시. imp…