-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
310 lines (156 loc) · 83 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>블로구</title>
<link href="https://hhaze.github.io/atom.xml" rel="self"/>
<link href="https://hhaze.github.io/"/>
<updated>2021-11-21T14:35:18.986Z</updated>
<id>https://hhaze.github.io/</id>
<author>
<name>jhgu</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>Redis TTL</title>
<link href="https://hhaze.github.io/posts/2019/redis-ttl/"/>
<id>https://hhaze.github.io/posts/2019/redis-ttl/</id>
<published>2019-12-24T14:23:21.000Z</published>
<updated>2021-11-21T14:35:18.986Z</updated>
<content type="html"><![CDATA[<h3 id="TTL-Time-To-Live"><a href="#TTL-Time-To-Live" class="headerlink" title="TTL (Time To Live)"></a>TTL (Time To Live)</h3><p>데이터의 유효 기간을 나타내기 위한 방법이다. 데이터에 만료 시간을 주어 지정한 시간 이후 데이터를 제거하게 된다.</p><h3 id="SETEX"><a href="#SETEX" class="headerlink" title="SETEX"></a>SETEX</h3><p>레디스에서는 <code>SETEX</code> 명령어를 통해 키에 만료 시간을 부여할 수 있다.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ setex [key] [seconds] [value]</span><br></pre></td></tr></table></figure><p>나는 특정 키에 만료 시간을 주고, 고 루틴을 통해 만료 이벤트를 받아 특정 로직을 수행하는 방식으로 이를 활용하고 있다.</p><h3 id="redis-cli-pubsub"><a href="#redis-cli-pubsub" class="headerlink" title="redis-cli pubsub"></a>redis-cli pubsub</h3><p>redis-cli 통해 <code>expired_event</code> 수신을 확인해 볼 수 있다. 터미널을 두 개 띄우고 아래처럼 해보면 된다.</p><ul><li><p>터미널 1</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ subscribe channel: __keyevent@0__:expired</span><br></pre></td></tr></table></figure></li><li><p>터미널 2</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ setex [key] [seconds] [value]</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<summary type="html"><h3 id="TTL-Time-To-Live"><a href="#TTL-Time-To-Live" class="headerlink" title="TTL (Time To Live)"></a>TTL (Time To Live)</h3><p>데이터의 유효 기간</summary>
<category term="Redis" scheme="https://hhaze.github.io/tags/Redis/"/>
<category term="TTL" scheme="https://hhaze.github.io/tags/TTL/"/>
</entry>
<entry>
<title>JWT Parser</title>
<link href="https://hhaze.github.io/posts/2019/jwt-parser/"/>
<id>https://hhaze.github.io/posts/2019/jwt-parser/</id>
<published>2019-07-01T14:00:27.000Z</published>
<updated>2021-11-21T13:35:58.904Z</updated>
<content type="html"><![CDATA[<p>Go 언어로 개발하면서 JWT 파서로 <a href="https://github.com/dgrijalva/jwt-go">jwt-go</a> 패키지를 사용하고 있다. 패키지 사용 중 겪은 경험을 기록해두려 한다.</p><ul><li>문제: JWT Payload 내 19자리의 숫자 입력 값을 추출 후 출력하면 값이 달라져 있는 상황</li><li>원인: 파서에서 숫자 값을 모두 <code>float64</code> 타입으로 취급<ul><li>관련 링크: <a href="https://github.com/dgrijalva/jwt-go/issues/224">https://github.com/dgrijalva/jwt-go/issues/224</a></li><li><code>float64</code> 데이터 타입은 <code>15자리 정밀도 보장</code> 이라 19자리의 정밀도는 보장되지 않는 것</li></ul></li><li>해결: 위의 GitHub Issue 코멘트를 참고하여 JSONNumber 플래그와 Custom Struct Type 사용</li></ul><p>수신한 JWT를 <a href="https://jwt.io/">https://jwt.io</a> 사이트에서 Decode 해서 Payload 값을 확인하며 문제를 검토했었는데, 사이트에서도 값이 바뀌어 보이고 있었다. 그래서 올바른 방법으로 해결을 해놓고서도 Decode 된 값과 코드에서 추출한 값이 달라 삽질을 좀 했다. 제대로 된 값은 <a href="https://www.base64decode.org/">여기</a>에서 확인을 할 수 있었고, 위의 해결 방법으로 올바르게 파싱되었다.</p>]]></content>
<summary type="html"><p>Go 언어로 개발하면서 JWT 파서로 <a href="https://github.com/dgrijalva/jwt-go">jwt-go</a> 패키지를 사용하고 있다. 패키지 사용 중 겪은 경험을 기록해두려 한다.</p>
<ul>
<li>문제: JW</summary>
<category term="Go" scheme="https://hhaze.github.io/tags/Go/"/>
<category term="JWT" scheme="https://hhaze.github.io/tags/JWT/"/>
<category term="Token" scheme="https://hhaze.github.io/tags/Token/"/>
<category term="jwt-go" scheme="https://hhaze.github.io/tags/jwt-go/"/>
</entry>
<entry>
<title>GraphQL</title>
<link href="https://hhaze.github.io/posts/2019/graphql/"/>
<id>https://hhaze.github.io/posts/2019/graphql/</id>
<published>2019-04-14T13:39:42.000Z</published>
<updated>2021-04-04T02:37:53.894Z</updated>
<content type="html"><![CDATA[<h2 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h2><ul><li>API를 위해 Facebook에서 만든 <strong>쿼리 언어 (Query Language)</strong> <ul><li>Facebook이 2012년에 개발하여 2015년에 공개적으로 발표</li><li>“write one, run anywhere”</li></ul></li></ul><p>배경</p><ul><li>모바일 사용 증가로 효율적인 데이터 로드에 대한 필요성</li><li>다양한 프론트 엔드 프레임워크 및 플랫폼 대응</li><li>빠른 개발</li></ul><p>특징</p><ul><li><p>Specification</p><ul><li>API 디자인에 대한 스펙/방법론 (ex. REST)</li><li>클라이언트가 서버에서 데이터를 로드하는 방법을 정의</li><li>스펙이 스키마의 유효성 판별</li><li>스카마가 클라이언트 호출의 유효성 판별</li></ul></li><li><p>Application Layer</p><ul><li>정의된 스키마 기반으로 데이터 탐색 및 반환</li><li>데이터 저장 방식과 무관</li></ul></li><li><p>Graph: 스키마에 정의된 구조</p><ul><li>그래프는 노드(Node)와 에지(Edge)로 구성</li><li>GraphQL은 객체와 그 관계로 구성</li></ul></li></ul><p>REST와의 가장 큰 차이점</p><ul><li>flexibillity and efficiency</li><li>단 하나의 Endpoint</li><li>요청 시 사용한 쿼리에 따라 각기 다른 응답</li></ul><p>예제 상황</p><ul><li><p>블로그 앱에서 특정 사용자의 글 제목과 그 사용자의 최근 3명 follower 이름을 보여주려고 할 때</p><ul><li><p>REST 경우</p><p><img src="https://imgur.com/VRyV7Jh.png" alt="REST"></p></li><li><p>GraphQL 경우</p><p><img src="https://imgur.com/z9VKnHs.png" alt="GraphQL"></p></li></ul></li></ul><p>이로 인한 장점</p><ul><li>HTTP 요청 횟수 감소</li><li>HTTP 응답 사이즈 감소</li><li>서버 측 추가 작업 없이 클라이언트 수정 가능</li></ul><p>대표 사용처</p><ul><li>Facebook</li><li>Github<ul><li><a href="https://developer.github.com/v4/">Github API v4</a></li></ul></li></ul><h2 id="Learn"><a href="#Learn" class="headerlink" title="Learn"></a>Learn</h2><p>동작 방식</p><ul><li><p>요청 받은 쿼리에 대해 정의된 타입과 필드를 검사한 다음, 함수를 실행하여 결과를 생성하여 응답</p></li><li><p>타입과 필드를 정의하고, 각 타입의 필드에 대한 함수로 구현</p></li></ul><p>타입과 필드</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">type Query {</span><br><span class="line"> me: User</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">type User {</span><br><span class="line"> id: ID</span><br><span class="line"> name: String</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>쿼리</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> me {</span><br><span class="line"> name</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>응답 (JSON)</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"me"</span>: {</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Luke Skywalker"</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="Schema-a-collection-of-GraphQL-types"><a href="#Schema-a-collection-of-GraphQL-types" class="headerlink" title="Schema - a collection of GraphQL types"></a>Schema - a collection of GraphQL types</h4><ul><li><p>SDL (Schema Definition Language)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">type Query {</span><br><span class="line"> allPersons(last: Int): [Person!]!</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">type Mutation {</span><br><span class="line"> createPerson(name: String!, age: Int!): Person!</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">type Subscription {</span><br><span class="line"> newPerson: Person!</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">type Person {</span><br><span class="line"> name: String!</span><br><span class="line"> age: Int!</span><br><span class="line"> posts: [Post!]!</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">type Post {</span><br><span class="line"> title: String!</span><br><span class="line"> author: Person!</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h4 id="Type"><a href="#Type" class="headerlink" title="Type"></a>Type</h4><ul><li><p>Query - fetch</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">type Query {</span><br><span class="line"> allPersons(last: Int): [Person!]!</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>Mutation - create / update / delete</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">type Mutation {</span><br><span class="line"> createPerson(name: String!, age: Int!): Person!</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>Subscription - realtime connection</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">type Subscription {</span><br><span class="line"> newPerson: Person!</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>스칼라</p><ul><li>하위 필드가 없는 쿼리의 끝 부분</li><li>Int: 부호가 있는 32비트 정수</li><li>Float: 부호가 있는 부동소수점 값</li><li>String: UTF=8 문자열</li><li>Boolean: true 또는 false</li><li>ID: 고유 식별자를 나타내며 사람이 읽을 수 있도록 하는 의도가 아니라는 것을 의미</li></ul></li><li><p>열거형 (Enums)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">enum Weekday {</span><br><span class="line"> MONDAY</span><br><span class="line"> TUESDAY</span><br><span class="line"> WEDNESDAY</span><br><span class="line"> THURSDAY</span><br><span class="line"> FRIDAY</span><br><span class="line"> SATURDAY</span><br><span class="line"> SUNDAY</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>리스트와 Non-Null</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">myField: [String!]</span><br><span class="line"> </span><br><span class="line">myField: null // valid</span><br><span class="line">myField: [] // valid</span><br><span class="line">myField: ['a', 'b'] // valid</span><br><span class="line">myField: ['a', null, 'b'] // error</span><br></pre></td></tr></table></figure><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">myField: [String]!</span><br><span class="line"></span><br><span class="line">myField: null // error</span><br><span class="line">myField: [] // valid</span><br><span class="line">myField: ['a', 'b'] // valid</span><br><span class="line">myField: ['a', null, 'b'] // valid</span><br></pre></td></tr></table></figure></li><li><p>인터페이스</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">interface Node {</span><br><span class="line"> id: ID!</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><p><code>Node</code> 를 <em>구현한(implements)</em> 모든 타입은 이러한 인자와 리턴 타입을 가져야 한다는 것을 의미</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">type User implements Node {</span><br><span class="line"> id: ID!</span><br><span class="line"> name: String!</span><br><span class="line"> age: Int!</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul></li><li><p>유니온</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">union Person = Adult | Child</span><br></pre></td></tr></table></figure></li><li><p>입력</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">input ReviewInput {</span><br><span class="line"> stars: Int!</span><br><span class="line"> commentary: String</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {</span><br><span class="line"> createReview(episode: $ep, review: $review) {</span><br><span class="line"> stars</span><br><span class="line"> commentary</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"ep"</span>: <span class="string">"JEDI"</span>,</span><br><span class="line"> <span class="attr">"review"</span>: {</span><br><span class="line"> <span class="attr">"stars"</span>: <span class="number">5</span>,</span><br><span class="line"> <span class="attr">"commentary"</span>: <span class="string">"This is a great movie!"</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"data"</span>: {</span><br><span class="line"> <span class="attr">"createReview"</span>: {</span><br><span class="line"> <span class="attr">"stars"</span>: <span class="number">5</span>,</span><br><span class="line"> <span class="attr">"commentary"</span>: <span class="string">"This is a great movie!"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h4 id="Query-amp-Mutation"><a href="#Query-amp-Mutation" class="headerlink" title="Query & Mutation"></a>Query & Mutation</h4><p>쿼리 필드는 병렬로 실행되지만 뮤테이션 필드는 하나씩 차례대로 실행</p><ul><li><p>기본</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> allPersons {</span><br><span class="line"> name</span><br><span class="line"> age</span><br><span class="line"> posts {</span><br><span class="line"> title</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>인자</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> allPersons(last: 2) {</span><br><span class="line"> name</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>별칭 (alias) - 필드의 결과를 원하는 이름으로</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> first: User(id: "1") {</span><br><span class="line"> name</span><br><span class="line"> }</span><br><span class="line"> second: User(id: "2") {</span><br><span class="line"> name</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"first"</span>: {</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Alice"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">"second"</span>: {</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Sarah"</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>별칭이 없으면 두 개 결과 모두 “User”라는 필드명으로 반환되므로</li></ul></li><li><p>프래그먼트 - a collection of fields on a specific type</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> allUsers {</span><br><span class="line"> name</span><br><span class="line"> age</span><br><span class="line"> email</span><br><span class="line"> street</span><br><span class="line"> zipcode</span><br><span class="line"> city</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">fragment addressDetails on User {</span><br><span class="line"> name</span><br><span class="line"> street</span><br><span class="line"> zipcode</span><br><span class="line"> city</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> allUsers {</span><br><span class="line"> age</span><br><span class="line"> email</span><br><span class="line"> ... addressDetails</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><p>유니온과 활용하는 예제</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">type Adult {</span><br><span class="line"> name: String!</span><br><span class="line"> work: String!</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line">type Child {</span><br><span class="line"> name: String!</span><br><span class="line"> school: String!</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">union Person = Adult | Child</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> allPersons {</span><br><span class="line"> name # works for `Adult` and `Child`</span><br><span class="line"> ... on Child {</span><br><span class="line"> school</span><br><span class="line"> }</span><br><span class="line"> ... on Adult {</span><br><span class="line"> work</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul></li></ul><ul><li><p>작업 이름</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">query HeroNameAndFriends {</span><br><span class="line"> hero {</span><br><span class="line"> name</span><br><span class="line"> friends {</span><br><span class="line"> name</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>변수</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">type Query {</span><br><span class="line"> allUsers(olderThan: Int = -1): [User!]!</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> allUsers(olderThan: 30) {</span><br><span class="line"> name</span><br><span class="line"> age</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>지시어</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">query Hero($episode: Episode, $withFriends: Boolean!) {</span><br><span class="line"> hero(episode: $episode) {</span><br><span class="line"> name</span><br><span class="line"> friends @include(if: $withFriends) {</span><br><span class="line"> name</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li>@include: 인자가 true인 경우에만 이 필드를 결과에 포함</li><li>@skip: 인자가 true인 경우 이 필드를 무시</li></ul><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"episode"</span>: <span class="string">"JEDI"</span>,</span><br><span class="line"> <span class="attr">"withFriends"</span>: <span class="literal">false</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"data"</span>: {</span><br><span class="line"> <span class="attr">"hero"</span>: {</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"R2-D2"</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>뮤테이션 (Mutation)</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">mutation {</span><br><span class="line"> createPerson(name: "Bob", age: 36) {</span><br><span class="line"> name</span><br><span class="line"> age</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"data"</span>: {</span><br><span class="line"> <span class="attr">"createPerson"</span>: {</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Bob"</span>,</span><br><span class="line"> <span class="attr">"age"</span>: <span class="number">36</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ul><h4 id="Resolver"><a href="#Resolver" class="headerlink" title="Resolver"></a>Resolver</h4><ul><li>쿼리 내 각 필드는 정확히 하나의 함수에 대응</li><li><a href="https://github.com/graphql-go/graphql/blob/master/examples/crud/main.go">Go 언어 예제</a></li></ul><h2 id="Code-amp-Playground"><a href="#Code-amp-Playground" class="headerlink" title="Code & Playground"></a>Code & Playground</h2><ul><li><p>예제:</p><p><a href="https://api.graph.cool/simple/v1/cju2eos093a0w01869i1pnnyj/">https://api.graph.cool/simple/v1/cju2eos093a0w01869i1pnnyj/</a></p></li></ul><h2 id="참고-링크"><a href="#참고-링크" class="headerlink" title="참고 링크"></a>참고 링크</h2><ul><li><a href="https://graphql-kr.github.io/">https://graphql-kr.github.io/</a></li><li><a href="https://www.howtographql.com/">https://www.howtographql.com/</a></li><li><a href="https://github.com/graphql-go/graphql">https://github.com/graphql-go/graphql</a></li><li><a href="https://graphql.github.io/swapi-graphql/">https://graphql.github.io/swapi-graphql/</a></li></ul>]]></content>
<summary type="html"><h2 id="Introduction"><a href="#Introduction" class="headerlink" title="Introduction"></a>Introduction</h2><ul>
<li>API를 위해 Facebook에서 만든 <s</summary>
<category term="GraphQL" scheme="https://hhaze.github.io/tags/GraphQL/"/>
</entry>
<entry>
<title>Serverless 시작하기 (Go)</title>
<link href="https://hhaze.github.io/posts/2019/serverless-getting-started/"/>
<id>https://hhaze.github.io/posts/2019/serverless-getting-started/</id>
<published>2019-01-23T13:27:07.000Z</published>
<updated>2021-11-21T14:30:55.357Z</updated>
<content type="html"><![CDATA[<p>😅 혼자 해 본 아주 얕은 수준의 <code>따라하기</code> </p><h2 id="사전-준비"><a href="#사전-준비" class="headerlink" title="사전 준비"></a>사전 준비</h2><ul><li>Node.js (v4 이상)</li><li>Go</li></ul><h2 id="Serverless-설치"><a href="#Serverless-설치" class="headerlink" title="Serverless 설치"></a>Serverless 설치</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ npm install -g serverless</span><br></pre></td></tr></table></figure><p>성공적으로 설치되면, 터미널에 <code>serverless</code> 라고 입력했을 때 <code>Commands</code> 부터 시작하는 설명이 출력된다. <code>sls</code> 라고 축약어로 입력해도 동일하게 동작한다.</p><h2 id="Hello-World-Go"><a href="#Hello-World-Go" class="headerlink" title="Hello World Go"></a>Hello World Go</h2><p>아래 내용을 따라하기만 하면 끝 🤓</p><ol><li><p>Create</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sls create --template aws-go --path myService</span><br></pre></td></tr></table></figure><p><img src="image1.png"></p><p>이렇게 짠 하고 서비스가 생성된다.</p></li><li><p>Build</p><p>만들어진 서비스에는 아래와 같은 내용의 <code>Makefile</code> 이 있고 빌드가 필요하다.</p><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><span class="meta-keyword">.PHONY</span>: build clean deploy</span></span><br><span class="line"></span><br><span class="line"><span class="section">build:</span></span><br><span class="line">env GOOS=linux go build -ldflags=<span class="string">"-s -w"</span> -o bin/hello hello/main.go</span><br><span class="line">env GOOS=linux go build -ldflags=<span class="string">"-s -w"</span> -o bin/world world/main.go</span><br><span class="line"></span><br><span class="line"><span class="section">clean:</span></span><br><span class="line">rm -rf ./bin</span><br><span class="line"></span><br><span class="line"><span class="section">deploy: clean build</span></span><br><span class="line">sls deploy --verbose</span><br></pre></td></tr></table></figure><p>빌드가 되면 <code>bin</code> 폴더가 생기고 폴더 아래에서 결과물을 확인할 수 있다. <code>GOOS</code> 는 타겟 운영 체제를 의미하므로, 빌드 환경이 <code>linux</code> 가 아니라면 빌드 결과물인 실행 파일이 실행되지 않음을 유의한다.</p></li><li><p>Deploy</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sls deploy</span><br></pre></td></tr></table></figure><p><code>endpoint</code> 를 통해 배포된 함수의 URL 정보를 확인할 수 있다. 브라우저를 통해 해당 URL을 입력하면 동작하여 메시지를 출력하는 것을 볼 수 있다.</p></li><li><p>Invoke</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ sls invoke -f hello</span><br><span class="line">$ sls invoke -f world</span><br></pre></td></tr></table></figure><p>-f 옵션은 함수를 의미하며 <code>invoke</code> 명령을 통해 함수를 실행하게 된다.</p><p>실행하면 아래와 같은 결과가 출력되는데 이는 hello/main.go에서 정의된 값이다.</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> "statusCode": 200,</span><br><span class="line"> "headers": {</span><br><span class="line"> "Content-Type": "application/json",</span><br><span class="line"> "X-MyCompany-Func-Reply": "hello-handler"</span><br><span class="line"> },</span><br><span class="line"> "multiValueHeaders": null,</span><br><span class="line"> "body": "{\"message\":\"Go Serverless v1.0! Your function executed successfully!\"}"</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>Remove</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sls remove</span><br></pre></td></tr></table></figure><p>배포한 서비스를 제거한다. 제거하고 나면 함수의 URL에 접속 시 유효하지 않은 결과가 출력된다.</p></li></ol><hr><h4 id="참고"><a href="#참고" class="headerlink" title="참고"></a>참고</h4><p><a href="https://serverless.com/framework/docs/providers/aws/guide/installation/">https://serverless.com/framework/docs/providers/aws/guide/installation/</a></p><p><a href="https://serverless.com/framework/docs/providers/aws/examples/hello-world/go/">https://serverless.com/framework/docs/providers/aws/examples/hello-world/go/</a></p><p><a href="https://github.com/aws/aws-sdk-go">https://github.com/aws/aws-sdk-go</a></p>]]></content>
<summary type="html"><p>😅 혼자 해 본 아주 얕은 수준의 <code>따라하기</code> </p>
<h2 id="사전-준비"><a href="#사전-준비" class="headerlink" title="사전 준비"></a>사전 준비</h2><ul>
<li>Node.j</summary>
<category term="Go" scheme="https://hhaze.github.io/tags/Go/"/>
<category term="Serverless" scheme="https://hhaze.github.io/tags/Serverless/"/>
</entry>
<entry>
<title>VSCode 확장 프로그램</title>
<link href="https://hhaze.github.io/posts/2019/vscode-extensions/"/>
<id>https://hhaze.github.io/posts/2019/vscode-extensions/</id>
<published>2019-01-13T07:13:43.000Z</published>
<updated>2021-04-04T02:37:53.897Z</updated>
<content type="html"><![CDATA[<p>내가 사용하는 Visual Studio Code 확장 프로그램을 정리 및 소개한다. 🧐</p><p>주 개발 언어가 <code>Go</code> 라서 다른 프로그래밍 언어에서 많이 사용하는 확장 프로그램들은 설치가 안 되어 있다. 본인 개발 환경에 맞추어 설치가 필요한데, 확장 탭에서 <code>@sort:installs</code> 정렬하여 참고해보면 좋다.</p><p>설치 및 사용하고 있는 확장 프로그램은 아래와 같다.</p><p><img src="image1.png"></p><h4 id="Bookmarks-🔖"><a href="#Bookmarks-🔖" class="headerlink" title="Bookmarks 🔖"></a>Bookmarks 🔖</h4><p>Toggle 방식으로 코드의 특정 지점을 북마크한다. 단축키로 북마크 설정과 이동이 가능하다. 좌측 메뉴 바에 북마크 탭을 통해 북마크를 모두 모아서 볼 수도 있다.</p><p><img src="image2.png"></p><p>에디터 우측에 Preview? (이렇게 칭하는지 잘 모르겠… ) 를 제공하는데, 그 뷰에서도 북마크가 보여서 편리하다. </p><h4 id="Bracket-Pair-Colorizer"><a href="#Bracket-Pair-Colorizer" class="headerlink" title="Bracket Pair Colorizer"></a>Bracket Pair Colorizer</h4><p>프로그램 명 그대로 괄호를 짝 맞추어 각기 다른 색으로 표시해준다. 따로 설정 없이 기본으로 사용하고 있다. 괄호 식별이 잘 돼서 유용하게 쓰고 있다.</p><h4 id="Code-Runner"><a href="#Code-Runner" class="headerlink" title="Code Runner"></a>Code Runner</h4><p>코드를 바로 실행할 수 있도록 해준다. C를 예로 들면, gcc를 통해 빌드하고 실행 파일을 실행하는 과정을 단축키로 할 수 있는 것이다.</p><p>이 확장 프로그램을 설치하면 기본 <code>code-runner.executorMap</code> 을 제공하는데 그대로 사용하거나 재정의해서 사용하면 된다.</p><p><img src="image3.png"></p><h4 id="GitLens-👀"><a href="#GitLens-👀" class="headerlink" title="GitLens 👀"></a>GitLens 👀</h4><p>코드에 커서를 갖다 대면 Commit 정보를 출력해준다. 누가 언제 작성/수정했는지 Commit Log를 함께 보여주고, 추가 액션도 할 수 있다.</p><h4 id="Power-Mode-💥"><a href="#Power-Mode-💥" class="headerlink" title="Power Mode 💥"></a>Power Mode 💥</h4><p>기능 편의를 위한 것이 아니라 시각적 효과를 주는 프로그램이다. 한 자 한 자 타이핑 할 때 마다 폭죽 같은 애니메이션이 발생한다. 재밌어보여서 설치해서 쓰다가 타이핑이 조-금 밀리는 것 같아서 지금은 ‘사용 안 함’ 상태이다. 가끔 코딩하면서 기분 전환하고 싶을 때 <code>재미로</code> 쓸 만 하다.</p><h4 id="Settings-Sync-🔄"><a href="#Settings-Sync-🔄" class="headerlink" title="Settings Sync 🔄"></a>Settings Sync 🔄</h4><p>VSCode를 여러 컴퓨터에서 사용한다면 추천하는 프로그램이다. 나도 추천받아서 사용하게 됐는데 좋다. 설정 및 확장 프로그램을 동기화해준다.</p><p>내 경우 이 프로그램 덕에 개인 컴퓨터랑 회사 컴퓨터 간 설정을 쉽게 동기화해서 사용하고 있다. </p><p>사용법은 프로그램 세부 정보에 잘 나와있으니 참고한다. Github에 토큰을 만들고 <code>Gist ID</code> 를 통해 Upload/Download 하는 방식이다.</p><p>Upload/Download를 자동으로 하게 하려면 <code>Advanced Options</code> 에서 ON하면 된다.</p><ul><li>Sync : Advanced Options > Toggle Auto-Download On Startup</li><li>Sync : Advanced Options > Toggle Auto-Upload on Settings Change</li></ul><h4 id="Text-Marker-Highlighter"><a href="#Text-Marker-Highlighter" class="headerlink" title="Text Marker (Highlighter)"></a>Text Marker (Highlighter)</h4><p>Toggle 방식으로 특정 문자열을 하이라이팅할 수 있다. 단축키…는 기본으로 없는 것 같고 마우스 우클릭 방식으로 사용하고 있다. 개인적으로는 정-말 많이 사용하고 있다. 프리뷰에서도 하이라이트한 색을 표시해준다.</p><h4 id="TODO-Highlight"><a href="#TODO-Highlight" class="headerlink" title="TODO Highlight"></a>TODO Highlight</h4><p>딱 <code>TODO</code> 라는 키워드에 대해 하이라이팅을 해준다. 코드를 한 번에 내리 작성하지 못 하고 막힐 때, Commit 전까지는 혼자 보기 위해 주석으로 정리해두는데 그 때 사용한다. 하이라이팅 돼있어서 스크롤 슥슥 내리다가도 눈에 딱 띄어서 놓치지 않게 도와준다.</p><p>기본으로 <code>TODO</code> 랑 <code>FIXME</code> 를 제공하고 (나는 <code>TODO</code> 만 주로 사용) 다른 키워드로 커스텀도 가능한 것 같다.</p><h4 id="vscode-icons"><a href="#vscode-icons" class="headerlink" title="vscode-icons"></a>vscode-icons</h4><p>좌측 메뉴바에서 파일 탐색기를 볼 수 있는데 그 파일들에 아이콘을 적용할 수 있다. 예쁘다. 🤩</p><hr><p>아래와 같은, 특정 프로그래밍 언어의 확장 프로그램이나 언어 팩은 소개하지 않았는데 본인이 사용하는 개발 언어의 확장 프로그램은 기본으로 설치해서 사용하면 된다.</p><ul><li>C/C++</li><li>Go</li><li>Python</li><li>Korean Language Pack for Visual Studio Code</li><li>Vim</li></ul>]]></content>
<summary type="html"><p>내가 사용하는 Visual Studio Code 확장 프로그램을 정리 및 소개한다. 🧐</p>
<p>주 개발 언어가 <code>Go</code> 라서 다른 프로그래밍 언어에서 많이 사용하는 확장 프로그램들은 설치가 안 되어 있다. 본인 개발 환</summary>
<category term="Visual Studio Code" scheme="https://hhaze.github.io/tags/Visual-Studio-Code/"/>
<category term="VSCode" scheme="https://hhaze.github.io/tags/VSCode/"/>
</entry>
<entry>
<title>go debug</title>
<link href="https://hhaze.github.io/posts/2018/go-debug/"/>
<id>https://hhaze.github.io/posts/2018/go-debug/</id>
<published>2018-12-25T13:14:03.000Z</published>
<updated>2021-04-04T02:37:53.890Z</updated>
<content type="html"><![CDATA[<p>Visual Studio Code에서의 Go Debug 방법이다. 다른 IDE 및 다른 디버깅 툴은 아직 사용해보지 않았다.</p><h2 id="사전-준비"><a href="#사전-준비" class="headerlink" title="사전 준비"></a>사전 준비</h2><ul><li><p>Microsoft Visual Studio</p></li><li><p><code>Go</code> Extension</p><p><img src="image1.png"></p></li></ul><h2 id="Start-Debugging-😈"><a href="#Start-Debugging-😈" class="headerlink" title="Start Debugging 😈"></a>Start Debugging 😈</h2><p>두 가지 중 하나의 방법으로 디버깅을 시작할 수 있다.</p><ul><li><p>상단 메뉴 바에서 [Debug] - [Start Debugging]</p></li><li><p>[F5] 단축키</p></li></ul><p>처음 실행하면 아래와 같은 알림이 발생하는데 우측 [Open launch.json]을 선택한다.</p><p><img src="image2.png"></p><p>그러면 아래처럼 기본 값으로 <code>launch.json</code> 파일이 생성된다.</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="comment">// Use IntelliSense to learn about possible attributes.</span></span><br><span class="line"> <span class="comment">// Hover to view descriptions of existing attributes.</span></span><br><span class="line"> <span class="comment">// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387</span></span><br><span class="line"> <span class="attr">"version"</span>: <span class="string">"0.2.0"</span>,</span><br><span class="line"> <span class="attr">"configurations"</span>: [</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">"name"</span>: <span class="string">"Launch"</span>,</span><br><span class="line"> <span class="attr">"type"</span>: <span class="string">"go"</span>,</span><br><span class="line"> <span class="attr">"request"</span>: <span class="string">"launch"</span>,</span><br><span class="line"> <span class="attr">"mode"</span>: <span class="string">"auto"</span>,</span><br><span class="line"> <span class="attr">"program"</span>: <span class="string">"${fileDirname}"</span>,</span><br><span class="line"> <span class="attr">"env"</span>: {},</span><br><span class="line"> <span class="attr">"args"</span>: []</span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>값을 본인 설정에 맞게 바꾸어서 사용하면 된다. 옵션에 대한 설명은 <a href="https://github.com/Microsoft/vscode-go/wiki/Debugging-Go-code-using-VS-Code">링크</a>를 참고한다.</p><p>내 경우 <code>program</code> 과 <code>args</code> 를 수정해서 사용하고 있다.</p><p>줄 번호 좌측으로 마우스를 가져다 대면 빨간 점을 찍을 수 있는데 이 점이 <code>Break Point</code> 가 되고, 정상적으로 디버깅이 시작되면 해당 위치에 멈춘다. 좌측 디버그 뷰에서 변수 값에 대한 조회가 가능하고 상단에 뜨는 메뉴 바에서 컨트롤이 가능하다.</p><p><img src="image3.png"></p><h2 id="💁♀️-Tip"><a href="#💁♀️-Tip" class="headerlink" title="💁♀️ Tip"></a>💁♀️ Tip</h2><p>macOS에서 위 과정이 순조롭지 않을 수 있다. 발생 가능한 문제가 있고 (나도 직면했고) 그에 대한 해결 방법도 더불어 정리한다.</p><blockquote><p>정확도를 높이고자 이 과정을 다시 하면서 문제와 해결 방법을 적으려고 했는데, 개인 맥북에서는 문제가 발생하지 않는다. 회사 맥북에서는 문제가 있었고 해결했는데… 기억에 의존하여 적어두어야겠다.</p></blockquote><ul><li>디버깅을 시작했을 때 인증서 관련 에러가 나면서 진행되지 않는다면<ul><li><a href="https://www.youtube.com/watch?v=4K2bDLzYiAQ">동영상</a>을 참고해서 Self-Signed Certificate 발급 진행 필요</li></ul></li><li><code>delve</code> 설치가 제대로 되지 않았다면 아래 방법 중 하나를 해보는데<ul><li>VSCode 명령 팔레트 (⌘ + ⇧ + P) 에서 <code>Go: Install/Update Tools</code> -> <code>dlv</code> 선택해서 설치/업데이트</li><li><code>delve</code> 를 직접 다운로드 받아 빌드 - <a href="https://github.com/derekparker/delve/blob/master/Documentation/installation/osx/install.md">링크</a> 참고</li></ul></li></ul><p>문제가 발생했다는 회사 맥북에서 나는 인증서 만들기랑 직접 다운로드 + 빌드로 해결했다. 경험 후 추천하는 방법은 <strong><code>delve</code> 직접 다운로드</strong>인데, 다운로드 후 빌드 과정에서 인증서 만드는 스크립트가 실행되어 자동으로 인증서를 만들어주기 때문이다.</p><p>다른 것들은 따라하면 되니까 쉬운 일이고 이 문제와 해결 방법을 자세히 기술하고 싶었던 건데… 설명이 부족한 것 같아 아쉽다. 하지만 (내 경우만 봐도) 문제 발생 확률이 100%가 아니니까 문제 없이 설치되는 것이 베스트겠다.</p>]]></content>
<summary type="html"><p>Visual Studio Code에서의 Go Debug 방법이다. 다른 IDE 및 다른 디버깅 툴은 아직 사용해보지 않았다.</p>
<h2 id="사전-준비"><a href="#사전-준비" class="headerlink" title="사전 준비</summary>
<category term="Go" scheme="https://hhaze.github.io/tags/Go/"/>
<category term="Visual Studio Code" scheme="https://hhaze.github.io/tags/Visual-Studio-Code/"/>
<category term="VSCode" scheme="https://hhaze.github.io/tags/VSCode/"/>
</entry>
<entry>
<title>Go 시작하기 (macOS)</title>
<link href="https://hhaze.github.io/posts/2018/go-getting-started/"/>
<id>https://hhaze.github.io/posts/2018/go-getting-started/</id>
<published>2018-12-25T06:55:05.000Z</published>
<updated>2021-11-21T14:27:35.516Z</updated>
<content type="html"><![CDATA[<h2 id="Go-설치"><a href="#Go-설치" class="headerlink" title="Go 설치"></a>Go 설치</h2><p>macOS에서 Go 설치하는 방법엔 크게 두 가지가 있는데 나는 첫 번째 방법으로 진행했다.</p><ul><li><strong>Golang 홈페이지에서 다운로드</strong> - <a href="https://golang.org/dl/">https://golang.org/dl/</a></li><li>homebrew 통해 다운로드 - <code>$ brew install go</code></li></ul><p>첫 번째 방법을 선택한 이유는 특별한 것이 아니라 단지 brew 통해서 받을 생각을 미처 못 했었다… 🙈</p><p>설치 파일을 통한 다운로드는 안내에 따르면 된다.</p><h2 id="GOPATH-설정"><a href="#GOPATH-설정" class="headerlink" title="GOPATH 설정"></a>GOPATH 설정</h2><p>설치를 마치고 <code>$ go env</code> 입력하면 <code>GOPATH</code> 및 <code>GOROOT</code> 를 확인할 수 있다.</p><p>GOPATH는 작업 공간을 의미하므로 본인이 작업하는 Path에 맞추어 설정한다.</p><p>내 경우에는 zsh 사용하고 있어 <code>.zshrc</code> 파일에 추가했는데 사용하는 쉘에 맞추어 적용한다.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">export</span> GOPATH=/Users/사용자명/work/go</span><br></pre></td></tr></table></figure><p>작업 공간에는 <code>bin</code>, <code>pkg</code>, <code>src</code> 세 개의 폴더를 생성한다.</p><ul><li><code>bin</code> : 실행 파일 (Command) 위치</li><li><code>pkg</code> : 라이브러리 파일 위치</li><li><code>src</code> : 소스 파일 위치</li></ul><h2 id="Hello-world"><a href="#Hello-world" class="headerlink" title="Hello, world"></a>Hello, world</h2><p>코딩의 시작은 역시 <code>Hello, world</code></p><p>소스 파일 위치에서 <code>hello/hello.go</code> 파일을 만들어 아래 내용을 입력한다.</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">"fmt"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line"> fmt.Println(<span class="string">"Hello, world"</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><p><code> $ go run hello.go</code> 를 통해 실행하거나</p></li><li><p><code>$ go build</code> 로 컴파일 후 <code>$ ./hello</code> 로 실행 파일을 실행하면</p></li></ul><p> <code>Hello, world</code> 출력을 볼 수 있다.</p><p>이제 <code>Go</code> 로 코딩할 준비가 되었다. 🙌</p><h2 id="💁♀️-Tip"><a href="#💁♀️-Tip" class="headerlink" title="💁♀️ Tip"></a>💁♀️ Tip</h2><p>나는 대부분의 경우 <code>go get</code> 을 사용하고 있는데 그래도 궁금해서 <strong>간단하게</strong> 차이를 알아봤다. (더 알고 싶으면 <a href="https://golang.org/cmd/go/">링크</a> 참고)</p><p>심지어 내가 사용하는 IDE (Visual Studio Code) 에서는 <code>import "URL"</code> 을 보고 설치를 도와주기 때문에 따로 설치할 일이 별로 없다. 설치 오류로 누락되는 패키지가 있는 경우에만 <code>go get</code> 사용해서 수동 설치하고 있다.</p><ul><li><p><code>go build</code> : 패키지 컴파일</p></li><li><p><code>go install</code> : 패키지 컴파일 + 설치</p></li><li><p><code>go get</code> : 패키지 다운로드 + 설치 (즉, 다운로드 + <code>go install</code> 인 셈)</p><ul><li><code>GOPATH</code> 에 패키지가 이미 있으면 fetch 생략하므로 <code>go install</code> 과 동일하게 동작</li><li>import 경로의 패키지는 <code>go get</code> 을 통해 <code>fetch -> build -> install</code> 단계 자동으로 수행</li></ul></li></ul>]]></content>
<summary type="html"><h2 id="Go-설치"><a href="#Go-설치" class="headerlink" title="Go 설치"></a>Go 설치</h2><p>macOS에서 Go 설치하는 방법엔 크게 두 가지가 있는데 나는 첫 번째 방법으로 진행했다.</p>
<u</summary>
<category term="Go" scheme="https://hhaze.github.io/tags/Go/"/>
</entry>
<entry>
<title>MongoDB 설치 가이드 (Windows)</title>
<link href="https://hhaze.github.io/posts/2018/mongodb-install-guide/"/>
<id>https://hhaze.github.io/posts/2018/mongodb-install-guide/</id>
<published>2018-12-09T04:15:14.000Z</published>
<updated>2021-11-21T14:27:13.437Z</updated>
<content type="html"><![CDATA[<h2 id="Windows-MongoDB-설치"><a href="#Windows-MongoDB-설치" class="headerlink" title="[Windows: MongoDB 설치]"></a>[Windows: MongoDB 설치]</h2><ol><li><p>MongoDB 홈페이지에서 Windows 용 MSI 파일을 받아서 설치 (Community Server)</p></li><li><p>설치 과정엔 특이사항이 없으니 Default로 진행</p></li><li><p>설치가 완료되면 아래 경로에서 mongod.exe 파일과 mongo.exe 파일 확인</p><ul><li>C:\Program Files\MongoDB\Server\4.0\bin</li></ul></li><li><p>시스템 변수를 편집하여 위에서 확인한 경로를 추가</p><p><img src="image1.png"></p></li><li><p>mongod.exe 파일로 서버를 띄우고 mongo.exe 파일로 접속하여 연결 상태 확인하면 끝</p><ul><li>서버는 localhost:21017</li><li>mongod 실행 시 옵션을 주면 커스텀 가능<ul><li>–dbpath 옵션으로 폴더 경로 지정 (ex. D:\mongodb\data)</li><li>–logpath 옵션으로 로그 파일 지정 (ex. D:\mongodb\log\mongo.log)</li></ul></li></ul></li></ol><h2 id="Windows-Service-등록"><a href="#Windows-Service-등록" class="headerlink" title="[Windows Service 등록]"></a>[Windows Service 등록]</h2><p>매번 .exe 파일이 있는 경로에서 실행하기 번거로우니까 윈도우 서비스로 등록하여 사용 가능</p><ol><li><p>필히 <code>관리자 권한</code>으로 cmd 실행</p></li><li><p>command에서 mongod 실행 시 –install 옵션 설정</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ mongod --install --serviceName MongoDB --serviceDisplayName MongoDB --dbpath <span class="string">"D:\\mongodb\\data"</span> --logpath <span class="string">"D:\\mongodb\\log\\mongo.log"</span> --port 21017</span><br></pre></td></tr></table></figure><ul><li>옵션을 지정하기 귀찮으면 .cfg 파일을 만들어서 사용하는 것도 가능</li><li>–logappend 옵션으로 하나의 로그 파일에 계속 덧붙이기도 가능</li></ul></li><li><p>services.msc 통해 <strong>MongoDB</strong> 서비스 확인 (command에서 설정한 serviceName)</p><p><img src="image2.png"></p></li><li><p>설치하고 나면 아래 명령어로 간단하게 MongoDB Start/Stop 가능</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ net start MongoDB</span><br><span class="line">$ net stop MongoDB</span><br></pre></td></tr></table></figure></li><li><p>혹시 제거하고 싶다면 아래 명령 중 하나를 수행</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ mongod --remove --serviceName MongoDB</span><br><span class="line">$ sc.exe delete MongoDB</span><br></pre></td></tr></table></figure></li></ol><h2 id="MongoDB-Windows-GUI-Robo-3T-설치"><a href="#MongoDB-Windows-GUI-Robo-3T-설치" class="headerlink" title="[MongoDB Windows GUI: Robo 3T 설치]"></a>[MongoDB Windows GUI: Robo 3T 설치]</h2><ol><li><p>Robomongo 홈페이지에 접속해서 Robo 3T 다운로드</p><p><img src="image3.png"></p></li><li><p>설치는 설치판/무설치판 모두 가능</p></li><li><p>MongoDB 실행 후 Robo 3T 실행하여 Connect</p></li><li><p>GUI로 DB 컨트롤 가능</p></li></ol>]]></content>
<summary type="html"><h2 id="Windows-MongoDB-설치"><a href="#Windows-MongoDB-설치" class="headerlink" title="[Windows: MongoDB 설치]"></a>[Windows: MongoDB 설치]</h2><ol</summary>
<category term="MongoDB" scheme="https://hhaze.github.io/tags/MongoDB/"/>
<category term="Robo 3T" scheme="https://hhaze.github.io/tags/Robo-3T/"/>
</entry>
<entry>
<title>[TIL] Redis - Data Types</title>
<link href="https://hhaze.github.io/posts/2018/redis-data-types/"/>
<id>https://hhaze.github.io/posts/2018/redis-data-types/</id>
<published>2018-09-26T12:46:28.000Z</published>
<updated>2019-03-31T04:44:32.727Z</updated>
<content type="html"><![CDATA[<ul><li><p>String</p><ul><li>1:1 관계</li><li>Key-Value 쌍</li><li>SET/GET</li></ul></li><li><p>List</p><ul><li>1:N 관계</li><li>중복 허용</li><li>큐/스택으로 활용</li><li>PUSH/POP</li></ul></li><li><p>Set</p><ul><li>1:N 관계</li><li>중복 불허용</li><li>집합 연산/카드 게임에 활용</li><li>합집합/교집합/차집합 연산 가능</li></ul></li><li><p>Sorted Set</p><ul><li>Score 있는 Set</li><li>Score 값으로 정렬</li><li>Score 값이 같으면 Value 값으로 정렬</li></ul></li><li><p>Hash</p><ul><li>테이블 개념</li><li>Hash Key - PK / Field - Column / Value - Value로 맵핑</li><li>Key가 PK와 같은 역할을 하기 때문에 Key 하나는 테이블의 한 행과 같은 셈</li></ul></li></ul>]]></content>
<summary type="html"><ul>
<li><p>String</p>
<ul>
<li>1:1 관계</li>
<li>Key-Value 쌍</li>
<li>SET/GET</li>
</ul>
</li>
<li><p>List</p>
<ul>
<li>1:N 관계</li>
<li>중복 허용</summary>
<category term="Redis" scheme="https://hhaze.github.io/tags/Redis/"/>
<category term="TIL" scheme="https://hhaze.github.io/tags/TIL/"/>
</entry>
<entry>
<title>[후기] if kakao 개발자 컨퍼런스 2018</title>
<link href="https://hhaze.github.io/posts/2018/if-kakao-2018/"/>
<id>https://hhaze.github.io/posts/2018/if-kakao-2018/</id>
<published>2018-09-04T13:38:50.000Z</published>
<updated>2021-04-04T02:37:53.894Z</updated>
<content type="html"><![CDATA[<h1 id="if-kakao-2018"><a href="#if-kakao-2018" class="headerlink" title="if kakao 2018"></a>if kakao 2018</h1><p>카카오에서 개발자 컨퍼런스를 개최했다. 너무 운 좋게도 참가자로 선정되어 다녀왔다. 주변에 선정된 사람이 극히 드문 걸 보면 경쟁률이 치열했던 모양이다. COEX 그랜드볼룸에서 진행됐고, 오전 10시 5분에 키노트로 시작해서 총 5개의 세션을 포함 오후 5시에 끝났다. 유익하게 잘 들었다. 잊기 전에 내가 들었던 세션들에 대해 간략하게 정리해두려 한다. (들으면서 동시에 필기를 해두지 않아서 상당 부분 기억에 의존한 글이라 불확실할 수 있다.)</p><h4 id="카프카-산전수전-노하우-고승범-peter-ko"><a href="#카프카-산전수전-노하우-고승범-peter-ko" class="headerlink" title="카프카, 산전수전 노하우 / 고승범(peter.ko)"></a>카프카, 산전수전 노하우 / 고승범(peter.ko)</h4><p>카프카로 책까지 출간하신 분께서 발표하셨다. 아마 경험 있는 사람이 들었으면 꽤나 유용하고 깊이 있었으리라. 나는 갓 서버 개발자로 일을 시작한 터라 카프카 잘 모른다. 회사 위키에서 잠깐 맛보기 해봤다고 궁금해서 들어 본 세션이다. 그래도 의미있었다. 회사에 가서 위키를 다시 보면 조금 더 수월하게 이해할 수 있지 않을까.</p><p>클러스터, 파티션, 토픽, 프로듀서, 컨슈머 등의 주요 개념들과 직접 겪었던 문제에 대해 소개해주셨다. 프로듀서는 <code>PUSH</code> 하고 컨슈머는 <code>PULL</code> 하는 그 가운데에 중개자로 카프카가 있다. 프로듀서와 컨슈머의 속도가 다르기 때문에, 카프카가 컨슈머로 PUSH 하는 방식은 사용하지 않는다고 한다. 카프카가 컨슈머들의 속도를 체크해서 보내는 것은 비효율적이니까.</p><p>컨슈머가 PULL 할 때는 <code>offset</code>을 기반으로 하는데, 이로 인해 파티션이 여러 개가 되면 순서를 보장할 수 없다고 한다. 파티션 내에서의 순서는 offset 값으로 보장되지만 파티션 간의 순서는 보장되지 않아서. 따라서 카프카를 사용하면서 순서를 반드시 보장해야 하는 경우, 파티션을 한 개만 사용해야 한다.</p><p>리더와 팔로어 그리고 <code>Replication</code>에 대한 소개도 있었는데, 리더가 다운되었을 때 팔로어가 리더를 위임받고 복제가 어떻게 이루어지는가에 대한 설명들이었다. 팔로어가 여럿일 수 있으니까 다양한 상황에 대해 하나하나 설명하셨다.</p><p>카카오에서는 사용하지 않는 토픽이 늘어만 가는 것을 막기 위해 모니터링?도 하고 있다고 했다. 조건을 두고 (예를 들면 몇 일 이상 사용하지 않는 토픽) 그에 부합하면 삭제 후보가 되어 알리는 방식이다. 중요한 토픽이 삭제되는 경우를 막기 위해 삭제 예정일 몇 일 전부터 알림을 주고 있다고.</p><h4 id="카카오-봇-플랫폼-소개-황지수-mario-h"><a href="#카카오-봇-플랫폼-소개-황지수-mario-h" class="headerlink" title="카카오 봇 플랫폼 소개 / 황지수(mario.h)"></a>카카오 봇 플랫폼 소개 / 황지수(mario.h)</h4><p>제일 넓은 공간에서 진행됐다. 카카오에서 그만큼 중요하게 생각한다는 건가. 사람도 많았다. 플러스 친구로 서비스 되고 있는 카카오 챗봇에 대해 소개하는 세션이었다. 현재 적용된 챗봇 서비스를 동영상으로 보여주고 해당 서비스가 어떻게 구현되었는지 설명하셨다.</p><p><code>오늘 판교 날씨 어때?</code> 같은 간단한 예제로 시작해서 각 모듈?에 대한 설명이 이어졌다. 여기서 <code>오늘</code>이나 <code>판교</code> 같은 특정 값들은 다른 값으로 치환될 수 있으니까 모든 경우를 하나하나 처리하지 않고 하나의 파라미터로 활용을 하는 것이다.</p><p>즉, <code>@시간 @도시 날씨 어때? </code> 와 같은 패턴이 되는 것이다. <code>어때?</code> 라는 어미도 <code>어떠하다</code> 라는 원형으로 치환이 되는 것이라고 했다. 당연하겠지만, 결국 자연어 처리가 핵심인 것 같았다.</p><p>고객 응대를 챗봇으로 부분 대체하면서 상담원 문의량이 줄어든 것이 큰 성과라고 했다. 주문도 챗봇을 통해 할 수 있다고.</p><p>카카오 <code>오픈 빌더</code>는 키노트 때도 강조됐던 내용인데 카카오에서 AI 관련해서 많은 투자를 하고 있다고 느껴졌다. 오픈 빌더는 12월 베타 공개 예정이라고 했나. 오픈 빌더를 통해 챗봇 커스텀이 가능하다는 건데 궁금하다. 카카오 계정이랑 연동해서 편하게 쓸 수 있지 않을까 싶다.</p><h4 id="카카오-광고-플랫폼-MSA-적용-사례-및-API-Gateway와-인증-구현에-대한-소개-황민호-robin-hwang"><a href="#카카오-광고-플랫폼-MSA-적용-사례-및-API-Gateway와-인증-구현에-대한-소개-황민호-robin-hwang" class="headerlink" title="카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개 / 황민호(robin.hwang)"></a>카카오 광고 플랫폼 MSA 적용 사례 및 API Gateway와 인증 구현에 대한 소개 / 황민호(robin.hwang)</h4><p>점심 시간 후에 이어진 세션인데, 나름 늦지 않게 갔는데도 룸이 꽉 차있어서 듣지 못하고 중간에 나왔다… 서서 들으려고 찰나 고민하다 한 턴 쉬고 가는 걸로… 듣지 못해 아쉽다. 나중에 올라오면 들어봐야지.</p><h4 id="비디오-특성-분석-및-딥러닝을-이용한-실시간-인코딩-효율-최적화-여욱형-jaden-y"><a href="#비디오-특성-분석-및-딥러닝을-이용한-실시간-인코딩-효율-최적화-여욱형-jaden-y" class="headerlink" title="비디오 특성 분석 및 딥러닝을 이용한 실시간 인코딩 효율 최적화 / 여욱형(jaden.y)"></a>비디오 특성 분석 및 딥러닝을 이용한 실시간 인코딩 효율 최적화 / 여욱형(jaden.y)</h4><p>그나마 배경 지식이 조금 있다고 제일 재밌게 들었던 세션이다. 각 기반 기술들(딥 러닝이나 인코딩)에 대한 지식이 깊지 않지만 맥락을 따라갈 수 있었다. HLS 경력을 더 깊게 전문적으로 이어 갔다면 비슷한 고민과 시도를 하는 순간이 오지 않았을까. 물론 내가 이러한 고민과 시도를 할 수 있는 훌륭한 조직에 있을 것이라는 전제가 필요하겠다.</p><p>제목 그대로 비디오 특성 분석이 선행하고 그에 맞추어 인코딩 값을 설정하겠다는 것이 포인트다. <code>Netflix</code> 나 <code>Youtube</code> 도 그러한 흐름으로 변화하고 있다고 한다. 영상 특징에 따라 비트레이트를 배분하는 것이다. 스트리밍을 하기 위해선 스트림에 대한 인코딩이 필요한데, 그 앞 단에 초적의 인코딩 파라미터를 찾는 딥러닝을 선행한다. 이를 통해, 예를 들면, 정적인 화면과 동적인 화면에서 할당하는 비트레이트를 다르게 하여 효율은 높이고 손실은 최소화 할 수 있게 된다.</p><p>영상을 분석의 요소들도 굉장히 다양했는데, 앞서 예로 들었던 움직임도 하나고 해상도나 프레임을 구성하는 블록 및 파티션 사이즈 분포 등도 있었다. 약 20여가지의 데이터를 가지고 영상을 분석한다고 했다. 또한 평균 비트레이트를 의미하는 <code>ABR(Average Bit-Rate)</code> 과 비교하며 이 방식에 대한 장/단점을 소개해주셨다.</p><p>동영상 서비스가 늘어나는 만큼 중요하고 필요한 일이겠다는 생각이 들었다. 유익한 세션이었다.</p><h4 id="글로벌-게임-플랫폼에서-무정지-무점검-서버-개발과-운영-사례-김태현"><a href="#글로벌-게임-플랫폼에서-무정지-무점검-서버-개발과-운영-사례-김태현" class="headerlink" title="글로벌 게임 플랫폼에서 무정지, 무점검 서버 개발과 운영 사례 / 김태현"></a>글로벌 게임 플랫폼에서 무정지, 무점검 서버 개발과 운영 사례 / 김태현</h4><p>이 세션은 유일하게 블리자드 시니어 개발자님께서 발표하셨다. 선물로 키 체인과 스타크래프트 리마스터 팩을 👍</p><p>무정지, 무점검 서버 개발이라는 매혹적인 문구에 듣게 된 세션이다. 발표자님께서 유쾌하셔서 분위기가 제일 좋았던 세션이다. 무정지, 무점검을 어렵게 하는 것들을 소개하고 블리자드에서는 어떻게 해결하고 있는지 소개하셨다.</p><ul><li>패치<ul><li><code>Flipping</code> 방식을 통해 패치 전/후 버전으로 Site를 두 벌 준비하고 그대로 뒤집기</li><li>이를 통해 역으로 버전을 올렸다가 문제가 생겨서 낮추는 것도 쉽게 하고 있다고</li></ul></li><li>설정 변경 (config)<ul><li>설정 파일 자체를 서버에 두지 않고 Google <code>Protobuf</code> 프로토콜을 이용</li></ul></li><li>상수 변경<ul><li><code>Var System</code> 이라 부르는 것을 사용해서 외부에서 상수 값을 실시간으로 수정</li><li>이것이 보안 취약점이 아니냐는 어떤 분의 예리한 질문이 있었는데 일단 망 분리가 되어 있고 문제 없이 쓰고 있다고 답변</li></ul></li><li>스케일링<ul><li>잘 기억나지 않는다.</li></ul></li><li>장애<ul><li>장애는 피할 수가 없으니 장애에서 빨리 복구하는 것을 중점으로 하고</li><li>원인 모를 장애가 발생했을 땐 트러블 슈팅에 시간을 쏟기 전에 일단 Flipping을 통해 서버를 먼저 재배포</li><li>그 후 장애가 발생한 서버는 서비스하지 않은 상태에서 트러블 슈팅을 진행</li></ul></li></ul><p>모든 서버의 상태를 체크할 수 있는 GUI를 활용하고 있다고 설명하셨고 DevOps를 하나의 문화로서 받아들이고 있다고도 설명하셨다. AI가 더 고도화되어 가는 시대에 기술이 어떻게 변할지에 대해서도 간략하게 본인의 생각을 말씀해주시고 세션을 마쳤다.</p><hr><p>당장 활용할 수 있는 부분은 적을 것 같지만 견문을 넓히기엔 충분했다. 꾸준히 공부해야지. 🤓</p>]]></content>
<summary type="html"><h1 id="if-kakao-2018"><a href="#if-kakao-2018" class="headerlink" title="if kakao 2018"></a>if kakao 2018</h1><p>카카오에서 개발자 컨퍼런스를 개최했다. 너무 운</summary>
<category term="if kakao" scheme="https://hhaze.github.io/tags/if-kakao/"/>
<category term="review" scheme="https://hhaze.github.io/tags/review/"/>
<category term="후기" scheme="https://hhaze.github.io/tags/%ED%9B%84%EA%B8%B0/"/>
<category term="kakao" scheme="https://hhaze.github.io/tags/kakao/"/>
<category term="카카오" scheme="https://hhaze.github.io/tags/%EC%B9%B4%EC%B9%B4%EC%98%A4/"/>
</entry>
<entry>
<title>HLS (Http Live Streaming)</title>
<link href="https://hhaze.github.io/posts/2018/all-about-hls/"/>
<id>https://hhaze.github.io/posts/2018/all-about-hls/</id>
<published>2018-08-29T13:35:34.000Z</published>
<updated>2021-04-04T02:37:53.890Z</updated>
<content type="html"><![CDATA[<h2 id="Overview"><a href="#Overview" class="headerlink" title="Overview"></a>Overview</h2><p>HLS는 Apple에서 만든 HTTP 기반의 스트리밍 프로토콜이다. 현재 기준 (2018.08) 최신 프로토콜 버전은 8이고, 관련 스펙은 <a href="https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-02#page-4">2nd Edition</a>으로 계속 업데이트 되고 있다.</p><h4 id="구성-요소"><a href="#구성-요소" class="headerlink" title="구성 요소"></a>구성 요소</h4><p><img src="https://docs-assets.developer.apple.com/published/88e87744a3/de18e941-81de-482f-843d-834a4dd3aa71.png"></p><p>이미지 출처: <a href="https://developer.apple.com/documentation/http_live_streaming">https://developer.apple.com/documentation/http_live_streaming</a></p><p>HLS는 <code>Playlist</code>라고 부르는 <code>.m3u8</code> 파일을 통해 서비스 되는데 그 과정은 다음과 같다.</p><ul><li>Input(Content)이 MPEG-TS로 인코딩되고</li><li>인코딩 된 파일을 고정 값(duration)을 가지는 .ts 파일들로 작게 나누고 @서버</li><li>그 파일들을 인덱싱해서 playlist 파일로 서비스하고</li><li>URL로 .m3u8 및 .ts 파일을 요청 및 다운로드 받아 재생하고 @클라이언트</li></ul><p>즉, 서버에서는 컨텐츠를 인코딩해서 자르고 클라이언트에서는 그 조각난 파일들을 받아 재생한다.</p><h2 id="Adaptive-Streaming"><a href="#Adaptive-Streaming" class="headerlink" title="Adaptive Streaming"></a>Adaptive Streaming</h2><p>HLS의 탄생 배경을 이해하기 위해 Adaptive Streaming에 대해 알고 있으면 좋다.</p><p>Adaptive Streaming이란 Multi-bitrate을 지원하는 스트리밍 방식을 말한다. 실시간으로 네트워크 상태에 따라 High<->Low Bitrate switching을 하며 <code>끊김없는 재생</code>을 목표로 한다. 기존에는 전체 100을 한 번에 다운로드 받았다면, Adaptive에서는 전체 100을 10개의 조각(segment)으로 나누어 그 때 그 때 네트워크 상황에 맞추어 High-Mid-Low Bitrate stream을 선택하는 것이다. 이는 결국 <code>버퍼링을 최소화</code>하고 최적의 환경을 제공하기 위함이다.</p><p>HLS는 바로 이 Adaptive streaming의 한 종류이다. 대표적인 다른 프로토콜은 MPEG-DASH, Microsoft Smooth Streaming 등이 있다.</p><h2 id="Playlist"><a href="#Playlist" class="headerlink" title="Playlist"></a>Playlist</h2><p>HLS는 Manifest로 <code>.m3u8</code> 확장자를 가지는 <code>playlist</code> 파일을 사용한다. (각 프로토콜 별로 Manifest 파일의 확장자가 다르다.) playlist에는 <code>Master Playlist</code> 그리고 <code>Media Playlist</code> 두 종류가 있다. Master Playlist가 Media Playlist를 품고 있는 구조이다. Master Playlist에는 Stream 전체에 대한 정보가 Media Playlist에는 Segment에 대한 정보가 있다고 보면 된다. </p><p>Example을 보면 이해하기 좋을 것 같다. 공식 Draft에 있는 Example을 발췌하여 약간 수정했다.</p><p><strong>Master Playlist</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">#EXTM3U</span><br><span class="line">#EXT-X-STREAM-INF:BANDWIDTH=1280000,AVERAGE-BANDWIDTH=1000000</span><br><span class="line">http://example.com/low.m3u8</span><br><span class="line">#EXT-X-STREAM-INF:BANDWIDTH=2560000,AVERAGE-BANDWIDTH=2000000</span><br><span class="line">http://example.com/mid.m3u8</span><br><span class="line">#EXT-X-STREAM-INF:BANDWIDTH=7680000,AVERAGE-BANDWIDTH=6000000</span><br><span class="line">http://example.com/hi.m3u8</span><br></pre></td></tr></table></figure><p><strong>Media Playlist</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">#EXTM3U</span><br><span class="line">#EXT-X-TARGETDURATION:10</span><br><span class="line">#EXT-X-VERSION:3</span><br><span class="line">#EXTINF:9.009,</span><br><span class="line">first.ts</span><br><span class="line">#EXTINF:9.009,</span><br><span class="line">second.ts</span><br><span class="line">#EXTINF:3.003,</span><br><span class="line">third.ts</span><br><span class="line">#EXT-X-ENDLIST</span><br></pre></td></tr></table></figure><p>예제에는 없지만 처음에 Master Playlist를 다운로드 받기 위한 URL이 있을 것이고, 그 파일의 내용이 위와 같다고 하자. <code>BANDWIDTH</code> 속성 값으로 나누어져 있는 URL이 Media Playlist를 다운로드 받기 위한 URL이 된다. - low.m3u8 / mid.m3u8 / hi.m3u8</p><p>Multi-bitrate으로 인코딩 된 컨텐츠를 제공할 뿐, 동시에 여러 개의 Bandwidth를 재생하는 것은 아니다. 따라서 재생 시점에는 현재 네트워크 상황에 맞는 하나의 Media Playlist가 선택되고, 해당 Media Playlist에 명시된 .ts 파일들을 순차 재생하게 된다.</p><p>예를 들어, Media Playlist로 <a href="http://example.com/mid.m3u8">http://example.com/mid.m3u8</a> URL이 선택되었다면 처음 .ts 파일을 받기 위한 URL은 <a href="http://example.com/mid/first.ts">http://example.com/mid/first.ts</a> 같은 형식이 되는 것이다. High-bitrate으로 Switching 되어 재생을 이어간다면, <a href="http://example.com/hi/second.ts">http://example.com/hi/second.ts</a> 파일을 다운로드 받게 될 것이다.</p><p>즉, 각 Media Playlist에 있는 .ts 파일들은 동일한 컨텐츠를 담고 있는 것이다. <code>#EXTINF</code> Tag는 Duration 값을 나타내는데 아래 파일들 모두 9초 분량의 동일 컨텐츠인 셈이다. 물론 해상도는 다를 것이다.</p><ul><li>low/first.ts</li><li>mid/first.ts</li><li>hi/first.ts</li></ul><hr><p>다 아는 내용이라 금방일 줄 알았는데 괜찮은 글로 정리하려니 시간이 오래 걸린다. Tag는 굉장히 많아서 그 소개는 다음 포스팅으로 넘어가야 할 것 같다. 🧐</p>]]></content>
<summary type="html"><h2 id="Overview"><a href="#Overview" class="headerlink" title="Overview"></a>Overview</h2><p>HLS는 Apple에서 만든 HTTP 기반의 스트리밍 프로토콜이다. 현재 기준 (2</summary>
<category term="HLS" scheme="https://hhaze.github.io/tags/HLS/"/>
<category term="Streaming" scheme="https://hhaze.github.io/tags/Streaming/"/>
</entry>
</feed>