<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Life and IT</title>
    <link>https://lifeandit.tistory.com/</link>
    <description>삶과 개발 공부를 기록하는 프티 입니다.</description>
    <language>ko</language>
    <pubDate>Fri, 17 Apr 2026 03:24:29 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>프티</managingEditor>
    <image>
      <title>Life and IT</title>
      <url>https://tistory1.daumcdn.net/tistory/4513459/attach/cb49265a83ef48ee96672016cde29553</url>
      <link>https://lifeandit.tistory.com</link>
    </image>
    <item>
      <title>동적 프로그래밍[Dynamic Programming]</title>
      <link>https://lifeandit.tistory.com/156</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;Concept&lt;/b&gt;&lt;br /&gt;1. 문제를 더 작은 조각으로 나눈다.&lt;br /&gt;2. 앞에 위치한 조각을 기억한다.&lt;br /&gt;3. 기억하고 있는 조각을 통해서 작업의 양을 줄인다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언제 이것을 사용할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 2가지를 통해서 DP 알고리즘 사용 여부를 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;최적화를 할 수 있는 부분 구조의 존재여부&lt;/b&gt; [Optimal Substructure]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;반복되는 하위 로직의 존재여부&lt;/b&gt; [Overlapping subproblems]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;최적화를 할 수 있는 부분 구조의 존재여부&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[Optimal Substructure]&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;체크포인트&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;- 하위 문제의 최적 해답으로 상위 문제의 최적 해답을 구할 수 있는지?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;A -&amp;gt; ... -&amp;gt; Z로 가는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;최적 경로를 구하는 알고리즘과 같은 경우에, 위 사항을 체크해보아야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;A부터 Z까지 도달하는 데에 경로는 무수히 많을 수 있기 때문에 &lt;b&gt;각 단계별로의 최적 경로를 찾아 합할 수 있는지가 중요&lt;/b&gt;하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;사실 체감은 잘 안되기는 한다..&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;반복되는 하위 로직의 존재여부&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[Overlapping subproblems]&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;체크포인트&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;- 작은 문제로 나뉠 수 있는지?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;- 재활용 될 수 있는지?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;작은 문제로 나뉠 수 있고, 재활용될 수 있다면?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;-&amp;gt; 재활용 가능한 함수 형태로 작은 문제들을 구하고, 그 값을 기억하여 다음 연산에 사용한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;예시&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;피보나치 수열을 예로 들어보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;피보나치수열은 앞의 2개 숫자를 더한 값이 그다음 숫자로 나오는 수의 나열이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;1, 1, 2, 3, 5, 8, 13, ....와 같은 방식으로!&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이러한 방식은 단순 합의 나열 뿐만 아니라, 함수로의 나열 형태 또한 나타날 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;즉 앞의 2개의 함수의 연산값이 그 다음 함수의 연산값인 것으로 생각해 볼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 트리로 표현해보면,&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;피보나치수열 예시&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;fn(5)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;fn(4)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; +&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;b&gt;fn(3)&lt;/b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;b&gt;fn(3)&lt;/b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; +&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;b&gt;fn(2)&lt;/b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;b&gt;fn(2)&lt;/b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; +&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;b&gt;fn(1)&lt;/b&gt;&lt;br /&gt;&lt;b&gt;fn(2)&lt;/b&gt; +&amp;nbsp; &lt;b&gt;fn(1)&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 fn(3), fn(2), fn(1)의 연산값이 반복되어 나타나고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;값을 저장하는 방식&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 2가지 조건 모두, 하위 문제에 대한 연산값을 기억해야 최적화하고 재활용할 수 있다는 공통점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값을 재활용하기 위해서는 계산한 값을 저장해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 예시를 활용하여 아래와 같은 코드로 작성해 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1752333921601&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function fn(n, memo = []) {
  if (memo[n] !== undefined) return memo[n]
  const res = fn(n-1, memo) + fn(n-2, memo)
  memo[n] = res
  return res
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 값을 저장하게 되면, 시간 복잡도는 O(2^n)에서 O(n) 수준으로 급격하게 빨라진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;579&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KG9bk/btsPe4fFgPA/o7QJG5rAlKKXik8eBTk6uk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KG9bk/btsPe4fFgPA/o7QJG5rAlKKXik8eBTk6uk/img.png&quot; data-alt=&quot;거의 수직으로 올라가는 O(2^n)에서 완만한 O(n)으로..&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KG9bk/btsPe4fFgPA/o7QJG5rAlKKXik8eBTk6uk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKG9bk%2FbtsPe4fFgPA%2Fo7QJG5rAlKKXik8eBTk6uk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;478&quot; height=&quot;338&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;579&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;거의 수직으로 올라가는 O(2^n)에서 완만한 O(n)으로..&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;위에서 설명한 저장 방식은 위에서 아래로 내려오는 Top-Down 방식이었다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;아래로 내려가면서 하나씩 값을 구하고, 위에서 전부 더해주는 방식이 이전 방식이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;하지만 Bottom-Up 방식도 존재한다. 그것이 바로 타뷸레이션이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;동적 프로그래밍은 결국 2가지 방식으로 나뉜다.&lt;br /&gt;- 하향식 (Top-Down)&lt;br /&gt;- 타뷸레이션 (Bottom-Up)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;타불레이션(Tabulation)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;타뷸레이션은 보통 루프와 같이 순환을 통해 작업한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;순환 방식만 있는 것은 아니지만, 공간 복잡도가 더 낮기 때문에 주로 순환 방식을 사용한다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아래 코드를 통해 방식을 확인해 보겠다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1752334708281&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function fn(n) {
  if (n &amp;lt;= 2) return 1
  const nums = [0, 1, 1] // 피보나치에서 0번째 - 0 / 1번째 - 1 / 2번째 - 1
  for (let i = 3; i &amp;lt;= n; i++) {
  	nums[i] = nums[i - 1] + nums[i - 2]
  }
  
  return nums[n]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;하향식과 타뷸레이션 방식의 차이&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하향식은 재귀 방식이기 때문에, 콜스택에 하위 함수들이 대기하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 타뷸레이션은 함수를 한번만 호출하기 때문에 하위 함수들이 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 n이 증가할수록 하향식은 콜스택 초과 에러가 발생할 수 있는 반면에, 타뷸레이션은 에러가 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT/Algorithm</category>
      <category>Dynamic Programming</category>
      <category>tabulation</category>
      <category>동적 프로그래밍</category>
      <author>프티</author>
      <guid isPermaLink="true">https://lifeandit.tistory.com/156</guid>
      <comments>https://lifeandit.tistory.com/156#entry156comment</comments>
      <pubDate>Sun, 13 Jul 2025 00:44:05 +0900</pubDate>
    </item>
    <item>
      <title>벡터 테이블 만들기 삽질과정</title>
      <link>https://lifeandit.tistory.com/155</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;SQL 연습할 겸 한국 주소에 대한 테이블을 만들고 가공하는 중이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL 문법이나 서버 개발이 아직 손에 익지 않아서 고군분투 중..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 겸 검색값에 대한 테이블 조회를 단순히 LIKE 문을 사용하여 구현하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터가 한국 지도뿐이라서 속도가 느리지는 않으나 모든 데이터를 순회하며 비교를 하기 때문에,&lt;br /&gt;로컬 실행이고 전 세계 주소 데이터를 가지고 있었다면 매우 느린 속도를 보일 것이라고 판단하였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;20&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnsJLF/btsM3FgJYOJ/KUyovUEB8aXsXIfgJSIkX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnsJLF/btsM3FgJYOJ/KUyovUEB8aXsXIfgJSIkX1/img.png&quot; data-alt=&quot;ILIKE 검색 속도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnsJLF/btsM3FgJYOJ/KUyovUEB8aXsXIfgJSIkX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnsJLF%2FbtsM3FgJYOJ%2FKUyovUEB8aXsXIfgJSIkX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;567&quot; height=&quot;20&quot; data-origin-width=&quot;567&quot; data-origin-height=&quot;20&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ILIKE 검색 속도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 따라 벡터 테이블을 만들어 유사성 비교로 속도를 높이고자 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저렴한 구현을 추구하기 때문에 무료 벡터 모델을 찾아보았다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;오픈소스로 무료로 사용할 수 있는 Sentence-Transformers 모델 중 하나가 적합합니다.&lt;br /&gt;예를 들어,&amp;nbsp;paraphrase-multilingual-MiniLM-L12-v2&amp;nbsp;모델은 384차원의 임베딩을 생성하며, 50개 이상의 언어를 지원합니다. 이 모델은 다음과 같은 장점이 있습니다.&lt;br /&gt;멀티링구얼 지원: 전세계 다양한 언어의 주소 데이터를 효과적으로 임베딩할 수 있습니다. 효율적 차원: 384차원으로 비교적 낮은 차원이기 때문에, 저장 및 검색 시 리소스 부담이 적습니다. 비용 효율성: 무료로 사용할 수 있으며, 별도의 클라우드 API 호출 비용이 들지 않아 개인 프로젝트에 적합합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #333333; text-align: left; font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;또한 최신 PostgreSQL에는 pgvector가 내장되어 있다.&lt;/span&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 따라 내가 생각한 벡터 데이터 가공 플로우는 아래와 같다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;id, name, address를 조합하여 벡터값 계산 -&amp;gt; &lt;b&gt;paraphrase-multilingual-MiniLM-L12-v2의&amp;nbsp;&amp;nbsp;&lt;/b&gt;384차원으로 벡터값을 저장!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 vectorize 익스텐션 설치를 시도하였는데...&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;pgxn install vectorize 에러 (ssl)&lt;/b&gt;&lt;br /&gt;- python3 install certifi&lt;br /&gt;- sudo SSL_CERT_FILE=$(python3 -m certifi) pgxn install vectorize&lt;br /&gt;해결 -&amp;gt; cargo install cargo-pgxr 에러 (let dependency = cargo_edit::get_latest_dependency not found in `cargo_edit`)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 시도 -&amp;gt; cargo --version &amp;amp;&amp;amp; cargo install cargo-pgrx --version &quot;0.13.1&quot; --locked&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;b&gt;0: $PGRX_HOME does not exist 에러&lt;/b&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- mkdir&amp;nbsp;-p&amp;nbsp;$HOME/.pgrx&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- export PGRX_HOME=$HOME/.pgrx&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- export SSL_CERT_FILE=$(python3 -m certifi)&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- sudo -E pgxn install vectorize&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;b&gt;0: /Users/유저네임/.pgrx/config.toml not found.&amp;nbsp;&amp;nbsp;Have you run `cargo pgrx init` yet? 에러&lt;/b&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 해결 -&amp;gt; cargo pgrx init&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무수히 많은 에러를 거쳐 설치완료.. 하지만 익스텐션 만으로는 인코딩 자체가 안된다는 사실을 뒤늦게 알았다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 에러 해결도 왜 되는지 부끄러운 사실이지만 정확히 모.르.겠.다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설상가상으로 에러 해결을 위해 무지성으로 설치한 패키지들로 인해, PostgreSQL이 brew와 application 버전 2가지로 설치되어 있었고, 이로 인해 서버를 실행할 때마다 실행 실패를 해결하느라 내가 나의 발목을 잡는 상황이 계속해서 발생하였다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 PostgreSQL 전부 삭제하고, brew에 무지성 설치한 패키지들을 제거한 뒤, PostgreSQL 설치부터 다시 진행하였다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익스텐션만으로는 인코딩이 안되기 때문에 벡터 인코딩 방법에 대해 리서치 중에, sentence_transformers라는 파이썬 라이브러리가 있었다. 이것을 통해 벡터로 인코딩해서 벡터를 포함한 주소 테이블을 새로 생성하고자 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 따라 sentence_transformers를 활용한 벡터 인코딩 함수를 만들어서 실행해 보았는데, sentence_transformers 모듈을 찾을 수 없다는 에러가 발생하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위해, 무지성 패키지 설치보다는 문서를 먼저 보았고, PostgreSQL 17 버전과 호환되는 python 버전이 컴퓨터에 설치되어 있는지부터 확인하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 현재 PostgreSQL을 Application 형식으로 사용 중인데, 해당 앱이 설치한 파이썬과 연결되어 있는지 확인도 필요하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1743521671919&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 연결되어 있는 파이썬 정보 확인 함수
CREATE OR REPLACE FUNCTION python_env()
RETURNS text AS $$
import sys
return f&quot;
  Python: {sys.version}\n
  Prefix: {sys.prefix}\n
  Executable: {sys.executable}
&quot;
$$ LANGUAGE plpython3u;

# Python: 3.13.2 (v3.13.2:4f8bb3947cf, Feb  4 2025, 11:51:10) [Clang 15.0.0 (clang-1500.3.9.4)]
# Prefix: /Library/Frameworks/Python.framework/Versions/3.13                                   
# Executable: /Applications/Postgres.app/Contents/Versions/17/bin/postgres

# 파이썬 경로 정보 확인 함수
CREATE OR REPLACE FUNCTION get_sys_path()
RETURNS text AS $$
import sys
return &quot;\n&quot;.join(sys.path)
$$ LANGUAGE plpython3u;

# /usr/local/opt/python@3.13/lib/python3.13/site-packages                        
# /Library/Frameworks/Python.framework/Versions/3.13/lib/python313.zip           
# /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13              
# /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/lib-dynload  
# /Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 연결되어 있는 파이썬에 sentence-transformers와 의존성 라이브러리인 torch를 설치하고자 하였으나, 무한 의존성 루프에 빠지며 죽어도 설치가 안 되는 상황이 되었다.. 리서치를 해보니 아래와 같이 상황 정리되었다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- postgreSQL 17 버전에서의 PL/Python은 파이썬 3.13 이상만을 지원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- sentence_transformers의 의존성 라이브러리는 torch(PyTorch)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 현재 torch의 python에 대한 공식 휠는 3.12까지 지원함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt; 따라서 PostgreSQL 17 버전에서는 sentence_transformers 사용 불가함..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 PostgreSQL 버전을 다운그레이드할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒷목이 뻐근한 순간이다..&lt;/p&gt;</description>
      <category>IT/PostgreSQL</category>
      <category>PostgreSQL</category>
      <category>Python</category>
      <author>프티</author>
      <guid isPermaLink="true">https://lifeandit.tistory.com/155</guid>
      <comments>https://lifeandit.tistory.com/155#entry155comment</comments>
      <pubDate>Wed, 2 Apr 2025 00:40:32 +0900</pubDate>
    </item>
    <item>
      <title>AWS) Web Hosting</title>
      <link>https://lifeandit.tistory.com/153</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Web Hosting?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 웹 사이트를 구성하는 여러 파일을 다양한 디바이스에서 엑세스할 수 있도록 하는 서비스&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;웹사이트에 엑세스하는 과정과 원리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 웹사이트를 본다 === IP 주소를 통해 서버에 페이지를 요청한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 우리는 보통 IP 주소를 입력하여 웹사이트에 접근하지 않는다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 유저가 브라우저 URL 주소를 입력한다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; URL의 2가지 형태&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;도메인&lt;/b&gt; (ex. naver.com)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IP 주소&lt;/b&gt; (ex. 172.0.0.1) &amp;lt;/aside&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거의 대부분의 서비스들은 URL 주소로 IP를 직접 노출시키지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자의 편의성을 위하여, 인식하기 쉬운 naver.com과 같은 도메인을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도메인으로 웹사이트에 접근하는 원리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인은 IP 주소와 매칭되어있다.&lt;/li&gt;
&lt;li&gt;DNS 서버를 통해 해당 도메인과 매칭되는 IP 주소를 찾을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DNS(도메인 네임 시스템)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1459&quot; data-origin-height=&quot;525&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlkPqE/btsMEmioQII/QvbNPdVftQUcyT2prIFkp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlkPqE/btsMEmioQII/QvbNPdVftQUcyT2prIFkp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlkPqE/btsMEmioQII/QvbNPdVftQUcyT2prIFkp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlkPqE%2FbtsMEmioQII%2FQvbNPdVftQUcyT2prIFkp0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1459&quot; height=&quot;525&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1459&quot; data-origin-height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DNS 쿼리가 캐시되어 있지 않다면, IP 탐색은 Root 영역으로부터 시작된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Root 영역에서부터 차례로 내려가며, 최종적으로 해당 도메인과 매칭되는 IP 주소를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾은 IP 주소는 최종적으로 클라이언트에게 반환되며, 반환된 IP 주소로 웹 사이트를 요청한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.gabia.com/?utm_source=google&amp;amp;utm_medium=cpc&amp;amp;utm_term=%EA%B0%80%EB%B9%84%EC%95%84&amp;amp;utm_campaign=%EA%B0%80%EB%B9%84%EC%95%84&quot;&gt;가비아&lt;/a&gt;, &lt;a href=&quot;https://www.godaddy.com/en-sg/offers/godaddy?isc=sem3year&amp;amp;countryview=1&amp;amp;currencyType=KRW&amp;amp;cdtl=c_17604520935.g_143846946448.k_kwd-315249687776.a_731840259076.d_c.ctv_g&amp;amp;bnb=b&amp;amp;gad_source=1&amp;amp;gclid=Cj0KCQiA8fW9BhC8ARIsACwHqYor2fY9P4gxI8f7qjt6hzomC4n7GVXdXXM5rs6J6sa86NSMtg54ux0aAmv3EALw_wcB&quot;&gt;고대디&lt;/a&gt;와 같이 도메인 거래 서비스 업체에서 특정 도메인 이름을 구매할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DNS 설정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DNS는 등록된 레코드 정보를 바탕으로 IP를 탐색한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 참고 - 레코드 종류별 정보&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;A 레코드&lt;/b&gt;&amp;nbsp;- 도메인의 IP 주소를 갖고 있는 레코드.&amp;nbsp;&lt;a href=&quot;https://www.cloudflare.com/learning/dns/dns-records/dns-a-record/&quot;&gt;A 레코드에 대해 자세히 알아보세요.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AAAA 레코드&lt;/b&gt;&amp;nbsp;- 도메인의 IPv6 주소를 포함하는 레코드(IPv4 주소를 나열하는 A 레코드와 반대).&lt;a href=&quot;https://www.cloudflare.com/learning/dns/dns-records/dns-aaaa-record/&quot;&gt;AAAA 레코드에 대해 자세히 알아보세요.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CNAME 레코드&lt;/b&gt;&amp;nbsp;- 하나의 도메인이나 하위 도메인을 다른 도메인으로 전달하며, IP 주소를 제공하지는 않습니다.&amp;nbsp;&lt;a href=&quot;https://www.cloudflare.com/learning/dns/dns-records/dns-cname-record/&quot;&gt;CNAME 레코드에 대해 자세히 알아보세요.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MX 레코드&lt;/b&gt;&amp;nbsp;- 이메일을 이메일 서버로 전송합니다.&amp;nbsp;&lt;a href=&quot;https://www.cloudflare.com/learning/dns/dns-records/dns-mx-record/&quot;&gt;MX 레코드에 대해 자세히 알아보세요.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TXT 레코드&lt;/b&gt;&amp;nbsp;- 관리자가 레코드에 텍스트 메모를 저장할 수 있습니다.이 레코드는 종종 이메일 보안에 사용됩니다.&lt;a href=&quot;https://www.cloudflare.com/learning/dns/dns-records/dns-txt-record/&quot;&gt;TXT 레코드에 대해 자세히 알아보세요.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;NS 레코드&lt;/b&gt;&amp;nbsp;- DNS 항목의 이름 서버를 저장합니다.&amp;nbsp;&lt;a href=&quot;https://www.cloudflare.com/learning/dns/dns-records/dns-ns-record/&quot;&gt;NS 레코드에 대해 자세히 알아보세요.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SOA 레코드&lt;/b&gt;&amp;nbsp;- 도메인에 대한 관리자 정보를 저장합니다.&amp;nbsp;&lt;a href=&quot;https://www.cloudflare.com/learning/dns/dns-records/dns-soa-record/&quot;&gt;SOA 레코드에 대해 자세히 알아보세요.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SRV 레코드&lt;/b&gt;&amp;nbsp;- 특정 서비스에 대한 포트를 지정합니다.&amp;nbsp;&lt;a href=&quot;https://www.cloudflare.com/learning/dns/dns-records/dns-srv-record/&quot;&gt;SRV 레코드에 대해 자세히 알아보세요.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PTR 레코드&lt;/b&gt;&amp;nbsp;- 리버스 조회에서 도메인 이름을 제공합니다.&amp;nbsp;&lt;a href=&quot;https://www.cloudflare.com/learning/dns/dns-records/dns-ptr-record/&quot;&gt;PTR 레코드에 대해 자세히 알아보세요.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NS / A 레코드를 통한 IP 탐색 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 NS 레코드 &amp;rarr; 네임서버 정보 요청&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;도메인에 대한 DNS 요청권한을 가진 &lt;b&gt;네임서버 정보&lt;/b&gt; 획득&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;네임서버 정보 &amp;rarr; &lt;b&gt;A 레코드&lt;/b&gt; 정보 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;A 레코드에 대한 &lt;b&gt;IP 주소&lt;/b&gt; 획득&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CNAME의 역할&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 도메인의 이름과 매칭되는 정보&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CNAME을 통해 페이지를 요청한다면, 연결된 도메인을 먼저 탐색한 후에 NS / A 레코드를 통한 IP 탐색을 시작한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. URL 주소와 연결되어 있는 서버에 페이지를 요청한다.&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &lt;/b&gt;서버의 종류&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자체적으로 관리하는 내부서버&lt;/li&gt;
&lt;li&gt;클라우드를 통해 임대하는 외부서버&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 서버의 장점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버의 물리적인 유지보수를 할 필요가 없음&lt;/li&gt;
&lt;li&gt;대규모 트래픽에 대하여 안정적이고 일관성 있는 대응이 가능함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 서버를 사용하면 적은 리소스로 안정적이고 신뢰성있는 서비스 제공이 가능하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;참고) 위펄슨에서 사용하는 클라우드GCP: Cloud Functions, Authentication&lt;/li&gt;
&lt;li&gt;AWS: 웹 호스팅, S3 버킷&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AWS로 웹 호스팅하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;S3 Bucket 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트에게 웹 사이트를 보여주려면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 클라이언트에게 보낼 웹 사이트 구성 파일을 가지고 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;S3 &amp;gt; 버킷 만들기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WAo2r/btsMEVR3Bj3/5cThKQKKpeBCBT1sKktLa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WAo2r/btsMEVR3Bj3/5cThKQKKpeBCBT1sKktLa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WAo2r/btsMEVR3Bj3/5cThKQKKpeBCBT1sKktLa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWAo2r%2FbtsMEVR3Bj3%2F5cThKQKKpeBCBT1sKktLa1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;437&quot; height=&quot;205&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;205&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 버킷 정보 입력&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;버킷 이름&lt;/b&gt; : CloudFront, Route53에서 생성할 이름과 동일하게 지정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ACL 활성화&lt;/b&gt; 버킷 소유자 : 버킷을 소유한 계정에게 버킷에 있는 모든 객체(파일들)에 대한 모든 권한이 있음 : 버킷 소유자가 아닌 사람이 해당 버킷에 객체 업로드를 하는 경우, 버킷 소유자에게 모든 권한을 이전하는 추가 설정이 필요함 (--acl bucket-owner-full-control) 객체 라이터 : 버킷에 업로드한 객체의 권한은, 해당 객체를 업로드한 사람에게 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;퍼블릭 엑세스 차단 설정&lt;/b&gt; : 버킷의 객체에 접근할 수 있는 엑세스 권한 설정 : CloudFront를 통해서만 S3 버킷에 접근하는 경우, 엑세스 차단을 풀어줌&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정적 웹 사이트 호스팅&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;버킷 &amp;gt; 버킷 이름 &amp;gt; 속성 &amp;gt; 정적 웹 사이트 호스팅 &amp;gt; 편집&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;678&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo5AHv/btsME6MzWuZ/rt3RBtWb5PQ1T2Whti8ml1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo5AHv/btsME6MzWuZ/rt3RBtWb5PQ1T2Whti8ml1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo5AHv/btsME6MzWuZ/rt3RBtWb5PQ1T2Whti8ml1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo5AHv%2FbtsME6MzWuZ%2Frt3RBtWb5PQ1T2Whti8ml1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;706&quot; height=&quot;678&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 웹 사이트 호스팅을 활성화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 지정한 인덱스 문서에 대한 원본 주소를 얻을 수 있음&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CloudFront 배포하기 ( + 기존 캐시된 파일 무효화 )&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; CloudFront &amp;gt; 배포 생성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원본 Origin Domain : S3 Bucket의 주소&lt;/li&gt;
&lt;li&gt;원본 엑세스 Legacy access Identities : 원본 엑세스 ID를 사용하여 Bucket에 접근 : 새 OAI 생성으로 ID 등록&lt;/li&gt;
&lt;li&gt;기본 캐시 동작 뷰어 &amp;gt; 프로토콜 정책 &amp;gt; Redirect HTTP to HTTPS : weperson에서는 사용자 편의성을 위해 리다이렉트 옵션 사용중 뷰어 &amp;gt; 허용된 HTTP 방법 &amp;gt; GET, HEAD : weperson은 SPA 서비스이기 때문에, 최소 허용 옵션 사용중&lt;/li&gt;
&lt;li&gt;설정 &lt;b&gt;Custom SSL certificate&amp;nbsp;- optional&lt;/b&gt; : HTTPS 보안 세팅을 위한 SSL 파일 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;생성 후&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_4.png&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;293&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Koix6/btsMETzXqa4/Bdf0HcSWXHKc1qGQXyKRVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Koix6/btsMETzXqa4/Bdf0HcSWXHKc1qGQXyKRVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Koix6/btsMETzXqa4/Bdf0HcSWXHKc1qGQXyKRVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKoix6%2FbtsMETzXqa4%2FBdf0HcSWXHKc1qGQXyKRVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;495&quot; height=&quot;293&quot; data-filename=&quot;edited_4.png&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;293&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;aws cli를 통해 빌드한 파일을 업로드 / 캐시 무효화 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// 빌드
yarn build

// 기존 dist/spa 제거 후 새롭게 빌드된 dist/spa 파일 업로드
aws s3 sync --acl public-read --delete dist/spa s3://서브도메인.com

// 존재하는 CDN 캐시파일 무효화
aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_PROD_CLOUDFRONT_ID }} --paths &quot;/*&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐시 무효화 직접 해보기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CloudFront &amp;gt; 배포 &amp;gt; 배포ID &amp;gt; 무효화 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경로 패턴을 통해 하위 파일들을 타겟팅하여 무효화 생성 &amp;rarr; 캐시 무효화&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;389&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6TBar/btsMEZUlwWZ/tJ0GYmQ5HkCRjddL5dY3p1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6TBar/btsMEZUlwWZ/tJ0GYmQ5HkCRjddL5dY3p1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6TBar/btsMEZUlwWZ/tJ0GYmQ5HkCRjddL5dY3p1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6TBar%2FbtsMEZUlwWZ%2FtJ0GYmQ5HkCRjddL5dY3p1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;664&quot; height=&quot;389&quot; data-filename=&quot;5.png&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;389&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Route53 연결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Route53 &amp;gt; 호스팅 영역 &amp;gt; 레코드 생성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레코드 이름 : 유저가 입력할 도메인 이름 레코드 유형&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CloudFront 연결을 할 때 &amp;rarr; CloudFront의 도메인 이름 또는 IP 주소&lt;/li&gt;
&lt;li&gt;정적 웹 호스팅을 할 때 &amp;rarr; S3 Bucket의 인덱스 문서의 주소&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>IT/Project</category>
      <author>프티</author>
      <guid isPermaLink="true">https://lifeandit.tistory.com/153</guid>
      <comments>https://lifeandit.tistory.com/153#entry153comment</comments>
      <pubDate>Sun, 9 Mar 2025 00:49:49 +0900</pubDate>
    </item>
    <item>
      <title>Expo) Sentry 소스맵 업로드</title>
      <link>https://lifeandit.tistory.com/152</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Sentry의 역할&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빌드 파일은 기존 코드를 난독화하고, 압축하기 때문에 정확한 에러 지점을 파악하기 어렵다.&lt;/li&gt;
&lt;li&gt;Sentry에 소스맵을 업로드하면, 에러가 발생한 코드에 대한 원본 코드 위치를 소스맵을 통해 알 수 있다.&lt;/li&gt;
&lt;li&gt;또한 에러 발생 즉시 리포트가 이루어지기 때문에 즉각적인 대응이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 소스맵 업로드&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 버전별로 소스맵을 Sentry에 업로드할 수 있다.&lt;/li&gt;
&lt;li&gt;다만, 아래 2가지 상황별로 소스맵 업로드 방식이 다르게 존재한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1 EAS Cloud 빌드&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동으로 Sentry에 소스맵이 업로드 된다.&lt;/li&gt;
&lt;li&gt;별도의 소스맵 업로드 처리가 필요하지 않다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2 EAS Update&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EAS Update 명령 실행 시 소스맵이 생성된다. (위치: &lt;b&gt;root/dist/bundles&lt;/b&gt;)&lt;/li&gt;
&lt;li&gt;bundle 폴더에 생성된 소스맵 파일은 &lt;b&gt;Android / IOS 각각 .hbc와 .map 파일로 구성된다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 배포 절차&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 소스맵 수동 업로드가 필요한 EAS Update에 대한 배포 방법이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1. EAS Update 실행&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 아래 명령어를 실행한다.&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;npx eas update
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 결과로 Group ID, Android ID, iOS ID 총 3개의 업데이트 ID가 출력된다.&lt;/li&gt;
&lt;li&gt;Group ID는 iOS와 Android를 일괄 업데이트하는 데 사용할 수 없다. 따라서 각 플랫폼별 업데이트 ID를 각각 사용해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;root/dist/bundles&lt;/b&gt; 경로에 생성된 파일 이름을 통해 각 OS 별로 다른 ID를 가진 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2. Sentry CLI를 이용한 소스맵 업로드&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2.1. 소스맵 업로드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업데이트 ID를 활용해 소스맵을 업로드한다. 명령어 형식은 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;npx sentry-cli releases files &amp;lt;앱_패키지_name&amp;gt;@&amp;lt;패키지_version&amp;gt;+&amp;lt;버전_code&amp;gt; \\
    upload-sourcemaps --dist &amp;lt;업데이트_ID&amp;gt; --rewrite \\
    &amp;lt;번들_파일_경로&amp;gt; &amp;lt;소스맵_파일_경로&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;플랫폼 별 위 변수에 들어갈 값 정리&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IOS Android&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;앱_패키지_name&lt;/td&gt;
&lt;td&gt;&amp;lt;패키지.이름&amp;gt;&lt;/td&gt;
&lt;td&gt;&amp;lt;패키지.이름&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;패키지_version&lt;/td&gt;
&lt;td&gt;(package.json).version&lt;/td&gt;
&lt;td&gt;(package.json).version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;버전_code&lt;/td&gt;
&lt;td&gt;App Store 버전 코드&lt;/td&gt;
&lt;td&gt;Play Store 버전 코드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;업데이트_ID&lt;/td&gt;
&lt;td&gt;eas update 시 IOS ID&lt;/td&gt;
&lt;td&gt;eas update 시 Android ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;번들_파일_경로&lt;/td&gt;
&lt;td&gt;&amp;hellip;/main.jsbundle&lt;/td&gt;
&lt;td&gt;&amp;hellip;/index.android.bundle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;소스맵_파일_경로&lt;/td&gt;
&lt;td&gt;&amp;hellip;/ios-업데이트_ID.map&lt;/td&gt;
&lt;td&gt;&amp;hellip;/android-업데이트_ID.map&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Android&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;npx sentry-cli releases files &amp;lt;패키지.이름&amp;gt;@1.0.0+100 \\
    upload-sourcemaps --dist &amp;lt;android_update_id&amp;gt; --rewrite \\
    dist/bundles/index.android.bundle dist/bundles/android-&amp;lt;android_update_id&amp;gt;.map
    
?) 번들파일 생성시 index.android.bundle의 실제 이름: &amp;lt;android_update_id&amp;gt;.hbc
?) **&amp;lt;android_update_id&amp;gt;.hbc -&amp;gt; index.android.bundle로 이름 변경**&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;iOS&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;npx sentry-cli releases files &amp;lt;패키지.이름&amp;gt;@1.0.0+100 \\
    upload-sourcemaps --dist &amp;lt;ios_update_id&amp;gt; --rewrite \\
    dist/bundles/main.jsbundle dist/bundles/ios-&amp;lt;ios_update_id&amp;gt;.map
    
?) 번들파일 생성시 main.jsbundle의 실제 이름: &amp;lt;ios_update_id&amp;gt;.hbc
?) **&amp;lt;ios_update_id&amp;gt;.hbc -&amp;gt; main.jsbundle로 이름 변경**&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Sentry에서는 번들파일인 index.android.bundle과 main.jsbundle을 &lt;b&gt;&amp;lt;update_id&amp;gt;.hbc 형식&lt;/b&gt;으로 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2.2. Sentry 릴리즈 최종화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스맵 업로드가 완료되면, 릴리즈를 최종화한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;npx sentry-cli releases finalize &quot;&amp;lt;패키지.이름&amp;gt;@&amp;lt;패키지_version&amp;gt;+&amp;lt;버전_code&amp;gt;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용 예시&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;npx sentry-cli releases finalize &quot;&amp;lt;패키지.이름&amp;gt;@2.0.5+62&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2.3. 배포 등록&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종화된 릴리즈를 배포 환경(dev 또는 prod)에 등록한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;npx sentry-cli releases deploys new -r &quot;&amp;lt;패키지.이름&amp;gt;@&amp;lt;패키지_version&amp;gt;+&amp;lt;버전_code&amp;gt;&quot; -e &amp;lt;sentry_등록한_환경변수명&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용예시&lt;/p&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// sentry 환경변수로 prod가 있다고 가정
npx sentry-cli releases deploys new -r &quot;&amp;lt;패키지.이름&amp;gt;@2.0.5+62&quot; -e prod

// sentry 환경변수로 dev가 있다고 가정
npx sentry-cli releases deploys new -r &quot;&amp;lt;패키지.이름&amp;gt;@2.0.5+62&quot; -e dev&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 토큰 및 환경변수&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;환경변수는 Sentry에서 발급한 토큰과 설정한 프로젝트, organization이 필요하다.&lt;/li&gt;
&lt;li&gt;EAS Update 시에는 로컬에서 작업이 수행되기 때문에, 로컬 환경변수에 export한다.&lt;/li&gt;
&lt;li&gt;EAS Build 시에는 EAS 클라우드에서 빌드되기 때문에, EAS 환경변수에 등록한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;export SENTRY_AUTH_TOKEN=&amp;lt;SENTRY_AUTH_TOKEN&amp;gt;
export SENTRY_PROJECT=&amp;lt;SENTRY_PROJECT&amp;gt;
export SENTRY_ORG=&amp;lt;SENTRY_ORG&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT/React-native</category>
      <category>EAS</category>
      <category>Expo</category>
      <category>react-native</category>
      <category>SENTRY</category>
      <author>프티</author>
      <guid isPermaLink="true">https://lifeandit.tistory.com/152</guid>
      <comments>https://lifeandit.tistory.com/152#entry152comment</comments>
      <pubDate>Sun, 9 Mar 2025 00:19:56 +0900</pubDate>
    </item>
    <item>
      <title>Expo) 카카오 로그인 구현하기 - 라이브러리 설치 및 빌드</title>
      <link>https://lifeandit.tistory.com/151</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;expo에서 카카오 로그인을 구현하고자 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 구현 방식은 웹뷰/앱 내부로 크게 두 가지로 구현이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹뷰로 로그인을 구현하게 되면 카카오 앱으로 넘어가기 때문에 웹뷰가 아닌 앱 내부에서 로그인을 처리하고 싶었다. (&lt;a href=&quot;https://velog.io/@uffetkk/expo%EC%97%90%EC%84%9C-%EC%9B%B9%EB%B7%B0%EC%97%86%EC%9D%B4-%EC%86%8C%EC%85%9C%EB%A1%9C%EA%B7%B8%EC%9D%B8%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고링크&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서치한 결과&amp;nbsp;&lt;a href=&quot;https://github.com/crossplatformkorea/react-native-kakao-login&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@react-native-seoul/kakao-login&lt;/a&gt;을 사용하면 expo에서도 앱 내부에서 카카오 로그인이 구현 가능하다는 것을 알게 되었다.&lt;/p&gt;
&lt;pre id=&quot;code_1713287632527&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn add @react-native-seoul/kakao-login&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 로컬 빌드를 하였으나 아래의 에러를 마주하게 되었다.&lt;/p&gt;
&lt;pre id=&quot;code_1713287827004&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;* What went wrong:
Could not determine the dependencies of task ':app:processDebugResources'.
&amp;gt; Could not resolve all task dependencies for configuration ':app:debugRuntimeClasspath'.
   &amp;gt; Could not find com.kakao.sdk:v2-user:2.11.2.
     Searched in the following locations:
       - https://oss.sonatype.org/content/repositories/snapshots/com/kakao/sdk/v2-user/2.11.2/v2-user-2.11.2.pom
       - https://repo.maven.apache.org/maven2/com/kakao/sdk/v2-user/2.11.2/v2-user-2.11.2.pom
       - file:/Users/user/projects/myapp/node_modules/jsc-android/dist/com/kakao/sdk/v2-user/2.11.2/v2-user-2.11.2.pom
       - https://dl.google.com/dl/android/maven2/com/kakao/sdk/v2-user/2.11.2/v2-user-2.11.2.pom
       - https://www.jitpack.io/com/kakao/sdk/v2-user/2.11.2/v2-user-2.11.2.pom
       - file:/Users/user/projects/myapp/node_modules/react-native/android/com/kakao/sdk/v2-user/2.11.2/v2-user-2.11.2.pom
     Required by:
         project :app &amp;gt; project :react-native-seoul_kakao-login
   &amp;gt; Could not find com.kakao.sdk:v2-talk:2.11.2.
     Searched in the following locations:
       - https://oss.sonatype.org/content/repositories/snapshots/com/kakao/sdk/v2-talk/2.11.2/v2-talk-2.11.2.pom
       - https://repo.maven.apache.org/maven2/com/kakao/sdk/v2-talk/2.11.2/v2-talk-2.11.2.pom
       - file:/Users/user/projects/myapp/node_modules/jsc-android/dist/com/kakao/sdk/v2-talk/2.11.2/v2-talk-2.11.2.pom
       - https://dl.google.com/dl/android/maven2/com/kakao/sdk/v2-talk/2.11.2/v2-talk-2.11.2.pom
       - https://www.jitpack.io/com/kakao/sdk/v2-talk/2.11.2/v2-talk-2.11.2.pom
       - file:/Users/user/projects/myapp/node_modules/react-native/android/com/kakao/sdk/v2-talk/2.11.2/v2-talk-2.11.2.pom
     Required by:
         project :app &amp;gt; project :react-native-seoul_kakao-login
   &amp;gt; Could not find com.kakao.sdk:v2-story:2.11.2.
     Searched in the following locations:
       - https://oss.sonatype.org/content/repositories/snapshots/com/kakao/sdk/v2-story/2.11.2/v2-story-2.11.2.pom
       - https://repo.maven.apache.org/maven2/com/kakao/sdk/v2-story/2.11.2/v2-story-2.11.2.pom
       - file:/Users/user/projects/myapp/node_modules/jsc-android/dist/com/kakao/sdk/v2-story/2.11.2/v2-story-2.11.2.pom
       - https://dl.google.com/dl/android/maven2/com/kakao/sdk/v2-story/2.11.2/v2-story-2.11.2.pom
       - https://www.jitpack.io/com/kakao/sdk/v2-story/2.11.2/v2-story-2.11.2.pom
       - file:/Users/user/projects/myapp/node_modules/react-native/android/com/kakao/sdk/v2-story/2.11.2/v2-story-2.11.2.pom
     Required by:
         project :app &amp;gt; project :react-native-seoul_kakao-login
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 라이브러리 문서에 나온대로 아래 설정을 해주고 리서치를 진행했으나, 빌드시 kakao android sdk를 찾지 못하는 원인에 대한 해결책을 찾을 수 없었다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 해당 이슈에 대한 원인을 친절히 알려주시는 코멘트를 발견하였다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;625&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1XE46/btsGFhHfbdR/jk8C0odlfWK37d1EiiHhLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1XE46/btsGFhHfbdR/jk8C0odlfWK37d1EiiHhLK/img.png&quot; data-alt=&quot;따봉 100만개 주고싶다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1XE46/btsGFhHfbdR/jk8C0odlfWK37d1EiiHhLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1XE46%2FbtsGFhHfbdR%2Fjk8C0odlfWK37d1EiiHhLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;932&quot; height=&quot;625&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;625&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;따봉 100만개 주고싶다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Maven은 안드로이드의 라이브러리들을 관리해주는 도구인데, kakao sdk를 찾지 못하니 app.json / app.config.ts에서 해당 라이브러리에 대한 레포를 추가해줌으로서 해결할 수 있다는 가이드였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 따라 아래와 같이 설정해주었다.&lt;/p&gt;
&lt;pre id=&quot;code_1713288225463&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins: [
    [
      'expo-build-properties',
      {
        android: {
          &quot;extraMavenRepos&quot;: [&quot;https://devrepo.kakao.com/nexus/content/groups/public/&quot;]
        }
      }
    ],
    [
      '@react-native-seoul/kakao-login', {
        kakaoAppKey: '카카오 앱 키',
      }
    ]
  ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만.. 또 다시 에러를 마주하고 말았다.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;text-align: center; caret-color: transparent; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/6D8Et/btsGIgGD0WB/P6YstVi4fPfBosabkbqbB1/img.png&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;140&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;expo에 세팅된 kotlin gradle version은 1.5.10인데, 플러그인 호환 버전이 최소 1.5.20 이상인 것을 알게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, &lt;a style=&quot;background-color: #e6f5ff; color: #0070d1; text-align: start;&quot; href=&quot;https://github.com/crossplatformkorea/react-native-kakao-login&quot;&gt;@react-native-seoul/kakao-login&lt;/a&gt; 플러그인 세팅에서 코틀린 버전을 1.5.20으로 설정하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1713288432149&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugins: [
    [
      'expo-build-properties',
      {
        android: {
          &quot;extraMavenRepos&quot;: [&quot;https://devrepo.kakao.com/nexus/content/groups/public/&quot;]
        }
      }
    ],
    [
      '@react-native-seoul/kakao-login', {
        kakaoAppKey: '카카오 앱 키',
        kotlinVersion: '1.5.20'
      }
    ]
  ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드디어 빌드 성공.. 역시 지식 공유의 힘은 크다 &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별거 없지만 해당 이슈에 대한 PR에 코틀린 버전 명시가 제거되어 있길래 먼지톨보다도 작은 제안을 하며 이번 이슈를 마무리하였다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 제안에 피드백이 오면 추가 공유 예정!&lt;/p&gt;</description>
      <category>IT/React-native</category>
      <category>Expo</category>
      <category>react-native</category>
      <category>리액트 네이티브</category>
      <category>엑스포</category>
      <category>카카오 로그인</category>
      <author>프티</author>
      <guid isPermaLink="true">https://lifeandit.tistory.com/151</guid>
      <comments>https://lifeandit.tistory.com/151#entry151comment</comments>
      <pubDate>Wed, 17 Apr 2024 02:31:25 +0900</pubDate>
    </item>
    <item>
      <title>eslint, husky, lint-staged, commitlint 설정</title>
      <link>https://lifeandit.tistory.com/150</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 리액트 네이티브 프로젝트를 시작하면서 eslint, husky, lint-staged, commitlint를 적용해보았다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;eslint&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 할 때마다 설정하는건데 항상 찾아보는 것 같다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 타입스크립트를 사용하기 때문에 타입스크립트 관련 eslint 패키지도 함께 설치해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1704984377806&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn add -D eslint eslint-plugin-react-hooks eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin @typescript-eslint/parser&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;eslint를 설정하기 위해 .eslintrc.js를 구성한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;.eslintrc.js에 모든 설정을 몰아넣게되면 관리하기가 어려우므로, 먼저 주제에 따라 rule을 분리하고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;// rules 디렉토리 구조&lt;br /&gt;eslint-config/index.js&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /rules/es6.js&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /import.js&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /react.js&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /typescript.js&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rules의 디렉토리 구조는 위와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1704984723719&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// eslint-config/rules/typescript.js
module.exports = {
  extends: [
    'plugin:@typescript-eslint/eslint-recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:@typescript-eslint/recommended-requiring-type-checking'
  ],
  rules: {
    // typescript 룰 적용
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위와같이 각 rule에 맞는 규칙과 세부 설정을 해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1704985007223&quot; class=&quot;vim&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// index.js
module.exports = {
  extends: ['./rules/es6', './rules/import', './rules/react', './rules/typescript'].map(require.resolve),
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 구성된 rules 파일을 index에 extends한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1704985359402&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;// .eslintrc.js
module.exports = {
  env: {
    es6: true,
    node: true
  },
  extends: ['./eslint-config', 'eslint:recommended'],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: ['./tsconfig.json']
  },
  plugins: ['@typescript-eslint'],
  settings: {
    react: {
      version: 'detect'
    },
    'import/ignore': ['react-native']
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;최종으로 .eslintrc.js에서 eslint-config를 extends 시켜주면 깔끔하게 관리할 수 있어 유지보수에 용이하다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;husky 설정&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;git hook이란? &lt;/b&gt;&lt;br /&gt;git 이벤트가 있을때 특정 스크립트를 실행하게 하는 것 실수로 origin에 push되어 배포가 되는 일을 방지할 수 있다. &lt;br /&gt;&lt;b&gt;&lt;br /&gt;husky란?&lt;/b&gt;&lt;br /&gt;git hook을 쉽게 사용할 수 있도록 도와주는 라이브러리&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;1248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2TBYB/btsDkAwvc9t/2oNVulAAh57E54f8RIoSuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2TBYB/btsDkAwvc9t/2oNVulAAh57E54f8RIoSuK/img.png&quot; data-alt=&quot;git hook의 분류별 실행 단계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2TBYB/btsDkAwvc9t/2oNVulAAh57E54f8RIoSuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2TBYB%2FbtsDkAwvc9t%2F2oNVulAAh57E54f8RIoSuK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1272&quot; height=&quot;1248&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;1248&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;git hook의 분류별 실행 단계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1704979707130&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npx husky-init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커밋시 린트 검사를 하기위해 아래와 같이 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1704979723643&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 터미널
npx husky add .husky/pre-commit 'yarn lint-staged'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;lint-staged 설정&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git의 stage 상태의 파일들을 대상으로 특정 명령어를 실행할 수 있도록 해주는 툴이다.&lt;/p&gt;
&lt;pre id=&quot;code_1704979762440&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn -D lint-staged&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1704979776781&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// package.json
...
&quot;script&quot;: {
	...
	&quot;lint-staged&quot;: &quot;lint-staged&quot;,
	&quot;type-lint&quot;: &quot;tsc --pretty --noEmit &amp;amp;&amp;amp; eslint . --ext .js,.jsx,.ts,.tsx&quot;
},
&quot;lint-staged&quot;: {
	&quot;**/*.{js,jsx,ts,tsx}&quot;: [&quot;yarn type-lint&quot;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 만들어진 type, lint 검사 스크립트를 활용하여 lint-staged시에 해당 스크립트를 실행할 수 있도록 한다. 특정 파일들을 대상으로하기 위해, &quot;**/*.{js,jsx,ts,tsx}&quot;와 같은 경로 및 확장자를 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1704979794490&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// .husky/pre-commit

#!/usr/bin/env sh
. &quot;$(dirname -- &quot;$0&quot;)/_/husky.sh&quot;

yarn lint-staged&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;husky의 커밋 워크플로 훅의 하나인 &lt;span style=&quot;color: #eb5757;&quot; data-token-index=&quot;1&quot;&gt;pre-commit&lt;/span&gt; 에서 stage 파일들이 커밋되기 전에 lint-staged 스크립트가 실행될 수 있도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;commitlint 설정&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1704979963368&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yarn add -D @commitlint/cli&amp;nbsp;@commitlint/config-conventional&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;commitlint-cli(&lt;span data-token-index=&quot;1&quot;&gt;@commitlint/cli&lt;/span&gt;)와 컨벤션 기반의 규칙을 제공하는 commitlint 플러그인(&lt;span data-token-index=&quot;3&quot;&gt;@commitlint/config-conventional&lt;/span&gt;)을 설치한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1704979997426&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// .husky/commit-msg
#!/usr/bin/env sh
. &quot;$(dirname -- &quot;$0&quot;)/_/husky.sh&quot;

npx --no-install commitlint --edit $1&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;git commit -m &amp;ldquo;XXX: message&amp;hellip;&amp;rdquo; 사용자 입력&lt;/li&gt;
&lt;li&gt;husky &amp;rarr; commit-msg 파일 실행( npx --no-install commitlint --edit $1 )&lt;/li&gt;
&lt;li&gt;컨벤션 위반시 0이 아닌 에러코드와 위반된 규칙 메세지 반환&lt;/li&gt;
&lt;li&gt;터미널에 에러 코드와 메세지 출력&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EZVym/btsDmqGOF8y/kDoeU2kaGkk35xufFb30DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EZVym/btsDmqGOF8y/kDoeU2kaGkk35xufFb30DK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EZVym/btsDmqGOF8y/kDoeU2kaGkk35xufFb30DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEZVym%2FbtsDmqGOF8y%2FkDoeU2kaGkk35xufFb30DK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;986&quot; height=&quot;246&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;루트에 &lt;span style=&quot;color: #ef5369;&quot;&gt;commitlint.config.js&lt;/span&gt; 를 추가하여 구성하면 커스텀 커밋 컨벤션을 구성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커스텀 컨벤션을 구성하지 않는 경우, 기본적으로 허용하는 컨벤션이 적용된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;80&quot; data-origin-height=&quot;279&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byF6PY/btsDkHJbrEe/62rEORnT5Iyz2KAQBgRX5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byF6PY/btsDkHJbrEe/62rEORnT5Iyz2KAQBgRX5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byF6PY/btsDkHJbrEe/62rEORnT5Iyz2KAQBgRX5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyF6PY%2FbtsDkHJbrEe%2F62rEORnT5Iyz2KAQBgRX5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;124&quot; height=&quot;432&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;80&quot; data-origin-height=&quot;279&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;type과 body은 : 로 구성된다.&lt;/li&gt;
&lt;li&gt;body의 맨앞에는 ``빈칸으로 구성한다.&lt;/li&gt;
&lt;li&gt;등등..&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://deku.posstree.com/en/react-native/eslint-prettier-husky-lint-staged/&quot;&gt;https://deku.posstree.com/en/react-native/eslint-prettier-husky-lint-staged/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://deku.posstree.com/ko/react-native/eslint-prettier-husky-lint-staged/#google_vignette&quot;&gt;https://deku.posstree.com/ko/react-native/eslint-prettier-husky-lint-staged/#google_vignette&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@kay_/Husky#3-sample-pre-commit-hook-추가하기&quot;&gt;https://velog.io/@kay_/Husky#3-sample-pre-commit-hook-추가하기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/conventional-changelog/commitlint/blob/master/docs/reference-rules.md&quot;&gt;https://github.com/conventional-changelog/commitlint/blob/master/docs/reference-rules.md&lt;/a&gt;&lt;/p&gt;</description>
      <category>IT/React-native</category>
      <category>commitlint</category>
      <category>husky</category>
      <category>lint-staged</category>
      <author>프티</author>
      <guid isPermaLink="true">https://lifeandit.tistory.com/150</guid>
      <comments>https://lifeandit.tistory.com/150#entry150comment</comments>
      <pubDate>Thu, 11 Jan 2024 22:35:47 +0900</pubDate>
    </item>
    <item>
      <title>루트 컴포넌트 렌더링 방식</title>
      <link>https://lifeandit.tistory.com/147</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Vue는 React와 마찬가지로 하나의 div 안에서 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 해당 div에 연결하는 방식은 조금 다르지만 비슷한 원리를 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) index.js(React) &amp;rarr; main.js(Vue)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 부가 기능 없이 연결했을 때&lt;/p&gt;
&lt;pre id=&quot;code_1660868746544&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// React
ReactDOM.render(
	&amp;lt;App /&amp;gt;,
	document.getElementById(&quot;root&quot;),
);

// Vue
createApp(App).mount(&quot;#root&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) store 또는 router 연결했을 때&lt;/p&gt;
&lt;pre id=&quot;code_1660868821608&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// React
ReactDOM.render(
	&amp;lt;Provider store={store}&amp;gt;
		&amp;lt;Router&amp;gt;
			&amp;lt;App /&amp;gt;
		&amp;lt;/Router&amp;gt;
	&amp;lt;/Provider&amp;gt;,

	document.getElementById(&quot;root&quot;),
);

// Vue
createApp(App).use(store).use(router).mount(&quot;#root&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React는 render 메서드에 컴포넌트와 이를 바인딩할 div를 인자로 넘겨준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 반해 Vue는 createApp 메서드를 사용하고, 체이닝을 통해 다양한 메서드를 연결시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면 알 수 있듯이, React는 컴포넌트로 루트 컴포넌트를 감싸고 있는 방식이지만 Vue는 메서드 체이닝을 사용하기 때문에 다른 형태를 가지고 있다.&lt;/p&gt;</description>
      <category>IT/Vue</category>
      <category>REACT</category>
      <category>vue</category>
      <category>렌더링</category>
      <category>루트 컴포넌트</category>
      <category>리액트</category>
      <category>뷰</category>
      <author>프티</author>
      <guid isPermaLink="true">https://lifeandit.tistory.com/147</guid>
      <comments>https://lifeandit.tistory.com/147#entry147comment</comments>
      <pubDate>Fri, 19 Aug 2022 09:27:42 +0900</pubDate>
    </item>
    <item>
      <title>Getter와 Setter</title>
      <link>https://lifeandit.tistory.com/146</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 프로퍼티에는 두 종류로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 데이터 프로퍼티&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 접근자 프로퍼티&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 지금까지 사용했던 프로퍼티는 데이터 프로퍼티이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근자 프로퍼티는 본질이 함수이며, 값을 획득(getter)하고 설정(setter)하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 리터럴 안에서 getter와 setter는 각각 get과 set으로 나타낼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656553103787&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let user = {
  name: &quot;John&quot;,
  surname: &quot;Smith&quot;,

  get fullName() {
    return `${this.name} ${this.surname}`;
  }
};

alert(user.fullName); // John Smith&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 보면 get 프로퍼티를 일반 프로퍼티처럼 호출하여 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 뒤의 로직은 getter 메서드가 처리하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656553216870&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let user = {
  name: &quot;John&quot;,
  surname: &quot;Smith&quot;,

  get fullName() {
    return `${this.name} ${this.surname}`;
  },

  set fullName(value) {
    [this.name, this.surname] = value.split(&quot; &quot;);
  }
};

// 주어진 값을 사용해 set fullName이 실행됩니다.
user.fullName = &quot;Alice Cooper&quot;;

alert(user.name); // Alice
alert(user.surname); // Cooper&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 setter 메서드를 구현하면 해당 프로퍼티에 새로운 값을 할당할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 getter와 setter 메서드를 구현하면 객체엔 fullName이라는 가상의 프로퍼티가 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상의 프로퍼티는 읽고 쓸 수 있지만 실제로 존재하지는 않는다.&lt;/p&gt;</description>
      <category>IT/JS</category>
      <category>getter</category>
      <category>setter</category>
      <author>프티</author>
      <guid isPermaLink="true">https://lifeandit.tistory.com/146</guid>
      <comments>https://lifeandit.tistory.com/146#entry146comment</comments>
      <pubDate>Fri, 1 Jul 2022 16:25:15 +0900</pubDate>
    </item>
    <item>
      <title>Javascript는 왜 싱글 스레드일까?</title>
      <link>https://lifeandit.tistory.com/145</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 싱글 스레드라는 것은  개념을 외우듯이 알고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 자바스크립트 언어를 만든 브렌던 아이크 선생님은 왜 싱글 스레드를 선택했을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 그전에 프로세스와 스레드의 개념을 알고 가야 할 것 같다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로세스와 스레드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스는 운영 체제로부터 할당받은 작업의 단위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스 내부에는 Code, Data, Stack, Heap이라는&amp;nbsp; 네 가지 리소스가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램을 실행했을 때 보조 기억장치(ex. 하드 디스크)에서 프로그램의 코드를 컴파일하여 주 기억장치인 메모리에 옮겨가면, 그것을 프로세스라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;싱글스레드 프로세스 리소스.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;711&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNiKDf/btrDEA4aTMp/w2V41RNKkP0erZCoxxKmXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNiKDf/btrDEA4aTMp/w2V41RNKkP0erZCoxxKmXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNiKDf/btrDEA4aTMp/w2V41RNKkP0erZCoxxKmXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNiKDf%2FbtrDEA4aTMp%2Fw2V41RNKkP0erZCoxxKmXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;711&quot; data-filename=&quot;싱글스레드 프로세스 리소스.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;711&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드는 프로세스가 할당받은 자원을 사용하는 작업의 흐름 단위이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드는 Stack을 가지며 나머지 Code, Data, Heap 리소스를 사용하며 작업을 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 프로세스 내부에 스레드가 하나라면&amp;nbsp;&lt;b&gt;싱글 스레드&lt;/b&gt;, 여러 개라면&amp;nbsp;&lt;b&gt;멀티 스레드&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티 스레드는 여러 스레드가 리소스를 공유하며 작업을 처리하기 때문에, 여러 작업을 동시에 처리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에 처리한다고 말했지만, 스레드를 돌아가며 순차적으로 처리하는 방식이 매우 빠르기 때문에 거의 동시에 처리되는 것처럼 느껴진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 스레드에서 또 다른 스레드로 넘어가는 과정을 &lt;b&gt;스레드&lt;/b&gt;&amp;nbsp;&lt;b&gt;컨텍스트 스위칭&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드 컨텍스트 스위칭은 스레드 하나의 작업을 진행하기 위해 &lt;b&gt;해당 스레드의 Context를 읽어오고, 다시 다른 스레드로 작업을 변경할 때, 이전 스레드의 Context를 저장하고 작업을 진행&lt;/b&gt;할 스레드의 Context를 읽어오는 작업을 말한다.&lt;br /&gt;여기서 Context는 정보를 나타내는데 레지스터, 커널 스택, 사용자 스택 등의 여러 정보를 말하지만, 이에 대해서는 아직 잘 모르기에 추후에 다루도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 스레드 컨텍스트 스위칭의 시간이 오래 걸리는 경우, 프로그램의 성능 저하가 일어나 프로그램이 멈추는 사용자 경험을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 멀티 스레드는 &lt;b&gt;동시성에 대응&lt;/b&gt;해야 한다는 어려움이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시성이란, 싱글 코어에서 멀티 스레드를 동작시켜 동시에 실행되는 것 같이 보이는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시성은 병렬성과 비교해서 보아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시성은 싱글 코어에서 멀티 스레드 환경을 구성하여 스레드 컨텍스트 스위칭을 통해 여러 개의 스레드가 번갈아가면서 실행되는 성질이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 병렬성은&amp;nbsp;&lt;b&gt;멀티 코어&lt;/b&gt;에서 멀티 스레드를 동작시키는 방식이다. 따라서 실제로 동시에 여러 작업이 처리된다고 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;싱글스레드 동시성.png&quot; data-origin-width=&quot;1203&quot; data-origin-height=&quot;709&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf58eb/btrDHGvdnm5/Zk0Bk8MZFsBS2Y6HK2bWo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf58eb/btrDHGvdnm5/Zk0Bk8MZFsBS2Y6HK2bWo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf58eb/btrDHGvdnm5/Zk0Bk8MZFsBS2Y6HK2bWo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf58eb%2FbtrDHGvdnm5%2FZk0Bk8MZFsBS2Y6HK2bWo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1203&quot; height=&quot;709&quot; data-filename=&quot;싱글스레드 동시성.png&quot; data-origin-width=&quot;1203&quot; data-origin-height=&quot;709&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 이야기했듯이, 멀티 스레드는 여러 개의 스레드가 프로세스가 할당받은 리소스들을 공유하며 작업을 처리하기 때문에, 같은 자원을 두고 &lt;b&gt;교착상태(deadlock)&lt;/b&gt;가 발생할 수 있다. 따라서 교착상태를 해결하기 위해 스레드 안정성(thread safe)을 가지며 코드를 작성해야 한다. 스레드 안정성을 확보하기 위한 방법들은 추후에 자세히 다루도록 하고, 방법들만 간단하게 나열해보겠다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;암시적 Lock (synchronuized)&lt;/li&gt;
&lt;li&gt;명시적 Lock&lt;/li&gt;
&lt;li&gt;thread safe 한 객체 사용&lt;/li&gt;
&lt;li&gt;불변 객체 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자바스크립트는 왜 싱글 스레드일까?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트가 싱글 스레드를 선택한 이유는 자바스크립트가 탄생한 역사를 보면 알 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-style=&quot;style3&quot;&gt;자바스크립트는 &lt;b&gt;웹 페이지의 보조적인 기능을 수행하기 위해&lt;/b&gt; 브라우저에서 동작하는 &lt;b&gt;경량 프로그래밍 언어&lt;/b&gt;를 도입하기로 결정하고 만들어진 언어이다.&lt;/li&gt;
&lt;li data-ke-style=&quot;style3&quot;&gt;웹 사이트를 구현하던 개발자들에게 자바라는 언어는 다소 무겁고 어려운 언어였다.&lt;/li&gt;
&lt;li data-ke-style=&quot;style3&quot;&gt;자바는&amp;nbsp;&lt;b&gt;멀티 스레드 모델을 지원하는 언어&lt;/b&gt;이다.&lt;/li&gt;
&lt;li data-ke-style=&quot;style3&quot;&gt;멀티 스레드로 구현되는 서비스에서는 동시성 문제를 불가피하게 신경 써야만 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 역사 그리고 동시성으로 인한 복잡도 증가와 같은 이유들로 인해 자바스크립트는 싱글 스레드로 탄생한 것이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 우리는 자바스크립트를 멀티 스레드처럼 사용하고 있다. 이것이 어떻게 가능하게 되었을까?&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비동기 vs 동기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 싱글 스레드 방식으로 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 하나의 &lt;b&gt;실행 컨텍스트 스택&lt;/b&gt;을 갖는다. 하나의 스레드로는 동시에 2개 이상의 함수를 실행시킬 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;동기적인 처리 방식을 사용&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;b&gt;Web api, Eventloop, Taskque&lt;/b&gt;와 같은 자바스크립트가 아닌 &lt;b&gt;브라우저에 내장되어 있는 기능들을 사용&lt;/b&gt;함으로써, 자바스크립트는 &lt;b&gt;비동기 처리&lt;/b&gt;를 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 우리는 DOM Element의 이벤트 핸들러, 타이머, 서버에 자원을 요청 또는 응답할 수 있는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저의 구조 및 자세한 과정은 추후에 다루도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하자면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바스크립트 언어의 초기 개발 목적은 웹 페이지의 보조적인 기능을 수행하기 위한 경량적 언어였다.&lt;/li&gt;
&lt;li&gt;따라서 자바스크립트는 멀티 스레드의 동시성과 같은 무겁고 대응하기 복잡한 부분들을 피하기 위해 싱글 스레드 방식으로 구현되었다.&lt;/li&gt;
&lt;li&gt;하지만 브라우저의 내장 기능들(Web api, Eventloop, Taskque)을 활용하여 비동기 처리가 가능하게 함으로써 멀티 스레드처럼 동작시킬 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://miracleground.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%99%9C-%EC%8B%B1%EA%B8%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EB%A5%BC-%EC%84%A0%ED%83%9D%ED%96%88%EC%9D%84%EA%B9%8C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%8F%99%EA%B8%B0-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%94%EC%A7%84-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EB%A3%A8%ED%94%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://miracleground.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%99%9C-%EC%8B%B1%EA%B8%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EB%A5%BC-%EC%84%A0%ED%83%9D%ED%96%88%EC%9D%84%EA%B9%8C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%8F%99%EA%B8%B0-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%94%EC%A7%84-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EB%A3%A8%ED%94%84&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654009950157&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;자바스크립트는 왜 싱글 스레드를 선택했을까? 프로세스, 스레드, 비동기, 동기, 자바스크립트 &quot; data-og-description=&quot;목차 프로세스와 스레드 프로세스 싱글 스레드와 멀티 스레드 자바스크립트는 왜 싱글 스레드를 선택했을까 동기 vs 비동기 동기 비동기 자바스크립트로 비동기 처리하는 방법 자바스크립트 엔&quot; data-og-host=&quot;miracleground.tistory.com&quot; data-og-source-url=&quot;https://miracleground.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%99%9C-%EC%8B%B1%EA%B8%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EB%A5%BC-%EC%84%A0%ED%83%9D%ED%96%88%EC%9D%84%EA%B9%8C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%8F%99%EA%B8%B0-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%94%EC%A7%84-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EB%A3%A8%ED%94%84&quot; data-og-url=&quot;https://miracleground.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%99%9C-%EC%8B%B1%EA%B8%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EB%A5%BC-%EC%84%A0%ED%83%9D%ED%96%88%EC%9D%84%EA%B9%8C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%8F%99%EA%B8%B0-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%94%EC%A7%84-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EB%A3%A8%ED%94%84&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eE3T0/hyOBK1C052/h5elWQwl1BSy9YOvCQkS20/img.png?width=800&amp;amp;height=444&amp;amp;face=0_0_800_444,https://scrap.kakaocdn.net/dn/fpr9t/hyOBzZ3q8q/9cKhKr36sqTe4GXEUf5Yfk/img.png?width=800&amp;amp;height=444&amp;amp;face=0_0_800_444,https://scrap.kakaocdn.net/dn/by4dLj/hyOBE778nN/jsIVb0HBzrS7GPltbms6V0/img.png?width=1870&amp;amp;height=1040&amp;amp;face=0_0_1870_1040&quot;&gt;&lt;a href=&quot;https://miracleground.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%99%9C-%EC%8B%B1%EA%B8%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EB%A5%BC-%EC%84%A0%ED%83%9D%ED%96%88%EC%9D%84%EA%B9%8C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%8F%99%EA%B8%B0-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%94%EC%A7%84-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EB%A3%A8%ED%94%84&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://miracleground.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-%EC%99%9C-%EC%8B%B1%EA%B8%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EB%A5%BC-%EC%84%A0%ED%83%9D%ED%96%88%EC%9D%84%EA%B9%8C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EB%A0%88%EB%93%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%8F%99%EA%B8%B0-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%94%EC%A7%84-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EB%A3%A8%ED%94%84&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eE3T0/hyOBK1C052/h5elWQwl1BSy9YOvCQkS20/img.png?width=800&amp;amp;height=444&amp;amp;face=0_0_800_444,https://scrap.kakaocdn.net/dn/fpr9t/hyOBzZ3q8q/9cKhKr36sqTe4GXEUf5Yfk/img.png?width=800&amp;amp;height=444&amp;amp;face=0_0_800_444,https://scrap.kakaocdn.net/dn/by4dLj/hyOBE778nN/jsIVb0HBzrS7GPltbms6V0/img.png?width=1870&amp;amp;height=1040&amp;amp;face=0_0_1870_1040');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트는 왜 싱글 스레드를 선택했을까? 프로세스, 스레드, 비동기, 동기, 자바스크립트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;목차 프로세스와 스레드 프로세스 싱글 스레드와 멀티 스레드 자바스크립트는 왜 싱글 스레드를 선택했을까 동기 vs 비동기 동기 비동기 자바스크립트로 비동기 처리하는 방법 자바스크립트 엔&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;miracleground.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hojak99.tistory.com/307&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://hojak99.tistory.com/307&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654009956241&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Thread] 스레드 컨텍스트 스위칭&quot; data-og-description=&quot;스레드 컨텍스트 스위칭이란 무엇일까? 우선 우리는 컨텍스트 스위칭이란 것부터 알아야 한다. 그래야 스레드에서의 컨텍스트 스위칭을 더 쉽게 이해할 수 있을 것 같은 내 생각 때문이다.&amp;nbsp;이 &quot; data-og-host=&quot;hojak99.tistory.com&quot; data-og-source-url=&quot;https://hojak99.tistory.com/307&quot; data-og-url=&quot;https://hojak99.tistory.com/307&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/blJjaa/hyOBL7nI42/gVEyjYRAsTKeFL6xn3DPT0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bz1meC/hyOBGx5JYg/C9RYig3HqLITo79Sjp6qU0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/7VYEj/hyOBzZ3rdb/OLxeJjeKNiQK03kAKqkKv0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://hojak99.tistory.com/307&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hojak99.tistory.com/307&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/blJjaa/hyOBL7nI42/gVEyjYRAsTKeFL6xn3DPT0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bz1meC/hyOBGx5JYg/C9RYig3HqLITo79Sjp6qU0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/7VYEj/hyOBzZ3rdb/OLxeJjeKNiQK03kAKqkKv0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Thread] 스레드 컨텍스트 스위칭&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;스레드 컨텍스트 스위칭이란 무엇일까? 우선 우리는 컨텍스트 스위칭이란 것부터 알아야 한다. 그래야 스레드에서의 컨텍스트 스위칭을 더 쉽게 이해할 수 있을 것 같은 내 생각 때문이다.&amp;nbsp;이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hojak99.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@dyllis/%EB%8F%99%EC%8B%9C%EC%84%B1%EC%9D%B4-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@dyllis/%EB%8F%99%EC%8B%9C%EC%84%B1%EC%9D%B4-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654009964867&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;동시성이 무엇일까&quot; data-og-description=&quot;소개 이 글을 작성하게 된 이유는 사전면접이나 기술면접에서 항상 등장하는 프로세스와 스레드 차이, 동시성에 대해서 설명해주세요라고 했을 때 제대로 설명하지 못하는 나의 모습을 보고 정&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@dyllis/%EB%8F%99%EC%8B%9C%EC%84%B1%EC%9D%B4-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C&quot; data-og-url=&quot;https://velog.io/@dyllis/동시성이-무엇일까&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ExGlh/hyOByz6UAo/iqOwXZfa3xClxMIaZRRaR1/img.png?width=1203&amp;amp;height=709&amp;amp;face=0_0_1203_709,https://scrap.kakaocdn.net/dn/wP8E5/hyOBIvWWwv/mgI7NwNIaTalo09yZnLmn1/img.png?width=1203&amp;amp;height=709&amp;amp;face=0_0_1203_709,https://scrap.kakaocdn.net/dn/buUAHj/hyOBGkzJH6/L5oB6Ic8sLUrdGahJkLxUk/img.png?width=1203&amp;amp;height=709&amp;amp;face=0_0_1203_709&quot;&gt;&lt;a href=&quot;https://velog.io/@dyllis/%EB%8F%99%EC%8B%9C%EC%84%B1%EC%9D%B4-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@dyllis/%EB%8F%99%EC%8B%9C%EC%84%B1%EC%9D%B4-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ExGlh/hyOByz6UAo/iqOwXZfa3xClxMIaZRRaR1/img.png?width=1203&amp;amp;height=709&amp;amp;face=0_0_1203_709,https://scrap.kakaocdn.net/dn/wP8E5/hyOBIvWWwv/mgI7NwNIaTalo09yZnLmn1/img.png?width=1203&amp;amp;height=709&amp;amp;face=0_0_1203_709,https://scrap.kakaocdn.net/dn/buUAHj/hyOBGkzJH6/L5oB6Ic8sLUrdGahJkLxUk/img.png?width=1203&amp;amp;height=709&amp;amp;face=0_0_1203_709');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;동시성이 무엇일까&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;소개 이 글을 작성하게 된 이유는 사전면접이나 기술면접에서 항상 등장하는 프로세스와 스레드 차이, 동시성에 대해서 설명해주세요라고 했을 때 제대로 설명하지 못하는 나의 모습을 보고 정&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ganzicoder.tistory.com/98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ganzicoder.tistory.com/98&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654009966032&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;스레드와 동시성&quot; data-og-description=&quot;스레드 스레드는 어떠한 프로그램 안에서 , 프로세스 안에서 실행되는 흐름의 단위! 통상 한 프로그램은 하나의 스레드를 갖고있지만 프로그램 환경에따라 둘 이상의 스레드를 동시에 실행가능&quot; data-og-host=&quot;ganzicoder.tistory.com&quot; data-og-source-url=&quot;https://ganzicoder.tistory.com/98&quot; data-og-url=&quot;https://ganzicoder.tistory.com/98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bqERJC/hyOBJ2HyZA/1BgM5EikSKzBrCh4xXqM5k/img.jpg?width=720&amp;amp;height=961&amp;amp;face=0_0_720_961,https://scrap.kakaocdn.net/dn/EfRPP/hyOBHDMUEg/sCfmuWNKyhziRRRbMzxuC1/img.jpg?width=720&amp;amp;height=961&amp;amp;face=0_0_720_961,https://scrap.kakaocdn.net/dn/itSmd/hyOBHDMUBt/sxsUkhXD9DK18Rk6hVZ2o0/img.jpg?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000&quot;&gt;&lt;a href=&quot;https://ganzicoder.tistory.com/98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ganzicoder.tistory.com/98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bqERJC/hyOBJ2HyZA/1BgM5EikSKzBrCh4xXqM5k/img.jpg?width=720&amp;amp;height=961&amp;amp;face=0_0_720_961,https://scrap.kakaocdn.net/dn/EfRPP/hyOBHDMUEg/sCfmuWNKyhziRRRbMzxuC1/img.jpg?width=720&amp;amp;height=961&amp;amp;face=0_0_720_961,https://scrap.kakaocdn.net/dn/itSmd/hyOBHDMUBt/sxsUkhXD9DK18Rk6hVZ2o0/img.jpg?width=1000&amp;amp;height=1000&amp;amp;face=0_0_1000_1000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;스레드와 동시성&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;스레드 스레드는 어떠한 프로그램 안에서 , 프로세스 안에서 실행되는 흐름의 단위! 통상 한 프로그램은 하나의 스레드를 갖고있지만 프로그램 환경에따라 둘 이상의 스레드를 동시에 실행가능&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ganzicoder.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@mooh2jj/%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@mooh2jj/%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1654009974859&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;멀티 스레드의 동시성 이슈 그리고 해결방법&quot; data-og-description=&quot;스레드는 작업의 한단위이다. 여기서 멀티스레드 방식은 멀티태스킹을 하는 방식 중, 한 코어에서 여러 스레드를 이용해서 작업을 처리하는 방식이다.멀티 스레드를 이용하면 공유하는 장원이 &quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@mooh2jj/%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88&quot; data-og-url=&quot;https://velog.io/@mooh2jj/멀티-스레드의-동시성-이슈&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b8S1Sa/hyOBCvIEn4/ZAu9eymFSi8N3QfHXtn3GK/img.png?width=700&amp;amp;height=350&amp;amp;face=0_0_700_350,https://scrap.kakaocdn.net/dn/bpQBQF/hyOBAEF7xd/YuFHcl3qAXau1du8VtwiEk/img.png?width=700&amp;amp;height=350&amp;amp;face=0_0_700_350,https://scrap.kakaocdn.net/dn/bcWvA7/hyOBKHi4mV/Hl2R7K8KExXzZLEzwsSAp0/img.jpg?width=1440&amp;amp;height=1440&amp;amp;face=0_0_1440_1440&quot;&gt;&lt;a href=&quot;https://velog.io/@mooh2jj/%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@mooh2jj/%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b8S1Sa/hyOBCvIEn4/ZAu9eymFSi8N3QfHXtn3GK/img.png?width=700&amp;amp;height=350&amp;amp;face=0_0_700_350,https://scrap.kakaocdn.net/dn/bpQBQF/hyOBAEF7xd/YuFHcl3qAXau1du8VtwiEk/img.png?width=700&amp;amp;height=350&amp;amp;face=0_0_700_350,https://scrap.kakaocdn.net/dn/bcWvA7/hyOBKHi4mV/Hl2R7K8KExXzZLEzwsSAp0/img.jpg?width=1440&amp;amp;height=1440&amp;amp;face=0_0_1440_1440');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;멀티 스레드의 동시성 이슈 그리고 해결방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;스레드는 작업의 한단위이다. 여기서 멀티스레드 방식은 멀티태스킹을 하는 방식 중, 한 코어에서 여러 스레드를 이용해서 작업을 처리하는 방식이다.멀티 스레드를 이용하면 공유하는 장원이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT/Study</category>
      <category>동시성</category>
      <category>멀티스레드</category>
      <category>브라우저</category>
      <category>싱글스레드</category>
      <category>자바스크립트</category>
      <category>컨텍스트</category>
      <category>프로세스</category>
      <author>프티</author>
      <guid isPermaLink="true">https://lifeandit.tistory.com/145</guid>
      <comments>https://lifeandit.tistory.com/145#entry145comment</comments>
      <pubDate>Wed, 1 Jun 2022 00:13:13 +0900</pubDate>
    </item>
    <item>
      <title> Status Code</title>
      <link>https://lifeandit.tistory.com/144</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Status Code, 즉 상태 코드는 http 요청 시에 request가 아닌 response에서 요청의 처리 상태를 알려주는 기능이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;100 ~ 5xx번 대의 상태 코드가 존재하며 숫자 맨 앞자리의 번호에 따라 처리 상태의 종류가 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1xx (informational): 요청이 수신되어 처리 중&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청을 받았으며 작업을 계속한다는 의미를 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP/1.0 이래로 1xx 상태 코드들은 정의되지 않았다고 하니, 실험적인 상태를 제외하고 HTTP/1.0 클라이언트로 보내면 안 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2xx (Successful): 요청 정상 처리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 요청한 동작을 수신하여 이해했고 승낙했으며 성공적으로 처리했음을 가리킨다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;200(성공): 서버가 요청을 제대로 처리했다는 뜻이다. 이는 주로 서버가 요청한 페이지를 제공했다는 의미로 쓰인다.&lt;/li&gt;
&lt;li&gt;201(작성됨): 성공적으로 요청되었으며 서버가 새 리소스를 작성했다. (&lt;b&gt;POST, PUT에 의한 수정, 추가 성공 시&lt;/b&gt;)&lt;/li&gt;
&lt;li&gt;202(허용됨): 서버가 요청을 접수했지만 아직 처리하지 않았다.&lt;/li&gt;
&lt;li&gt;203(신뢰할 수 없는 정보): 서버가 요청을 성공적으로 처리했지만 다른 소스에서 수신된 정보를 제공하고 있다.&lt;/li&gt;
&lt;li&gt;204(콘텐츠 없음): 서버가 요청을 성공적으로 처리했지만 콘텐츠를 제공하지 않는다.&lt;/li&gt;
&lt;li&gt;205(콘텐츠 재설정): 서버가 요청을 성공적으로 처리했지만 콘텐츠를 표시하지 않는다. 204 응답과 달리 이 응답은 요청자가 문서 보기를 재설정할 것을 요구한다(예: 새 입력을 위한 양식 비우기).&lt;/li&gt;
&lt;li&gt;206(일부 콘텐츠): 서버가 GET 요청의 일부만 성공적으로 처리했다.&lt;/li&gt;
&lt;li&gt;207(다중 상태,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc4918&quot;&gt;RFC 4918&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;208(이미 보고됨,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc5842&quot;&gt;RFC 5842&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;226 IM Used (&lt;a href=&quot;https://tools.ietf.org/html/rfc3229&quot;&gt;RFC 3229&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3xx (Redirection): 요청을 완료하려면 추가 행동이 필요&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트는 요청을 마치기 위해 추가 동작을 취해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;300(여러 선택항목): 서버가 요청에 따라 여러 조치를 선택할 수 있다. 서버가 사용자 에이전트에 따라 수행할 작업을 선택하거나, 요청자가 선택할 수 있는 작업 목록을 제공한다.&lt;/li&gt;
&lt;li&gt;301(영구 이동): 요청한 페이지를 새 위치로 영구적으로 이동했다. GET 또는 HEAD 요청에 대한 응답으로 이 응답을 표시하면 요청자가 자동으로 새 위치로 전달된다.&lt;/li&gt;
&lt;li&gt;302(임시 이동): 현재 서버가 다른 위치의 페이지로 요청에 응답하고 있지만 요청자는 향후 요청 시 원래 위치를 계속 사용해야 한다.&lt;/li&gt;
&lt;li&gt;303(기타 위치 보기): 요청자가 다른 위치에 별도의 GET 요청을 하여 응답을 검색할 경우 서버는 이 코드를 표시한다. HEAD 요청 이외의 모든 요청을 다른 위치로 자동으로 전달한다.&lt;/li&gt;
&lt;li&gt;304(수정되지 않음): 마지막 요청 이후 요청한 페이지는 수정되지 않았다. 서버가 이 응답을 표시하면 페이지의 콘텐츠를 표시하지 않는다. 요청자가 마지막으로 페이지를 요청한 후 페이지가 변경되지 않으면 이 응답(If-Modified-Since HTTP 헤더라고 함)을 표시하도록 서버를 구성해야 한다.&lt;/li&gt;
&lt;li&gt;305(프록시 사용): 요청자는 프록시를 사용하여 요청한 페이지만 액세스할 수 있다. 서버가 이 응답을 표시하면 요청자가 사용할 프록시를 가리키는 것이기도 하다.&lt;/li&gt;
&lt;li&gt;307(임시 리다이렉션): 현재 서버가 다른 위치의 페이지로 요청에 응답하고 있지만 요청자는 향후 요청 시 원래 위치를 계속 사용해야 한다.&lt;/li&gt;
&lt;li&gt;308(영구 리다이렉션, RFC에서 실험적으로 승인됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4xx (Client Error): 클라이언트 오류, 잘못된 문법 등으로 서버가 요청을 수행할 수 없음&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트에 오류가 있음을 나타낸다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;400(잘못된 요청): 서버가 요청의 구문을 인식하지 못했다.&lt;/li&gt;
&lt;li&gt;401(권한 없음): 이 요청은 인증이 필요하다. 서버는 로그인이 필요한 페이지에 대해 이 요청을 제공할 수 있다. 상태 코드 이름이 권한 없음(Unauthorized)으로 되어 있지만 실제 뜻은 인증 안됨(Unauthenticated)에 더 가깝다.&lt;/li&gt;
&lt;li&gt;402(결제 필요): 이 요청은 결제가 필요합니다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/HTTP_403&quot;&gt;403&lt;/a&gt;(Forbidden, 금지됨): 서버가 요청을 거부하고 있다. 예를 들자면, 사용자가 리소스에 대한 필요 권한을 갖고 있지 않다. (401은 인증 실패, 403은 인가 실패라고 볼 수 있음)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/HTTP_404&quot;&gt;404&lt;/a&gt;(Not Found, 찾을 수 없음): 서버가 요청한 페이지(Resource)를 찾을 수 없다. 예를 들어 서버에 존재하지 않는 페이지에 대한 요청이 있을 경우 서버는 이 코드를 제공한다.&lt;/li&gt;
&lt;li&gt;405(허용되지 않는 메소드): 요청에 지정된 방법을 사용할 수 없다. 예를 들어 POST 방식으로 요청을 받는 서버에 GET 요청을 보내는 경우, 또는 읽기 전용 리소스에 PUT 요청을 보내는 경우에 이 코드를 제공한다.&lt;/li&gt;
&lt;li&gt;406(허용되지 않음): 요청한 페이지가 요청한 콘텐츠 특성으로 응답할 수 없다.&lt;/li&gt;
&lt;li&gt;407(프록시 인증 필요): 이 상태 코드는 401(권한 없음)과 비슷하지만 요청자가 프록시를 사용하여 인증해야 한다. 서버가 이 응답을 표시하면 요청자가 사용할 프록시를 가리키는 것이기도 한다.&lt;/li&gt;
&lt;li&gt;408(요청 시간초과): 서버의 요청 대기가 시간을 초과하였다.&lt;/li&gt;
&lt;li&gt;409(충돌): 서버가 요청을 수행하는 중에 충돌이 발생했다. 서버는 응답할 때 충돌에 대한 정보를 포함해야 한다. 서버는 PUT 요청과 충돌하는 PUT 요청에 대한 응답으로 이 코드를 요청 간 차이점 목록과 함께 표시해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/410_Gone&quot;&gt;410&lt;/a&gt;(사라짐): 서버는 요청한 리소스가 영구적으로 삭제되었을 때 이 응답을 표시한다. 404(찾을 수 없음) 코드와 비슷하며 이전에 있었지만 더 이상 존재하지 않는 리소스에 대해 404 대신 사용하기도 한다. 리소스가 영구적으로 이동된 경우 301을 사용하여 리소스의 새 위치를 지정해야 한다.&lt;/li&gt;
&lt;li&gt;411(길이 필요): 서버는 유효한 콘텐츠 길이 헤더 입력란 없이는 요청을 수락하지 않는다.&lt;/li&gt;
&lt;li&gt;412(사전 조건 실패): 서버가 요청자가 요청 시 부과한 사전 조건을 만족하지 않는다.&lt;/li&gt;
&lt;li&gt;413(요청 속성이 너무 큼): 요청이 너무 커서 서버가 처리할 수 없다.&lt;/li&gt;
&lt;li&gt;414(요청 URI가 너무 긺): 요청 URI(일반적으로 URL)가 너무 길어 서버가 처리할 수 없다.&lt;/li&gt;
&lt;li&gt;415(지원되지 않는 미디어 유형): 요청이 요청한 페이지에서 지원하지 않는 형식으로 되어 있다.&lt;/li&gt;
&lt;li&gt;416(처리할 수 없는 요청 범위): 요청이 페이지에서 처리할 수 없는 범위에 해당되는 경우 서버는 이 상태 코드를 표시한다.&lt;/li&gt;
&lt;li&gt;417(예상 실패): 서버는 Expect 요청 헤더 입력란의 요구사항을 만족할 수 없다.&lt;/li&gt;
&lt;li&gt;418(I'm a teapot,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc2324&quot;&gt;RFC 2324&lt;/a&gt;&lt;span&gt;&amp;nbsp;,&lt;a href=&quot;https://google.com/teapot&quot;&gt;https://google.com/teapot&lt;/a&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;420(Enhance Your Calm, 트위터)&lt;/li&gt;
&lt;li&gt;422(처리할 수 없는 엔티티, WebDAV;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc4918&quot;&gt;RFC 4918&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;423(잠김, WebDAV;&lt;a href=&quot;https://tools.ietf.org/html/rfc4918&quot;&gt;RFC 4918&lt;/a&gt;): 접근하려는 리소스가 잠겨 있다.&lt;/li&gt;
&lt;li&gt;424(실패된 의존성, WebDAV;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc4918&quot;&gt;RFC 4918&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;424(메쏘드 실패, WebDAV)&lt;/li&gt;
&lt;li&gt;425(정렬되지 않은 컬렉션, 인터넷 초안)&lt;/li&gt;
&lt;li&gt;426(업그레이드 필요,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc2817&quot;&gt;RFC 2817&lt;/a&gt;): 클라이언트는 업그레이드 헤더 필드에 주어진 프로토콜로 요청을 보내야 한다.&lt;/li&gt;
&lt;li&gt;428(전제조건 필요,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc6585&quot;&gt;RFC 6585&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;429(너무 많은 요청,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc6585&quot;&gt;RFC 6585&lt;/a&gt;): 사용자가 일정 시간 동안 너무 많은 요청을 보냈다.&lt;/li&gt;
&lt;li&gt;431(요청 헤더 필드가 너무 큼,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc6585&quot;&gt;RFC 6585&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;444(응답 없음, Nginx)&lt;/li&gt;
&lt;li&gt;449(다시 시도, 마이크로소프트)&lt;/li&gt;
&lt;li&gt;450(윈도 자녀 보호에 의해 차단됨, 마이크로소프트)&lt;/li&gt;
&lt;li&gt;451(법적인 이유로 이용 불가, 인터넷 초안)&lt;/li&gt;
&lt;li&gt;451(리다이렉션, 마이크로소프트)&lt;/li&gt;
&lt;li&gt;494(요청 헤더가 너무 큼, Nginx)&lt;/li&gt;
&lt;li&gt;495(Cert 오류, Nginx)&lt;/li&gt;
&lt;li&gt;496(Cert 없음, Nginx)&lt;/li&gt;
&lt;li&gt;497(HTTP to HTTPS, Nginx)&lt;/li&gt;
&lt;li&gt;499(클라이언트가 요청을 닫음, Nginx)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5xx (Server Error): 서버 오류, 서버가 정상 요청을 처리하지 못함&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;서버가 유효한 요청을 명백하게 수행하지 못했음을 나타낸다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;500(내부 서버 오류): 서버에 오류가 발생하여 요청을 수행할 수 없다.&lt;/li&gt;
&lt;li&gt;501(구현되지 않음): 서버에 요청을 수행할 수 있는 기능이 없다. 예를 들어 서버가 요청 메소드를 인식하지 못할 때 이 코드를 표시한다.&lt;/li&gt;
&lt;li&gt;502 (Bad Gateway, 불량 게이트웨이): 서버가 게이트웨이나 프록시 역할을 하고 있거나 또는 업스트림 서버에서 잘못된 응답을 받았다.&lt;/li&gt;
&lt;li&gt;503(서비스를 사용할 수 없음): 서버가 오버 로드되었거나 유지관리를 위해 다운되었기 때문에 현재 서버를 사용할 수 없다. 이는 대개 일시적인 상태이다.&lt;/li&gt;
&lt;li&gt;504(게이트웨이 시간 초과): 서버가 게이트웨이나 프록시 역할을 하고 있거나 또는 업스트림 서버에서 제때 요청을 받지 못했다.&lt;/li&gt;
&lt;li&gt;505(HTTP 버전이 지원되지 않음): 서버가 요청에 사용된 HTTP 프로토콜 버전을 지원하지 않는다.&lt;/li&gt;
&lt;li&gt;506(Variant Also Negotiates,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc2295&quot;&gt;RFC 2295&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;507(용량 부족, WebDAV;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc4918&quot;&gt;RFC 4918&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;508(루프 감지됨, WebDAV;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc5842&quot;&gt;RFC 5842&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;509(대역폭 제한 초과, Apache bw/limited extension)&lt;/li&gt;
&lt;li&gt;510(확장되지 않음,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc2774&quot;&gt;RFC 2774&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;511(네트워크 인증 필요,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc6585&quot;&gt;RFC 6585&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;520(Unknown Error, 알 수 없음)&lt;/li&gt;
&lt;li&gt;598(네트워크 읽기 시간초과 오류, 알 수 없음)&lt;/li&gt;
&lt;li&gt;599(네트워크 연결 시간초과 오류, 알 수 없음)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>IT/Study</category>
      <category>Status Code</category>
      <category>상태코드</category>
      <author>프티</author>
      <guid isPermaLink="true">https://lifeandit.tistory.com/144</guid>
      <comments>https://lifeandit.tistory.com/144#entry144comment</comments>
      <pubDate>Tue, 31 May 2022 17:42:32 +0900</pubDate>
    </item>
  </channel>
</rss>