서론

서양문화권의 경우 글을 쓰고 읽는것이 꽤 보편화 되어있다. 이론으로는 수년전부터 알고있었지만 얼마전 동유럽 여행 갔다왔을때 좀 제대로 느끼게 된점이 전철이나 버스를 타면 대부분의 사람들은 그냥 가만히 있고, 10~20%정도는 스마트폰으로 게임하고, 5%정도는 종이책을 읽고있다. 비율로는 적어보이긴 하지만 0% ~ 1%를 차지하는 우리나라에 비해서는 엄청 많은 편이다.

필자의 경우 컴퓨터 전문서적을 제외하고 월간 1~2권정도의 책을 읽는데, 읽으면서 항상 생각하는점이

책을 집필하고 출간하기까지는 많은 시간과 노력이 필요하다. 하지만 이렇게 많은 시간과 노력을 쏟아 붇는다고 해도 끝까지 재미있는책은 무척이나 드문편인데, 이유는 대충 짐작이 간다. 출판해야되는 페이지수는 대충 정해졌는데 내가 할 이야기는 끝나버렸다. 그러니 억지로 채워넣다보니 앞쪽은 재밌어도 끝까지 재미있는책은 무척이나 드물게 되어버린다.

중학생들 독서록 10줄 써오라고 했는데 3줄밖에 못채워서 있는말 없는말 지어내서 10줄 간신히 채우는 그런 느낌이다.

그럼 억지로 채울려고 하지말고 자기가 재밌는 이야기만 하고 끝내는 수단이 있으면 좋지 않을까? 라고 생각해서 시작하고 있는게 바로 이 사이트이다.

블로그 글 보다는 좀 더 전문성이 있으면서도 책보다는 좀 더 가벼운 주제를 다루기 위한 사이트 Byeoru의 개발일기를 시작한다.


구성요소

이 프로젝트는 2019년 1월부터 시작했고 지금은 2019년 7월이다. 그 사이에 많은 시행착오가 있었고 결과론적으로 정하게된 최종 구성은 다음과 같다.

  • 구성
    • Microservice Architecture
    • Kubernetees 기반
    • Consul as
      • Service Discovery
      • Key Store
    • Traefik as
      • Load Balancer
  • View
    • Nuxt.js + Koa api gateway server
  • Service
    • Post
      • 게시글 관리를 담당
      • Node.js
      • MongoDB
    • Comment
      • 댓글 담당
      • Node.js
      • MongoDB
    • User
      • 유저 정보를 저장하고 인증까지 해줌
      • Kotlin + Ktor
      • MongoDB 혹은 MariaDB
    • OAuth
      • Naver, Google, Facebook등의 Oauth 서비스와 협상
      • Node.js
    • Search
      • 검색기능을 담당
      • Kotlin + ElasticSearch
    • Storage
      • 이미지나 첨부파일같은 파일을 저장
      • Node.js + Redis + S3 Storage

개발순서는 Nuxt.js로 웹사이트를 만들어가면서 그때그때 필요한 서비스를 개발해 나가는 순서.


https://vue.ant.design/docs/vue/customize-theme/

Ant design에는 기본 색상을 변경하는 방식으로 커스터마이즈가 가능함. 이 방법은 Ant design이 CSS로 사용하는 Less 의 변수값을 변경하는 구조를 사용하는데 좀 더 정확히는 less-loader에서 로드를 해오는 과정에서 변수값을 바꾸는 방식을 사용함.

이를 조작하기 위해서는 nuxt.config.js에서 build/loaders 부분을 변경하면됨.

module.exports = {
  build: {
    loaders: {
      less: {
        javascriptEnabled: true,
        modifyVars: { 'primary-color': '#1DA57A' }
      }
    },
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {}
  }
}

less 3.0 이후버전에서는 javascriptEnabled 기능이 기본적으로 비활성화 되어있음. 문제는 Ant design의 bezierEasingMixin 부분이 이 기능을 사용하는지라 위와같이 명시적으로 활성화를 시키지 않으면 오류가 나게됨. 아마 보안관련한 조치인듯?

추가적으로 nuxt.config.js의 css부분을 보면 'ant-design-vue/dist/antd.css'가 추가되어 있을텐데 이 부분은 다음과 같이 변경해야 less 로드과정이 생김.

css: [
    {
      src: 'ant-design-vue/dist/antd.less',
      lang: 'less'
    }
  ],

https://cngu.github.io/vue-typer/#style-showcase
https://nuxtjs.org/api/components-no-ssr/

외부 Vue Component 사용하려고 하는데

document is not defined

뜸. SSR에서 자주 있는 에러로 클라이언트쪽에서 그려주기위해서 element를 먼저 소환할 필요가 있는데 아직 element가 가상으로 이뤄지고있는 상황이라서 서버쪽에서 렌더링이 불가능한 경우.

로딩을 지연시켰다가 클라이언트쪽에서 모든 요소를 불러오면 활성화 시켜주면 됨.

const { VueTyper } = process.client ? require('vue-typer') : ''

추가적으로 컴포넌트쪽에도 <no-ssr></no-ssr>로 감싸주면 더욱 안정적


https://github.com/nhn/toast-ui.vue-editor

기본적으로 사용할 마크다운 에디터를 골랐다. 본래는 디자인이 좋아서 SimpleMDE를 사용했었는데, 사실 이쪽은 처음 사용할때부터 업데이트가 잘 안되서 불안불안 했었다. ToastUi는 기능은 세련되고 멋졌지만 좀 후져보이고 왠진 모르겠지만 처음 골랐을때는 Vue에서 사용가능하게 Wrapping한것을 못찼았어서 안썼다.

지금은 우연히도 Vue로 Wrapping한것을 발견했고, 몇몇가지 기능을 써보니 Markdown에 대해 Wysiwyg기능을 추가했다는걸 보고 바로 이걸로 택했다. 디자인의 경우 require 형식으로 CSS를 별도로 로딩하는 시스템을 택하여 쉽게 커스터마이징이 가능하다.

아직 특별히 단점은 안보인다.


https://nuxtjs.org/guide/vuex-store

에디터를 사용함과 동시에 이제 Store를 다뤄야할 시점이 왔다. 현재 Editor부분을 만들고 있는데 이 부분은 저번에 만들어둔게 있어서 디자인만 AntD와 Toast ui 에 맞게 바꾸고 내부로직은 저번에 작성한걸 그대로 가져왔다.

저번 개발환경과 지금 개발환경에서 Nuxt.js 버전 차이는 꽤 나는데 Vuex 와 Vue 버전은 별로 차이가 없어 특별한 수정없이 그대로 호환되서 빠르게 끝냈다.


https://nuxtjs.org/guide/routing#transitions

Nuxt.js 문서를 읽어보다가 발견했는데 Routing할때 기본 Transtion 효과를 간단하게 추가 가능하다.

.page-enter-active, .page-leave-active {
  transition: opacity .5s;
}
.page-enter, .page-leave-to {
  opacity: 0;
}

옛날에 WordData.xyz 만들때 PushState 쓰면서 Post 바뀔때마다 Transition 효과나게 삽질했던게 허무할정도로 쉽게되는걸 보니 뭔가 시원 씁슬하다.


https://milooy.wordpress.com/2015/08/21/htmlcss-유튜브-반응형으로-삽입하기-responsive-youtubeiframe-embed/

Youtube Embed 화면 Responsive 하게 만들기


http://www.gethugames.in/2012/04/authentication-and-authorization-for-google-apis-in-javascript-popup-window-tutorial.html

oAuth를 진행할때 팝업을 띄워서 로그인을 실행하는 방법. 부모 페이지에서 팝업창을 띄운다음 주기적으로 감시를 행하는데, 특정 링크에 접속할 경우 거기서 get 방식으로 받은 정보를 빼오는 구조.


https://www.consul.io/docs/connect/index.html#getting-started-with-connect

사용자 인증을 진행하면서 드디어 View와 Microservice간의 통신환경 구축이 필요해졌다. 이 프로젝트에서는 Consul이 해당역할을 진행할 예정인데..... Production 환경에서는 어찌됬던 Development 환경에서는 좀 까다로워질것 같다.

일단 Consul이 제공하는 Service Discovery방법은 2가지 이다.

  1. DNS를 통해서 요청한 서비스에대한 ip주소들을 제공해주는 방법. (PORT는.....;;;)
  2. Sidecar방식으로 두 서비스간 TLS로 암호화된 통신

처음에는 2번 방식으로 하려고 했는데 방법이 매우 까다롭다. 일단 두 서비스 A,B가 있다고 치면 A쪽에 Consul Agent 하나 두고, B쪽에 또하나 둔다음에 Consul Agent에는 어떤서비스랑 연결할껀지, 연결한 서비스를 local에서 어느포트로 접속할껀지 선언해줘야한다.

문제는 api-gateway의 경우 모든 서비스와 소통을 해야하는데 이걸 Sidecar 방식으로 구현하면 local에서 8000, 8001, 8002... 이런느낌으로 모두 다른 포트로 배정해줘야함..... 물론 그렇게 하면 L7수준의 로드밸런싱이 가능하고 편하긴 하지만..... 뭔가 귀찮아질꺼 같아서 그냥 패스.

일단 Consul은 단순히 KV Storage랑 Service Check 정도의 용도로 사용하고 로드밸런싱이나 기타 기능은 Kubenetees를 사용하기로 했다. 그러기 위해 일단 모든 api 통신의 URL은 (당연하지만) 설정파일로 빼둠


oAuth 관련해서 기초적인 사용자가 Google로 로그인했을때 Google에서 제공해주는 정보 받아오기! 와 관련된 api를 구현했다. 추후 facebook이나 naver도 추가하기 쉽게 구현한건 좋은데, 이와 관련해서 문서화 작업도 시작해야된다.....

일단은 각 프로젝트의 rootDir에다가 readme.md 만들어놓고 대충 작성해놓고는 있는데 체계화의 필요성을 느끼고 있다.

추가적으로 후에 user 관련된 별도의 서비스도 개발을 시작했다. 현재 고민점은 계속 개발하면서 코드가 바뀌고 있는 common 라이브러리들을 어떻게 실시간으로 공유할것인가 이다.

일단 공용 라이브러리만을 위한 별도의 프로젝트를 열고, 복사 붙혀넣기 해서 각 프로젝트에서 사용을 생각하고 있는데, 발견한게 윈도우에도 리눅스랑 비슷한 Link가 있다. GUI상에서는 바로가기랑 같지만 내부적으로는 리눅스의 Symbolic Link랑 비슷한 구조라나 뭐라나. 일단 이걸 적용해볼 생각이다.


https://github.com/avajs/ava-docs/blob/master/ko_KR/readme.md

ava 사용을 시작했다. 일단 한글문서가 존재한다는건 매우 큰 합격점. ㅎㅅㅎ


https://stackoverflow.com/questions/39694407/adding-javascript-type-hints-for-vscode-monaco-intellisence

Typescript가 아닌 Javascript를 쓰다보니깐 VScode가 Type을 몰라서 Intelisense가 제역할을 못함.....;;; 이걸써서 도움을 받아보려 했더니, 이걸 사용할려면 해당 파일 문맥에서 Type 선언까지 호출이 가능해야하는데, 그런상황이 아니라서 별 도움은 안된게 함정......


//20190727
Javascript에서는 항상 별 의문없이 await를 동기가 필요한 함수 바로앞에 갔다대서 썼었다.

const val = await someAsyncFunc(doSomething);

근데 당연하게도 그럴 필요는 없다. someAsyncFunc(doSomething) 을 호출하면 Promise를 반환하는데, await은 그 Promise(약속)을 기다리는것이 핵심임으로 다음과 같이 사용 가능하다.

const job1 = someAsyncFunc1(doSomething);
const job2 = someAsyncFunc2(doSomething);

// do Something

const val1 = await job1;
const val2 = await job2;

정말 당연한건데 왜 이제 깨달았는지.....


https://kr.vuejs.org/v2/guide/forms.html

React던 Vue던 기본적으로 Dataflow는 up-down 방식을 지향하기 때문에 부모Component에서 자식Component로 Props의 형태로 변수를 보내줄수 있어도 그 반대는 별로 권장하지 않는 분위기인거 같다.

하지만 방법이 없는건 아닌데 자식이 이벤트를 발생시켜 부모의 함수를 실행시키는 방법이 대표적이고 (Store) 그 다음이 v-model이다.

v-model의 경우 자식과 부모가 공유하는 변수이다. 다만 접근주체가 하나 이상이 되어버린만큼 코드를 잘못짜면 무한루프등의 형태로 보상해주고 유지보수가 매우 X같아 질수있으니 주의


https://github.com/nhn/tui.editor/pull/124
https://github.com/nhn/tui.editor/wiki/Getting-Started-Korean#events

tui-editor를 이 프로젝트의 메인 에디터로 쓰는것으로 확정했다. 솔직히 Customization이 어려울꺼 같아서 Quill이랑 많이 고민했는데, 결국 최강 마크다운 에디터로 결정했다.

Toolbar 버튼의 동작인 Popup으로 때울 예정이고, XSS 취약점 대책일 생각해봐야하는데 일단 hook에서 XSS filtering을 해보는것으로 구상중.


중간에 일지쓰는걸 깜빡해서 이제 주기적으로 진행상황을 적어보고자 한다.

일단 오늘은 2019년 07월 27일

완성된거

  • 로그인 및 회원가입 (백엔드까지)
  • 기본적인 디자인 틀

해야될꺼

  • Markdown html css
  • 글 업로드 관련 백엔드
  • tui-editor Customization

//20190727
https://stackoverflow.com/questions/55665100/how-to-prevent-user-to-leave-page-using-middleware-in-nuxt

글쓰고 저장안하고 나가려고 할때 확인을 요구하는 메세지를 만들려고 구현할때 일이다.

일단 새로고침이나 브라우저 창을 끌때 메세지를 표현하는건 쉬웠다.

window.onbeforeunload = (e) => {
    return ''
}

보안상 메세지문구는 브라우저가 설정한 메세지밖에 못띄우기 때문에 저렇게 onberforeunload에 함수를 배정해놓기만 해도 잘 작동한다.

문제는 vue-router를 이용해 움직일때다. 새로고침 없이 history만 바꿔서 구동하는 SPA의 특징덕분에 onbeforeunload가 호출이 안된다.

그럼 vue-router쪽에 해당 기능 있겠지 하고 조금 찾아보니깐 Navigation guard를 발견하게 되고 beforeRouteUpdate를 알게 되었다. 여기서 또 문제가 발생하는데 vue-router 작동구조상 beforeRouteUpdate 를 선언해주면 알아서 호출되야하는데 Nuxt.js에서는 그게 안된다. production mode에서 컴파일된거 확인좀 해봤더니 babel에서 이름을 바꿔버리면서 vue-router상에서 호출을 못하는거 같다.

그래서 대안이 middleware를 사용하는것이다.(링크)

middleware에서 페이지 변환이 일어나기 전에 검사해보고 중간에 차단먹이는것이다.

현재 store에 flag하나 새워두고 각 컴포넌트에서 저장확인 필요하다는 flag를 새우고 middleware에서 flag 회수하는 식으로 구현함.


20190801
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/encodeURI

API서버로 Get 요청을 보낼때 계속 고민되었던점이 유니코드 문자나 띄어쓰기 같은 일반적이지 않은 형태의 URL이 들어가면 Axios가 처리를 못한다는 점이었다. Escaped Sequence로 인코딩하면 된다는데 별도로 라이브러리 깔기가 싫어서 방치하다가 오늘 방법을 찾아냈다.

encodeURI() 함수는 javascript 기본함수로 URL로 쓰기 적합한형태로 알아서 바꿔준다. 이제 get요청에 유니코드문자를 자유롭게 넣을 수 있게 되었다.


이번에는 주로 POST와 관련된 부분을 구현했다. 아직 S3 서버를 못만들어서 tui-editor Customization을 시작도 못했고 이미지 업로드도 미구현인 상태이지만, 기본적인 글 써서 올리고 수정하는 작업은 잘 된다.
--

이걸 구현하면서 가장 골치아팠던점은 SSR, SEO와 관련된 사항이었다. 현재 이 프로젝트는 편집기나 완성된 글을 보여주는 Viewer나 모두 Toast ui editor를 사용하는데, 이 라이브러리가 내부적으로 window를 사용하기때문에 서버쪽에서 렌더링이 불가하다.

다행히도 Nuxt.js에서는 해당 사항을 충분히 염려해서 <no-ssr>의 형태로 부분적으로 SSR를 취소할수 있지만 그래서는 구글의 서치엔진에 탐색되기가 힘들다는 단점이 생긴다.

이를 어떻게 해결하기위해, 일단 마크다운 원본 그 자체를 서버쪽에서 삽입시켜 보낸 후 클라이언트쪽에서 로딩이 완료되면 삽입된 부분을 지우고 렌더링된 요소를 띄우는 형태를 목표로 했다. 이론 자체는 나쁘지 않았지만 문제는 이걸 v-if 를 통해 구현해버리는 바람에 클라이언트쪽에선 렌더링에서 제외되고, 이게 서버쪽이랑 클라이언트쪽이랑 Render Tree가 일치하지 않게 유도되는 바람에 Development 모드에서 전체적으로 꼬여버리게 된다.

지금은 style="display:none;" 으로 타협보는중.


20190804 (새벽 4시)
screencapture-byeoru-editor-6-2019-08-04-04_18_54

업로드와 관련된 부분을 간략하게 완성했다. 간략하게라 해도 핵심적인부분은 다 완성했는데

  1. 업로드 요청시 사용자 인증을 거쳐 업로드 허가
  2. 업로드 된 파일은 Cache 저장소와 S3저장소에 각각 저장됨.
  3. 파일 요청이 있을경우 일차적으로 Cache 저장소를 탐색함.
  4. Cache에 없을경우 S3에서 스트림으로 불러와서 그대로 요청자에게 전달함.
  5. 요청이 있을때마다 요청 시간과 요청횟수등의 정보를 DB에 저장함.

등이다. 아직 미구현된 부분은

  1. DB에 저장된 정보를 보고 Cache에 올릴 후보군 정하기.
  2. Cache 업데이트 하기.

이다.

Server Side
서버쪽에서 인상깊었던 일은 다음과 같다.

  • 파일이름 정하기
    • 파일을 업로드할때 무엇보다 중요한건 중복되는 파일명을 없애는것이다. UUID, Hash, 원래 제목을 도메인 별로 나눠서 별도의 경로에 저장 등등을 생각해봤지만 결국 정한것은 시간이다. Javscript에서 Date.now() 함수는 현재 시간 Timestamp을 ms 단위로 보여주는데 파일을 유저, 도메인, 시간 을 섞어서 이름으로 만들면 겹칠리가 없어서 결국 이 방법을 채택했다.
    • iwanhae_postThumb_1564859202313.ico
    • {userId}_{Domain}_{timestamp}.{ext}
  • 유저 인증
    • JWT 토큰 사용
  • Koa에서 업로드된 파일 받아오기
    • 본래는 Request를 Header만 까보고 Body는 Stream으로 받아올려고 했는데 문제는 관련된 내용을 발견하질 못했다. 정확히는 koa-stream을 발견하긴 했는데 뭔가 지저분해서 관뒀고, Request를 직접 파싱하는건 변수가 Document도 제대로 안되어있고 예상치 못한 변수도 많아서 관뒀다.
    • 그래도 multipart-upload 가 불가능한건 아닌데 koa-body에서 기본적인 기능을 지원한다.
    • 단점은 파일이 일단 TmpDir에 저장이 완료된뒤에 요청 처리가 가능하다는 것이다. 본래 바로 들어오는 Stream을 S3로 Piping해서 부담을 최소화 하고 싶었으나 어차피 이미지 위주의 파일만 처리할 것이고, 업로드 된 파일은 최소 1회는 바로 요청이 들어올 것이므로(미리보기) 일단 Cache에 저장했다가 정기적인 Cache Refresh시간에 Cache에서 없애기로 했다.
    • TmpDir에 있는 파일을 Cache로 옮기는 작업은 fs.rename 을 사용하면 된다.
  • fs.rename을 Promise로 사용하기.
    • Async/Await 애용 유저로써 Node.js 기본함수가 Promise를 지원안하고 Callback을 강요한다는 점에서 충격먹었다.
    • 다행히도 Node.js v8 이후로는 이를 Promise화 하는 방법이 존재하는데 그것은 바로util.promisify(fs.rename)이다.
    • 처음에 이걸 발견했을때 어떤 Callback 함수도 자동으로 Promisify 해주는줄 알고 기뻐했는데, 특정 Interface를 상속받는 함수(객체?) 만 사용 가능한것 같다. 정확한 작동구조는 조사가 필요.
  • aws-sdk함수들의 promise화.
    • S3 저장공간을 활용하기 위해 채택한 클라이언트 라이브러리는 바로 aws-sdk이다.(아무래도 원조다 보니깐) 다만 이쪽도 처음에 충격먹은게 Promise가 아니라는것.....
    • 다행히도 사용하려는 함수 뒤에 .promise()를 붙혀주는 것 만으로도 promise화가 가능했다.
    • 이쪽도 작동구조가 꽤 궁금하다. 근데 탐구해볼정도로 부지런하지 않은게 함정.....
  • Cache에 존재하는 Static 파일 보내기.
    • koa-send라는 라이브러리가 존재한다.
    • koa에서 정적파일 요청처리하는게 기본적으로 koa-send를 wrapping 한 것이다.
    • (오픈소스의 좋은점. 어떻게 구현했는지 빠르게 알아낼 수 있다.)
  • S3에서 다운로드 Stream 그대로 요청자에게 보내주기.
    • 아무래도 S3도 기본적으로 http 통신이다보니 Stream은 호환될꺼라 생각했다.
    • (await ctx.s3.getObject({ Bucket: 'byeoru', Key: name }).promise()).Body 이게 다운로드 Stream이다.
    • 이걸 어떻게 Response로 piping하나.... 고민했었는데 Koa.js 공식 홈페이지에 ctx.body에 Stream을 대입해도 된다고 한다....
    • 그냥 ctx.body = 했더니 브라우저에서 잘 받아낸다.
  • Mime 구하기.
    • 라이브러리의 도움을 구했다.
    • mime-types

Client Side

  • 업로드 하기.
  • 드래그앤 드롭
    • UI
    • 처음부터 직접 구현할 생각은 1도 없었다. 브라우져별로 호환성이 달라서 이것만을 위한 라이브러리가 존재할정도라는것을 처음부터 알고있었기 떄문.
    • 구현된걸 가져온것은 좋으나 문제가 단일 업로드 옵션을 활성화 해도 다중 업로드가 가능했다는 것.
    • Document에서는 이 컴포넌트는 BeforeUpload로 정의된 함수를 실행한 후 상태 변화를 이벤트로 알려주는 구조로 되어있다고 함.
    • BeforeUpload에서 동시에 여러파일 업로드를 차단하는건 간단.
    • 순차적으로 여러개 업로드한것은 fileList Props와 연계됨. 단 이건 Props 일뿐 v-model이 아닌지라 이 리스트는 부모 컴포넌트에서 직접 조작해 줘야함.
    • https://github.com/ant-design/ant-design/issues/2423 (중국어 실화....?)
    • 이벤트로 날라오는 file 오브젝트를 fileList의 유일한 원소로 만들어서 단일 업로드를 구현함.
  • 부모 컴포넌트에 결과값 넘기기.
    • this.$emit

20190804
이제 Byeoru의 검색시스템을 만들 시기이다. 아직 만들진 시작도 못했는데 Backend 구성에서 고민을 좀 하고있다.

일단 가장큰 문제는 Elasticsearch로 어떻게 데이터를 Feed 할 것인가? 이다. 가장 간단한 해결책은 Post Service에서 MongoDB에 추가할때 Elasticsearch에도 같이 추가하는것이다. 단점은 전부 이런식으로 구현할경우 ElasticSearch는 많은 서비스에 의존성을 가진놈이 될테고, Elasticsearch가 과부화든 서버오류든 작동이 안되면 서비스 전채가 죽어버릴 것이다.

2안은 MongoDB랑 Elasticsearch랑 동기화를 시키는 것이다. 가장 유명한게 Connector를 쓰는건데 모든 서비스는 Docker로 Deploy할 예정이라 매우매우 귀찮을걸 예상한다. 그래서 좀 찾아보니깐 MongoDB 에서 Pub/Sub 하는 별도의 서비스를 만들던가 Transporter를 쓰면 된다는데 양쪽다 확장성이 부족하다고 생각한다.

3안은 MessageQueue를 사용하는것이다. 각각의 서비스는 Pub, Elasticsearch는 Sub, 하는식으로 사용할수 있고, 추후 도입할 예정인 추천컨텐츠 시스템을 이식하기에도 확장성 있어보여서 적용하려고 지금 결심했다.


20190805
MQ 서비스 몇개 알아보니 가장 유명한건 역시 Kafka랑 RabbitMQ.

둘다 장단점이 있는데 일단 성능은 Kafka가 훨씬 더 좋다. 게다가 이벤트형식으로 구독자가 강제구독하는게 아니라 구독자쪽에서 메세지 달라고 요청하면 주는식이라서 더 좋지만 RabbitMQ를 쓰기로했다.

뭐든 문제는 진입장벽이라고, Kafka가 성능은 좋지만 그렇게 고성능 필요하지도 않고 문서화가 RabbitMQ가 훨씬 잘되있다.


20190806
RabbitMQ 테스트는 성공적이고 Elasticsearch쪽 관리해줄 서비스를 dotnet으로 만들려고 하다가 토나오는줄 알았다.

이유는 단순한데, 간단한걸 복잡하게 꼬아놨다.

Elasticsearch는 기본적으로 REST 기반 API로 작동을 한다. 모든 작동은 http 통신 한번으로 대부분 해결이 될정도로 쓰기가 편한데..... C#에서 쓰려고 하니깐 사소한것까지 함수를 만들어 놓긴 했는데 명칭이 전혀 다르고 이게 완성되서 보내지는 통신문이 결국 어떻게되는질 알 수가 없다. 한마디로 같은걸 사용하는데 공부를 두번해야한다. 차라리 http 통신 라이브러리를 가져와서 모든 요청을 객체로 만들어 놓은다음 Json 형태로 보내는, 즉 라이브러리를 처음부터 만들어 쓰는편이 훨씬 빠른 지경이다.

짜증나서 Javascript로 복귀한다. Elasticsearch 1.0시절의 패턴이 그대로 내려오는거 같은데 솔직히 바뀔껀 좀 바뀌었으면 한다.