<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yong_dev.log</title>
        <link>https://velog.io/</link>
        <description>용한 개발자</description>
        <lastBuildDate>Fri, 01 Nov 2024 12:14:39 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yong_dev.log</title>
            <url>https://velog.velcdn.com/images/yong_dev/profile/c1dc9685-ef04-43db-b658-611d3ad53f57/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yong_dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yong_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[해외 API 캐싱 서버 구축 및 성능 개선]]></title>
            <link>https://velog.io/@yong_dev/%ED%95%B4%EC%99%B8-API-%EC%BA%90%EC%8B%B1-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95-%EB%B0%8F-%EC%84%B1%EB%8A%A5-%EA%B0%9C%EC%84%A0</link>
            <guid>https://velog.io/@yong_dev/%ED%95%B4%EC%99%B8-API-%EC%BA%90%EC%8B%B1-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95-%EB%B0%8F-%EC%84%B1%EB%8A%A5-%EA%B0%9C%EC%84%A0</guid>
            <pubDate>Fri, 01 Nov 2024 12:14:39 GMT</pubDate>
            <description><![CDATA[<h3 id="문제">문제</h3>
<p>TMDB API를 통해 서비스를 구현하고 있었습니다.</p>
<p>영화 포스터를 제공하는 API로는 거의 유일해서 선택했습니다. 
하지만 해외에 있는 서버이다 보니, 라우팅 지연으로 인해 대기 및 연결 시간이 길었습니다.
<img src="https://velog.velcdn.com/images/yong_dev/post/28685871-7dab-45e7-af02-7da13a629df3/image.png" alt="">
그리고 해외 사이트다 보니 국내 인기 영화 순위와 차이가 있었습니다.
다른 API를 써보려고 해도 마땅치 않았습니다.
국내에 영화진흥위원회(KOFIC)가 제공하는 API가 있긴 했지만, 포스터를 제공해주지 않았습니다.</p>
<h3 id="구상-및-해결책">구상 및 해결책</h3>
<p>처음엔 두 개의 API를 모두 쓸 생각이었습니다. </p>
<p>KOFIC에서 주간 인기 영화 리스트를 받아온다 </p>
<p>⇒ 해당 영화 제목으로 TMDB에 포스터 API 요청을 보낸다. </p>
<p>⇒ 두 요청의 응답을 합쳐서 데이터를 만들어서 화면에 뿌린다. </p>
<p>하지만 이러면 가뜩이나 소요 시간이 긴 해외 API를 쓰면서 다른 요청도 연달아 해야하는 꼴입니다. </p>
<p>그래서 해결 방안을 고민하던 차에, 이전에 공부했던 Next.JS 생각이 났습니다. Next.JS가 제공하던 기능 중 SSG는 프로젝트 빌드 시 미리 데이터 요청을 하고, 해당 요청을 바탕으로 화면을 만들어놓습니다. </p>
<ul>
<li>이번 서버는 일주일에 한 번 캐싱하니 ISR에 가깝겠습니다.</li>
</ul>
<p>거기서 아이디어를 얻어, 두 개의 API 요청을 미리 해 두고 그 값을 저장해둔다면 어떨까? 하는 생각이 들었습니다. </p>
<ul>
<li>CDN을 구축한것과 비슷하네요.</li>
</ul>
<p>TMDB와 KOFIC에서 필요한 정보만 요청해 온 다음, 캐싱해서 데이터를 다시 가져올 필요 없이 제공한다면? 이 서버를 클라우드로 배포한다면? 영화 순위 API 뿐만 아니라, 다른 기능도 만들 수 있습니다. </p>
<p>구상해 보니 아주 좋은 생각 같아서 바로 만들어봤습니다. </p>
<h3 id="기술-스택">기술 스택</h3>
<p>Nest.JS와 EC2를 선택했습니다. </p>
<p>이전에 express로 crud 서버를 구현해 본 적이 있어서 express 기반 프레임워크인 Nest.JS를 써보고 싶었습니다. 그리고 캐싱, cron 등 이번 서버 제작에 핵심적인 기능을 자체적으로 내장하고 있다는 점도 좋았습니다. </p>
<p>Cloudtype으로 express 서버를 간단하게 배포했던 기억이 있어서 사용할까 했지만, 무료 계정은 하루에 한 번 서버를 수동으로 재가동해야 한다는 점이 아주 불편했던 기억이 있어서, AWS에서 제공하는 free tier 인스턴스를 이용하기로 했습니다.</p>
<h3 id="서버-제작">서버 제작</h3>
<ol>
<li><p>KOFIC에서 영화 목록 불러와서 영화 제목 및 기타 정보 추출하기 </p>
<p> ⇒ 영화 순위는 매주 일요일 바뀌므로 그 전 주의 일요일의 날짜로 데이터 요청하기 </p>
</li>
<li><p>1에서 얻은 제목 리스트로 TMDB에 포스터 URL 요청하기 </p>
<p>⇒ TMDB에서는 영화 제목에 숫자가 들어있으면 한 자 띄워야 제대로 영화 제목을 인식하므로 숫자가 포함된 제목은 수정하기. </p>
</li>
<li><p>2, 3 데이터 합쳐서 메모리에 캐싱하기 </p>
<p> ⇒ 영화 순위는 매주 일요일 바뀌므로 cron을 이용해 일주일에 한 번, 월요일 자정 캐싱하기 </p>
</li>
<li><p>API요청 시 캐싱한 데이터로 응답하게 하기 </p>
</li>
</ol>
<p>이렇게 서버를 만들어서 ec2에 배포했습니다. </p>
<h3 id="성과">성과</h3>
<p>TBDB api와 제가 만들어 배포한 AWS api에 각각 열 번씩 요청을 보내고, 그 소요 시간의 평균을 측정했습니다. 
<strong>네트워크 탭에서 캐시 사용 중지 항목을 체크한 후 진행했습니다.</strong></p>
<p><strong>TMDB API</strong>
<img src="https://velog.velcdn.com/images/yong_dev/post/5548fe0e-97aa-4f59-9652-f5535026653d/image.png" alt="">
평균 : 209.82ms</p>
<p><strong>AWS API</strong>
<img src="https://velog.velcdn.com/images/yong_dev/post/3fcd11c8-1e7c-47d0-a607-05084fdb1d87/image.png" alt="">
평균 : 18.50ms
아주 만족스럽습니다. 열 배 이상 빨라졌습니다. </p>
<p>개발자도구도 보겠습니다. </p>
<p><strong>TMDB API</strong>
<img src="https://velog.velcdn.com/images/yong_dev/post/f466c814-0960-4072-9b41-097d679fac1b/image.png" alt="">
<img src="https://velog.velcdn.com/images/yong_dev/post/cf9b0650-1ef1-4c33-9c48-d1f7234a9088/image.png" alt="">
데이터 응답이 와야 화면이 그려지기 시작하므로, 477ms 까지 화면에 spinner만 보입니다. </p>
<p><strong>AWS API</strong>
<img src="https://velog.velcdn.com/images/yong_dev/post/def1926d-ceac-4ef0-97dd-5b6ba44e79bd/image.png" alt="">
317ms 정도부터 화면이 그려지는 모습입니다. 
⇒ API 속도 차이와 비슷한 차이가 납니다 </p>
<p>200ms. 사람에 따라 길 수도, 짧을 수도 있는 수치입니다만, 개발 공부를 진행하면서 거의 처음으로 진행한 성능 최적화 작업에서 유의미한 성과를 거두었다고 생각합니다. </p>
<p>개발자도구의 성능 탭을 이렇게 주의 깊게 본 적은 처음인데, depth가 굉장히 깊어서 놀랐습니다. 작은 데이터도 시사하는 바가 있기에 그런 것이겠죠. 개발자도구에 대해 좀 더 공부해 봐야겠다는 생각이 들었습니다. </p>
<p>성과를 측정하면서 느낀 점은, 아 이렇게 측정을 해봐야 실제로 효과가 있다는 걸 알 수 있구나. 라는 겁니다. </p>
<p>어떤 분야의 전문가는 문제 해결의 접근에 있어 모호한 구석이 없어야 한다고 생각합니다. 이 방법이 통할지는 둘째 치고, 이 방법이 불러올 결과에 대해서는 명확히 알아야 한다고 생각합니다. </p>
<p>평소 가지고 있는 생각입니다만, 런앤픽스를 반복하는 자신을 마주치곤 합니다. 전문가가 되고 싶습니다. </p>
<h3 id="겪었던-문제">겪었던 문제</h3>
<p>TMDB요청은 처음 요청 이후에는 거의 소요 시간이 없습니다*  10ms 정도였습니다. 적신호입니다. 몇 시간의 투자가 물거품이 될 상황입니다. </p>
<p>반면 AWS는 TMDM의 첫 요청보다는 짧지만, 그 시간이 줄어들진 않습니다. </p>
<p>문제는 Cache-Control 헤더였습니다. </p>
<p>Client는 네트워크 요청을 하고, Server는 이 요청을 처리합니다. 그런데 만약, 클라이언트가 이전에 요청한 데이터와 새로 요청한 데이터가 같다면 더 이상의 요청은 낭비일 수 있습니다. </p>
<p>이때 쓰이는 것이 HTTP가 제공하는 Cache-Control입니다. </p>
<p>클라이언트의 요청을 캐시 서버나 로컬 캐시 관리자에 전달하고, 캐시 된 문서가 있는지 조회한 후, 존재한다면 유효성 체크까지 마친 뒤, 새로 생성한 헤더와 기존의 Body를 조합해서 서버에서 온 응답처럼 캐시된 데이터를 재사용합니다. 이 때 네트워크 요청을 일어나지 않습니다. </p>
<p>유효성 체크에 유효기간 설정이나 ETag가 쓰이는데, </p>
<p>첫 요청 때 데이터와 Etag를 받고, 다음 요청에 Etag를 같이 보내서 만약 해당 태그의 데이터가 변경되지 않았다면 응답으로 304 Not Modified를 보냅니다. 캐시된 데이터가 사용됩니다. </p>
<p>만약 데이터가 변경되었다면 ETag도 변경되며, 새로운 데이터와 업데이트된 ETag를 받게 됩니다. </p>
<ul>
<li>데이터의 차이를 인식하게 한다는 점에서 mongodb의 __v 필드와 비슷하다는 생각이 들었습니다.</li>
</ul>
<pre><code class="language-jsx">  @Header(&#39;Cache-Control&#39;, &#39;max-age=3600&#39;)</code></pre>
<p>이 코드를 AWS 서버에 추가해서 해결했습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Sanity 에러(Error: Given project ID (22i8bajs) not found, or you do not have access to it) 해결방법. ]]></title>
            <link>https://velog.io/@yong_dev/Sanity-%EC%97%90%EB%9F%ACError-Given-project-ID-22i8bajs-not-found-or-you-do-not-have-access-to-it-%ED%95%B4%EA%B2%B0%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@yong_dev/Sanity-%EC%97%90%EB%9F%ACError-Given-project-ID-22i8bajs-not-found-or-you-do-not-have-access-to-it-%ED%95%B4%EA%B2%B0%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Fri, 30 Aug 2024 17:57:27 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>_답을 찾는 과정에 있던 일들을 기억을 더듬어가며 작성했습니다. 해결방법만 원하시는 분은 스크롤을 끝까지 내려주세요. _</p>
</blockquote>
<p>클론코딩을 하던 중 Sanity를 사용하게 되었습니다. 
<em><strong>이전에 써봤던</strong></em> 기술인지라 별 어려움 없으리라 생각했습니다. 
그러나 이게 왠걸, 
<img src="https://velog.velcdn.com/images/yong_dev/post/8c56e622-a7e9-451b-9e5e-169e94c79d20/image.png" alt="">
처음 보는 오류를 맞닥뜨립니다. </p>
<p>project ID 문제는 아닙니다. 방금 생성한 프로젝트이며, Sanity에서 제공하는 client install코드를 copy버튼을 눌러 복사해왔습니다. 
그럼 문제는 &#39;you do not have access to it&#39;. 권한이 없다. 
이제 막 설치하려던 참인데?
프로젝트를 만드는 다른 방법인, cli에서의 프로젝트 생성을 시도해봅니다. 
<code>npm create sanity@latest</code>
<img src="https://velog.velcdn.com/images/yong_dev/post/175818fe-7680-4303-b352-8883b7942c64/image.png" alt="">
잘 됩니다?! 
<img src="https://velog.velcdn.com/images/yong_dev/post/6db429b9-c5f5-4583-b4f4-953739b686aa/image.png" alt="">
참고로 &quot;The default dataset configuration has a public dataset named &#39;production&#39;&quot;.을 yes라고 하면 견본 데이터셋을 만들어서 넣어줍니다. 원치 않으신다면. No라고 입력하시면 됩니다.</p>
<p>다 만들어졌습니다. 왜 웹에서는 작동하지 않았을까요? Sanity웹을 확인해봐야겠습니다. 
<img src="https://velog.velcdn.com/images/yong_dev/post/54ad5c5a-cc68-4d74-a76b-1e9b33919a0c/image.png" alt="">
깨끗합니다. 프로젝트가 만들어지지 않았습니다. </p>
<p>정확히는, 만들어졌지만, <em><strong>이 계정에</strong></em> 만들어지지 않았습니다. 
문득 떠오르는 과거의 기억. 저는 과거 클론코딩을 하면서 Sanity를 쓴 적이 있습니다. 다른 계정입니다. 
그 계정으로 접속해봅니다. 
<img src="https://velog.velcdn.com/images/yong_dev/post/e8d18bd0-28ee-4df0-8368-bebd347f43f5/image.png" alt="">
세상에, 여기에 있습니다. </p>
<p>왜 이전 계정에 프로젝트가 생성된걸까요? 
당시 프로젝트는 로컬에서 모두 삭제했고, Sanity모듈도 지웠습니다. 그게 아마 작년 9~10월. _<strong>거의 1년 전</strong>_의 일입니다. 
vscode에 뭔가 기록이 남아있을까요? 아닙니다. 그 때와는 다른 github계정을 쓰고있습니다. </p>
<p>스택 오버플로우를 계속 넘겨도 비슷한 이슈가 보이지 않습니다. 
그 때 눈에 뛴 문구 하나. 
<img src="https://velog.velcdn.com/images/yong_dev/post/ba25d49c-125f-4cf2-8e37-a55cd7135618/image.png" alt="">
슬랙 커뮤니티? 선임 개발자의 조언은 귀중합니다. 당장 가서 물어봅시다. 
<img src="https://velog.velcdn.com/images/yong_dev/post/763e4b82-5968-44f3-b5c6-e19385de7717/image.png" alt="">
질문 작성! 
이후 답변이 달리길 기다리며, 약 두 시간에 걸친 구글링에 지친 몸을 이끌고 카페에 갔습니다. 
커피를 마시며 멍을 때리는데, 도통 답변이 달리질 않습니다. 시간이 너무 지체됩니다. 사람이 아닌 ai가 답변해주는 카테고리에 다시금 질문합니다. 
<img src="https://velog.velcdn.com/images/yong_dev/post/a664fa6b-b066-4b9f-a324-60ca5de935a2/image.png" alt="">
오? sanity whoami ? sanity logout? 
가슴이 뜁니다. 이거 뭔가 먹힐 것 같은 느낌입니다. 바로 집으로 달려와서 입력합니다. 
<img src="https://velog.velcdn.com/images/yong_dev/post/9d774c0f-4f1b-476c-b835-c780798ea886/image.png" alt="">
아! 아찔했지만 정신차립니다. 아직 sanity 설치 안했습니다. 당연합니다.
설치합니다. 공식문서에 따르면, sanity cli를 사용하기 위해서 글로벌하게 설치해야합니다. </p>
<pre><code>npm install --global sanity@latest</code></pre><p>그 후 다시 &quot;sanity whoami&quot;
<img src="https://velog.velcdn.com/images/yong_dev/post/5f26c5b6-1ae8-4f13-96b7-59d05c5201f7/image.png" alt="">
오! 커맨드는 틀렸지만 cli를 사용할 수 있게 되었습니다. 
뒤에나온 sanity logout을 실행해봅니다
<img src="https://velog.velcdn.com/images/yong_dev/post/f61bcbf9-0971-4d6a-96cc-0cfa9cc2bf5a/image.png" alt="">
??????????????
로그아웃(로그인 한 적 없음)을 했습니다. 
그 다음 부턴 일사천리였습니다. 
로그인을 하고, 
<img src="https://velog.velcdn.com/images/yong_dev/post/c8cfb15b-c497-4d51-817b-1355beb52281/image.png" alt="">
프로젝트도 무사히 만들었습니다. 
잘됐구만요~~</p>
<p>하지만 아직 찜찜합니다. 
대체 어떻게 1년 가까이 지난 지금까지도, 모듈이 삭제되었는데도 로그아웃을 유지하고 있던걸까요? 
전역에서도, 프로젝트 폴더에서도 Sanity는 없었습니다. </p>
<p>Sanity cli라는 해결방법을 추천해준 야무진 ai에게 다시 물어봅니다. 
<img src="https://velog.velcdn.com/images/yong_dev/post/1529d428-9daa-42a1-b600-29ba5f29535d/image.png" alt="">
useCurrentUser라는 훅이 최근 인증된 유저 정보를 검색한답니다. 하지만 이것도 아닙니다. 이 훅은 Sanity가 설치되어 있어야 동작합니다. 
그러다 문득 공식문서를 유심히 보지 않았다는 사실을 깨달았습니다. 
인증? authentication 검색. 
<img src="https://velog.velcdn.com/images/yong_dev/post/0422232d-bacf-416f-859c-150515bebbe7/image.png" alt="">
...
<br>
&quot;개입없이 개인 토큰은 1년동안 지속됩니다. Sanity CLi에서 로그아웃한 후 후속 로그인은 새 개인 토큰을 생성하고, 그렇게 하면서 이전 토큰을 무효화합니다&quot;
<br></p>
<pre><code>sanity debut --secrets</code></pre><br>
딸깍

<p><img src="https://velog.velcdn.com/images/yong_dev/post/25263e97-6d2d-4157-9b6c-2b696b6d42c8/image.png" alt="">
그랬습니다. 
약 1년전의 로그아웃을 하지 않은 저는 1년후의 저에게 유효기간이 채 한 달이 남지 않은 토큰을 선물로 주었던 것입니다. (모듈삭제 시에도 토큰이 남아있는것을 실험을 통해 재확인 하였습니다)
그리고 분명 cli로 로그인을 했을 저는 그 사실을 잊어버리고 온 사방을 헤멘 것입니다. </p>
<p>.
.
.</p>
<p>저는 지금껏 기록과 정리에 큰 노력을 기울이지 않았습니다. 쓰다보면 눈에 익겠지~라는 생각에 그랬던 것 같습니다.
그 결과 벌어진 이번 일은, 해결이 된 지금은 작은 해프닝이지만, 해결까지의 혼란은 상당한 것이었습니다. 분명 클론코딩을 하면서 익숙해졌다고 생각했는데, 시간이 지나니 생판 처음보는 기술처럼 느껴졌던 것입니다. </p>
<p>문제에 대한 접근도 반성할 점이 있습니다. 
에러가 발생했을 때,그 해결책을 공식문서가 아닌 블로그를 통해 구하려고 했다는 점입니다. 
만약 어떤 블로그에서 저보다 먼저 이 문제에 부딪힌 사람의 글을 발견했다면, 
저는 그저 copy &amp; paste를 통해 문제를 해결했을 것이 분명합니다. 
그러고선 아 잘됐구만~ 하고 프로젝트를 마저 진행했을 것이고, 오늘 얻은 교훈이나 지식들은 한층 더 멀어졌을 것입니다. 
오히려 행운이었다고 생각합니다. 앞으로는 블로그가 아닌 공식문서를 먼저 찬찬히 보는 습관을 들이려 합니다. </p>
<p>이번 일을 기록의 중요성을 실감하게 되는 계기가 되었습니다. 앞으론 공부한 내용을 잘 정리해보려 합니다. 
블로그도 조금씩 써 볼 생각입니다. 블로그에 글을 쓰다보니, 모르는 것을 차마 얼버무릴 수가 없습니다. 
읽어주셔서 감사합니다. </p>
<br>
<br>
<br>
<br>
<h3>해결 방법</h3>

<p>기존에 사용했던 계정이 logout되지 않은 상태에서 발생하는 에러입니다.</p>
<pre><code>npm install --global sanity@latest</code></pre><p>cli를 설치하신 다음, </p>
<pre><code>sanity logout</code></pre><p>로그아웃 하시고,</p>
<pre><code>sanity login</code></pre><p>프로젝트를 만드신 계정으로 로그인 하시면 해결됩니다. </p>
]]></description>
        </item>
    </channel>
</rss>