<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>as cool as snowman</title>
    <link>https://popawaw.tistory.com/</link>
    <description>software engineer</description>
    <language>ko</language>
    <pubDate>Thu, 7 May 2026 11:46:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>jongyun ha</managingEditor>
    <image>
      <title>as cool as snowman</title>
      <url>https://tistory1.daumcdn.net/tistory/4204827/attach/8df9e2c91bfa4c35ab9f1de032bd8a9a</url>
      <link>https://popawaw.tistory.com</link>
    </image>
    <item>
      <title>[leetcode] 689. Maximum Sum of 3 Non-Overlapping Subarrays</title>
      <link>https://popawaw.tistory.com/347</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/maximum-sum-of-3-non-overlapping-subarrays/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/maximum-sum-of-3-non-overlapping-subarrays/description/&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;해당 문제는 정수배열 nums 와 k 가 주어졌을 때 겹치지 않는 최대합을 가지는 길이 k 의 부분 배열 3개를 찾아서 반환하는 문제입니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 주의할 점은 정답이 여러개 인 경우 index 가 작은것 부터 반환해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Approach&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제는 총 3개의 부분 배열을 반환해야 합니다 그러므로 3 개의 section 으로 분할 할 수 있고 이것을 left, middle, right 라고 정의 하겠습니다.&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;먼저 sliding window 를 통해 구간 합을 미리 구해 두겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1735357821043&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val sums = IntArray(n) { i -&amp;gt;
    nums.slice(i until i + k).sum()
}&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_1735357857291&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val left = IntArray(n)
var maxIndex = 0
for (i in 0 until n) {
    if (sums[i] &amp;gt; sums[maxIndex]) {
        maxIndex = i
    }
    left[i] = maxIndex
}&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;마찬 가지로 오른쪽에서 시작했을때의 최대값을 계산합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1735357877627&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val right = IntArray(n)
maxIndex = n - 1
for (i in n - 1 downTo 0) {
    if (sums[i] &amp;gt;= sums[maxIndex]) {
        maxIndex = i
    }
    right[i] = maxIndex
}&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;마지막으로 합이 가장 큰 최적의 조합을 찾습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1735357902510&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (i in k until n - k) {
    val leftIndex = left[i - k]
    val rightIndex = right[i + k]
    val totalSum = sums[leftIndex] + sums[i] + sums[rightIndex]
    
    if (totalSum &amp;gt; maxSum) {
        maxSum = totalSum
        result[0] = leftIndex
        result[1] = i
        result[2] = rightIndex
    }
}&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;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;: O(n)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구간합 계산: O(n)&lt;/li&gt;
&lt;li&gt;왼쪽/오른쪽 최대값 계산: 각각 O(n)&lt;/li&gt;
&lt;li&gt;최적 조합 찾기: O(n)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공간 복잡도&lt;/b&gt;: O(n)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sums, left, right 배열: 각각 O(n)&lt;/li&gt;
&lt;/ul&gt;
&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;pre id=&quot;code_1735357934643&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    fun maxSumOfThreeSubarrays(nums: IntArray, k: Int): IntArray {
        val n = nums.size - k + 1

        val sums = IntArray(n) { i -&amp;gt;
            nums.slice(i until i + k).sum()
        }

        val left = IntArray(n)
        var maxIndex = 0

        for (i in sums.indices) {
            if (sums[i] &amp;gt; sums[maxIndex]) {
                maxIndex = i
            }
            left[i] = maxIndex
        }

        val right = IntArray(n)
        maxIndex = n - 1

        for (i in n - 1 downTo 0) {
            if (sums[i] &amp;gt;= sums[maxIndex]) {
                maxIndex = i
            }
            right[i] = maxIndex
        }

        val result = IntArray(3)
        var maxSum = Int.MIN_VALUE

        for (i in k until sums.size - k) {
            val leftIdx = left[i - k]
            val rightIdx = right[i + k]
            val sum = sums[leftIdx] + sums[i] + sums[rightIdx]
            if (sum &amp;gt; maxSum) {
                maxSum = sum
                result[0] = leftIdx
                result[1] = i
                result[2] = rightIdx
            }
        }

        return result
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/leetcode</category>
      <category>Algorithm</category>
      <category>Kotlin</category>
      <category>leetcode</category>
      <category>maximum sum of 3 non-overlapping subarrays</category>
      <author>jongyun ha</author>
      <guid isPermaLink="true">https://popawaw.tistory.com/347</guid>
      <comments>https://popawaw.tistory.com/347#entry347comment</comments>
      <pubDate>Sat, 28 Dec 2024 12:52:59 +0900</pubDate>
    </item>
    <item>
      <title>leetcode - 862. Shortest Subarray with Sum at Least K</title>
      <link>https://popawaw.tistory.com/346</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/description/?envType=daily-question&amp;amp;envId=2024-11-17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/description/?envType=daily-question&amp;amp;envId=2024-11-17&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;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Approach&lt;br /&gt;&lt;br /&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제를 O(N) 시간 복잡도로 문제를 해결 하기 위해서 PrefixSum 과 단조 증가 (Monotonic increasing) Queue 를 사용할 예정입니다.&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;정수 배열 nums와 정수 k가 주어졌을 때, 다음 조건을 만족하는 가장 짧은 부분 배열의 길이를 반환하세요:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부분 배열의 합이 최소한 k 이상이어야 함&lt;/li&gt;
&lt;li&gt;부분 배열은 비어있지 않아야 함&lt;/li&gt;
&lt;li&gt;만약 이러한 조건을 만족하는 부분 배열이 존재하지 않는다면 -1을 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 **부분 배열(subarray)**은 원래 배열의 &lt;b&gt;연속된&lt;/b&gt; 부분을 의미합니다.&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;[1,2,3] 배열에서 [2,3]은 유효한 부분 배열입니다 (연속된 요소들)&lt;/li&gt;
&lt;li&gt;[1,3]은 유효한 부분 배열이 아닙니다 (2를 건너뛰었기 때문에 연속적이지 않음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;초기설정&amp;nbsp;&lt;/h4&gt;
&lt;pre id=&quot;code_1731825787862&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;n := len(nums)
result := math.MaxInt
deque := make([]int, 0)&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;n: 배열의 길이&lt;/li&gt;
&lt;li&gt;result: 최소 길이를 저장할 변수 (초기값은 최대정수)&lt;/li&gt;
&lt;li&gt;deque: 단조증가하는 prefix sum의 인덱스를 저장할 덱(양방향 큐)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;누적합(Prefix Sum) 계산&lt;/h4&gt;
&lt;pre id=&quot;code_1731825809868&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;prefixSum := make([]int, n+1)
for i := 0; i &amp;lt; len(prefixSum)-1; i++ {
   prefixSum[i+1] = prefixSum[i] + nums[i]
}&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;prefixSum[i]: 0부터 i-1까지의 누적합&lt;/li&gt;
&lt;li&gt;예: nums = [2,-1,2]일 때&lt;/li&gt;
&lt;li&gt;prefixSum = [0,2,1,3]&lt;/li&gt;
&lt;/ul&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;pre id=&quot;code_1731825864172&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for i := 0; i &amp;lt; len(nums); i++ {
   // 첫 번째 while 루프
   for len(deque) &amp;gt; 0 &amp;amp;&amp;amp; prefixSum[i]-prefixSum[deque[0]] &amp;gt;= k {
      result = min(result, i-deque[0])
      deque = deque[1:]
   }

   // 두 번째 while 루프
   for len(deque) &amp;gt; 0 &amp;amp;&amp;amp; prefixSum[i] &amp;lt;= prefixSum[deque[len(deque)-1]] {
      deque = deque[:len(deque)-1]
   }
   deque = append(deque, i)
}&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 루프: 현재까지의 누적합에서 덱의 첫 번째 원소(가장 오래된 인덱스)를 뺀 값이 k 이상이면
&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;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 덱(deque)의 단조성을 유지하기 위한 핵심적인 조건입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1731825900264&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;len(deque) &amp;gt; 0 &amp;amp;&amp;amp; prefixSum[i] &amp;lt;= prefixSum[deque[len(deque)-1]]&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;len(deque) &amp;gt; 0: 덱이 비어있지 않은지 확인&lt;/li&gt;
&lt;li&gt;prefixSum[i]: 현재 보고 있는 위치까지의 누적합&lt;/li&gt;
&lt;li&gt;deque[len(deque)-1]: 덱의 마지막 원소 (가장 최근에 추가된 인덱스)&lt;/li&gt;
&lt;li&gt;prefixSum[deque[len(deque)-1]]: 덱의 마지막 위치의 누적합&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;왜 이 조건이 필요한가?&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1731825930310&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;현재 덱 상태: [0, 2, 4]
prefixSum[0] = 0
prefixSum[2] = 4
prefixSum[4] = 2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;왜냐하면:
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;더 뒤에 있는 위치(더 긴 부분배열)&lt;/li&gt;
&lt;li&gt;더 큰 누적합을 가짐&lt;/li&gt;
&lt;li&gt;따라서 최소 길이를 찾는데 도움이 되지 않음&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/leetcode</category>
      <category>leetcode</category>
      <category>monotonic queue</category>
      <category>prefixsum</category>
      <category>단조 증가</category>
      <author>jongyun ha</author>
      <guid isPermaLink="true">https://popawaw.tistory.com/346</guid>
      <comments>https://popawaw.tistory.com/346#entry346comment</comments>
      <pubDate>Sun, 17 Nov 2024 15:47:31 +0900</pubDate>
    </item>
    <item>
      <title>leetcode: Maximum Sum Circular Subarray (kadane 알고리즘)</title>
      <link>https://popawaw.tistory.com/345</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/maximum-sum-circular-subarray/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/maximum-sum-circular-subarray/&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;해당 문제는 kadane 알고리즘 방법으로 접근하여 문제를 해결 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Approach&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Kadane's algorithm을 사용하여 일반적인 최대 부분합을 O(n)에 구합니다.&lt;/li&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;시간복잡도: O(n) 공간복잡도: O(1)&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;전체 배열의 합 (total): 5 + (-3) + 5 = 7&lt;/li&gt;
&lt;li&gt;최소 부분합 (minSum): -3
&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;/li&gt;
&lt;li&gt;total - minSum = 7 - (-3) = 10
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이것이 바로 [5,5]를 선택했을 때의 합과 같습니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 되는 이유는:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;순환 배열에서 양 끝의 원소들을 선택하려면 (예: [5,5])&lt;/li&gt;
&lt;li&gt;중간에 있는 원소들을 제외해야 합니다 (예: [-3])&lt;/li&gt;
&lt;li&gt;중간의 원소들을 제외하는 가장 좋은 방법은 &quot;최소 부분합&quot;을 찾아서 제거하는 것입니다&lt;/li&gt;
&lt;li&gt;따라서 &quot;전체 합 - 최소 부분합&quot;이 순환 배열에서 가능한 최대 부분합이 됩니다&lt;/li&gt;
&lt;/ol&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;한 번의 순회로 최소 부분합을 찾을 수 있습니다 (O(n))&lt;/li&gt;
&lt;li&gt;전체 합도 한 번의 순회로 구할 수 있습니다 (O(n))&lt;/li&gt;
&lt;li&gt;추가 메모리를 사용하지 않습니다 (O(1))&lt;/li&gt;
&lt;/ul&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;circular-array.svg&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5e8GG/btsKEswBLv4/SiWVUsRjCKU76rWeNMdkfk/tfile.svg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5e8GG/btsKEswBLv4/SiWVUsRjCKU76rWeNMdkfk/tfile.svg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5e8GG/btsKEswBLv4/SiWVUsRjCKU76rWeNMdkfk/tfile.svg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5e8GG%2FbtsKEswBLv4%2FSiWVUsRjCKU76rWeNMdkfk%2Ftfile.svg&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;521&quot; height=&quot;391&quot; data-filename=&quot;circular-array.svg&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;150&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1731245204398&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func maxSubarraySumCircular(nums []int) int {
	if len(nums) == 0 {
		return 0
	}

	kadane := func(nums []int, findMax bool) int {
		curr := nums[0]
		result := nums[0]

		for i := 1; i &amp;lt; len(nums); i++ {
			if findMax {
				curr = max(nums[i], curr+nums[i])
				result = max(curr, result)
			} else {
				curr = min(nums[i], curr+nums[i])
				result = min(curr, result)
			}
		}
		return result
	}

	findMax := kadane(nums, true)
	if findMax &amp;lt; 0 {
		return findMax
	}

	totalSum := 0

	for _, num := range nums {
		totalSum += num
	}

	findMin := kadane(nums, false)
	return max(findMax, totalSum-findMin)
}&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&quot;mttContainer&quot; class=&quot;notranslate&quot; style=&quot;transform: translate(478px, 2333px);&quot; aria-expanded=&quot;false&quot;&gt;&amp;nbsp;&lt;/div&gt;</description>
      <category>Algorithm</category>
      <category>go</category>
      <category>leetcode</category>
      <category>leetcode 918</category>
      <category>maximum sum circular subarray</category>
      <author>jongyun ha</author>
      <guid isPermaLink="true">https://popawaw.tistory.com/345</guid>
      <comments>https://popawaw.tistory.com/345#entry345comment</comments>
      <pubDate>Sun, 10 Nov 2024 22:27:14 +0900</pubDate>
    </item>
    <item>
      <title>Docker 리소스 제약 (Resource constraints) 에 대하여</title>
      <link>https://popawaw.tistory.com/344</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 container resource 는 제약이 없으며 호스트의 커널 스케줄러가 허용하는 한계치 까지 주어진 리소스를 최대한 사용할 수 있습니다.&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;하나의 machine (Ubuntu) 이 cpu 4 core / memory 8GB 라고 가정했을때 4개의 application 을 실행하고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2개의 application 에 메모리 누수가 있다고 가정했을때 2개 의 application 모두 8GB 까지 메모리를 사용하려고 합니다&amp;nbsp;&lt;br /&gt;해당 상황은 해당 Ubuntu machine 을 shutdown 시키는 결과를 초래 할 수 있고 운영 상황에서는 큰 장애로 이어 질 수 있습니다.&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;br /&gt;&lt;br /&gt;이 글은 Docker 공식문서를 참고했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/engine/containers/resource_constraints/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.docker.com/engine/containers/resource_constraints/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1729860689463&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Resource constraints&quot; data-og-description=&quot;Specify the runtime options for a container&quot; data-og-host=&quot;docs.docker.com&quot; data-og-source-url=&quot;https://docs.docker.com/engine/containers/resource_constraints/&quot; data-og-url=&quot;https://docs.docker.com/engine/containers/resource_constraints/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c3vPvk/hyXpBgj038/MNipfEuKfo1aIV4TV8AcPK/img.jpg?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260&quot;&gt;&lt;a href=&quot;https://docs.docker.com/engine/containers/resource_constraints/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.docker.com/engine/containers/resource_constraints/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c3vPvk/hyXpBgj038/MNipfEuKfo1aIV4TV8AcPK/img.jpg?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260');&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;Resource constraints&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Specify the runtime options for a container&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.docker.com&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;메모리 제한 (Memory limit)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker 는 메모리 제한을 두가지로 제한 할 수 있습니다. 하나는 소프트 이고 하나는 하드입니다.&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;하드: hard 를 사용하면 컨테이너가 고정된 양의 메모리만 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트: soft 를 사용하면 커널이 메모리 부족이나 host 머신에서 경합을 감지하는등 특정 조건이 충족되지 않는 한 컨테이너가 필요한 만큼의 메모리를 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-10-25 at 21.53.49.png&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;771&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cn3Ls/btsKlk0r4E4/nPDToLHnxBUBERvKopVfk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cn3Ls/btsKlk0r4E4/nPDToLHnxBUBERvKopVfk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cn3Ls/btsKlk0r4E4/nPDToLHnxBUBERvKopVfk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCn3Ls%2FbtsKlk0r4E4%2FnPDToLHnxBUBERvKopVfk0%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;631&quot; height=&quot;771&quot; data-filename=&quot;Screenshot 2024-10-25 at 21.53.49.png&quot; data-origin-width=&quot;631&quot; data-origin-height=&quot;771&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;여기서 중요한 옵션은 memory 와 reservation 입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대중적으로 사용하길 reservation 의 2배를 memory 로 설정합니다&lt;br /&gt;&lt;br /&gt;memory 와 reservation 의 수치는 magic number 이므로 배포할 application 에 대해 모니터링 한뒤 세부조정을 하시는것을 추천 드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CPU 제한&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 각 컨테이너의 호스트 머신 CPU 사이클에 대한 액세스는 무제한 입니다.&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-10-25 at 21.58.30.png&quot; data-origin-width=&quot;621&quot; data-origin-height=&quot;767&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXu6hP/btsKkq71CMg/VkcrWpHxhVfZPm87dffQNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXu6hP/btsKkq71CMg/VkcrWpHxhVfZPm87dffQNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXu6hP/btsKkq71CMg/VkcrWpHxhVfZPm87dffQNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXu6hP%2FbtsKkq71CMg%2FVkcrWpHxhVfZPm87dffQNk%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;621&quot; height=&quot;767&quot; data-filename=&quot;Screenshot 2024-10-25 at 21.58.30.png&quot; data-origin-width=&quot;621&quot; data-origin-height=&quot;767&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;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;CPU가 1개 있는 경우 다음 명령은 각각 1초마다 컨테이너가 최대 CPU의 50%를 사용하도록 보장합니다.&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_1729861139645&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; docker run -it --cpus=&quot;.5&quot; ubuntu /bin/bash&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;&lt;b&gt;주의해야할점&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;CPU 스케줄링 및 우선순위 지정은 고급 커널 수준 기능입니다. 대부분 사용자는 이러한 값을 기본값에서 변경할 필요가 없습니다. 이러한 값을 잘못 설정하면 호스트 시스템이 불안정해지거나 사용할 수 없게 될 수 있습니다.&lt;/span&gt;&lt;/span&gt;&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;&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;pre id=&quot;code_1729861251634&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;api:
  image: node:16-alpine
  container_name: backend-api
  deploy:
    resources:
      limits:
        cpus: '1'
        memory: 1G
      reservations:
        cpus: '0.5'
        memory: 512M
  environment:
    - NODE_ENV=production
    - MAX_OLD_SPACE_SIZE=768
  volumes:
    - type: volume
      source: api-storage
      target: /app/storage
      volume:
        nocopy: true
        size: 2G
  healthcheck:
    test: [&quot;CMD&quot;, &quot;wget&quot;, &quot;--quiet&quot;, &quot;--tries=1&quot;, &quot;--spider&quot;, &quot;http://localhost:3000/health&quot;]
    interval: 30s
    timeout: 10s
    retries: 3&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Docker</category>
      <category>CPU</category>
      <category>docker</category>
      <category>Limit</category>
      <category>memory</category>
      <author>jongyun ha</author>
      <guid isPermaLink="true">https://popawaw.tistory.com/344</guid>
      <comments>https://popawaw.tistory.com/344#entry344comment</comments>
      <pubDate>Fri, 25 Oct 2024 22:01:28 +0900</pubDate>
    </item>
    <item>
      <title>Leetcode - Gas Station</title>
      <link>https://popawaw.tistory.com/343</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Problem&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;There are&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;gas stations along a circular route, where the amount of gas at the&lt;span&gt;&amp;nbsp;&lt;/span&gt;ith&lt;span&gt;&amp;nbsp;&lt;/span&gt;station is&lt;span&gt;&amp;nbsp;&lt;/span&gt;gas[i].&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;You have a car with an unlimited gas tank and it costs&lt;span&gt;&amp;nbsp;&lt;/span&gt;cost[i]&lt;span&gt;&amp;nbsp;&lt;/span&gt;of gas to travel from the&lt;span&gt;&amp;nbsp;&lt;/span&gt;ith&lt;span&gt;&amp;nbsp;&lt;/span&gt;station to its next&lt;span&gt;&amp;nbsp;&lt;/span&gt;(i + 1)th&lt;span&gt;&amp;nbsp;&lt;/span&gt;station. You begin the journey with an empty tank at one of the gas stations.&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Given two integer arrays&lt;span&gt;&amp;nbsp;&lt;/span&gt;gas&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;cost, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return&lt;span&gt;&amp;nbsp;&lt;/span&gt;-1. If there exists a solution, it is&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;guaranteed&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;to be&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;unique&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
Output: 3
Explanation:
Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 4. Your tank = 4 - 1 + 5 = 8
Travel to station 0. Your tank = 8 - 2 + 1 = 7
Travel to station 1. Your tank = 7 - 3 + 2 = 6
Travel to station 2. Your tank = 6 - 4 + 3 = 5
Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3.
Therefore, return 3 as the starting index.
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #f0f0f0; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;background-color: #f0f0f0; color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Input: gas = [2,3,4], cost = [3,4,3]
Output: -1
Explanation:
You can't start at station 0 or 1, as there is not enough gas to travel to the next station.
Let's start at station 2 and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 0. Your tank = 4 - 3 + 2 = 3
Travel to station 1. Your tank = 3 - 3 + 3 = 3
You cannot travel back to station 2, as it requires 4 unit of gas but you only have 3.
Therefore, you can't travel around the circuit once no matter where you start.&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;h2 data-ke-size=&quot;size26&quot;&gt;Approach&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 문제는 시계방향으로 주유소를 돌면서 다시 제자리로 돌아올 수 있는지 확인하는 문제다.&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;&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;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;로컬 최적 해가 글로벌 최적 해로 이어짐&lt;/b&gt;: 문제의 구조상, 어떤 주유소에서 출발해 연료가 바닥나기 전에 다음 주유소에 도달할 수 있다면, 그 선택은 최적의 로컬 해이다. 이러한 로컬 최적의 선택들이 연속적으로 이어질 때 전체 경로를 완주할 수 있는 글로벌 최적 해를 구성한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연료의 누적 및 소비 패턴&lt;/b&gt;: 주유소에서 연료를 충전하고 다음 주유소로 이동하는 과정에서 연료의 누적과 소비가 일어난다. 그리디 알고리즘을 사용하면 각 단계에서 연료의 누적량과 소비량을 계산하여 현재 상태에서 가장 좋은 결정(다음 주유소로 이동할 수 있는지 여부)을 즉각적으로 내릴 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유일한 해의 존재&lt;/b&gt;: 문제에서는 해가 존재한다면 그 해가 유일하다고 명시되어 있다. 그리디 알고리즘을 사용하여 한 번의 순회로 출발 가능한 주유소를 찾아낼 수 있으며, 이는 문제의 조건과 일치한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;효율성&lt;/b&gt;: 모든 주유소를 순회하면서 현재 연료량과 각 주유소에서의 연료 충전량, 그리고 다음 주유소로의 이동 비용을 고려하여 그리디 알고리즘을 적용하면, O(n)의 시간 복잡도로 문제를 해결할 수 있다. 이는 대규모 데이터셋에도 효과적으로 작동하는 효율적인 접근 방식이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1709366147752&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func canCompleteCircuit(gas []int, cost []int) int {
	totalGas, totalCost, start, tank := 0, 0, 0, 0

	for i := 0; i &amp;lt; len(gas); i++ {
		currGas := gas[i]
		currCost := cost[i]

		totalGas += currGas
		totalCost += currCost
		tank += currGas - currCost
		if tank &amp;lt; 0 {
			start = i + 1
			tank = 0
		}
	}

	if totalCost &amp;gt; totalGas {
		return -1
	}

	return start
}&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;마지막에 totalCost 와 totalGas 를 비교하는 부분에 대해서 설명하자면 totalCost 가 totalGas 보다 큰경우 어떠한 주유소에서 시작해도 다시 제자리로 돌아올수 없기 때문에 start 값이 유효하지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러므로 -1 을 리턴한다.&lt;/p&gt;</description>
      <category>Algorithm</category>
      <category>Algorithm</category>
      <category>Gas Station</category>
      <category>go</category>
      <category>leetcode</category>
      <author>jongyun ha</author>
      <guid isPermaLink="true">https://popawaw.tistory.com/343</guid>
      <comments>https://popawaw.tistory.com/343#entry343comment</comments>
      <pubDate>Sat, 2 Mar 2024 16:57:39 +0900</pubDate>
    </item>
    <item>
      <title>Leetcode86. partition list (kotlin)</title>
      <link>https://popawaw.tistory.com/342</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/partition-list/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/partition-list/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1682158397734&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Partition List - LeetCode&quot; data-og-description=&quot;Can you solve this real interview question? Partition List - Given the head of a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. You should preserve the original relative order of the no&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/partition-list/&quot; data-og-url=&quot;https://leetcode.com/problems/partition-list/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/tsnnG/hySlKLlg5Y/AU5KIZ9Kl5k7JQVyV4xpEk/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/OvfMF/hySlGWtCB4/JKT8NMVnDBCrfmUI7Rost1/img.png?width=924&amp;amp;height=222&amp;amp;face=0_0_924_222,https://scrap.kakaocdn.net/dn/cjM5Wv/hySmZGTWsB/jhF2K3WzfKzfPHQXDM2BV0/img.jpg?width=662&amp;amp;height=222&amp;amp;face=0_0_662_222&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/partition-list/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/partition-list/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/tsnnG/hySlKLlg5Y/AU5KIZ9Kl5k7JQVyV4xpEk/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/OvfMF/hySlGWtCB4/JKT8NMVnDBCrfmUI7Rost1/img.png?width=924&amp;amp;height=222&amp;amp;face=0_0_924_222,https://scrap.kakaocdn.net/dn/cjM5Wv/hySmZGTWsB/jhF2K3WzfKzfPHQXDM2BV0/img.jpg?width=662&amp;amp;height=222&amp;amp;face=0_0_662_222');&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;Partition List - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Can you solve this real interview question? Partition List - Given the head of a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. You should preserve the original relative order of the no&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Given the&lt;span&gt;&amp;nbsp;&lt;/span&gt;head&lt;span&gt;&amp;nbsp;&lt;/span&gt;of a linked list and a value&lt;span&gt;&amp;nbsp;&lt;/span&gt;x, partition it such that all nodes&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;less than&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;x&lt;span&gt;&amp;nbsp;&lt;/span&gt;come before nodes&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;greater than or equal&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;to&lt;span&gt;&amp;nbsp;&lt;/span&gt;x.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;You should&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;preserve&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;the original relative order of the nodes in each of the two partitions.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVWEEX/btsbTpVXEwb/9tSIghU43g5xuVvPDTbVS0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVWEEX/btsbTpVXEwb/9tSIghU43g5xuVvPDTbVS0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVWEEX/btsbTpVXEwb/9tSIghU43g5xuVvPDTbVS0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVWEEX%2FbtsbTpVXEwb%2F9tSIghU43g5xuVvPDTbVS0%2Fimg.jpg&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;662&quot; height=&quot;222&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;222&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;pre id=&quot;code_1682158421915&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Input: head = [1,4,3,2,5,2], x = 3
Output: [1,2,2,4,3,5]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Approach&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제는 주어진 x 보다 작은 것들은 왼쪽 더 큰것들은 오른쪽으로 정렬 하는 문제입니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;x 보다 작은것들을 연결할 Listnode(lessNode) 를 만들고 x 보다 큰 것들을 연결할 LIstnode(moreNode) 를 만듭니다.&lt;/li&gt;
&lt;li&gt;head 를 iteration 하면서 x 보다 작으면 lessNode 의 next 로 Listnode(val) 을 추가하고 크다면 moreNode 의 next 로 Listnode(val) 을 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1682158642953&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun partition(head: ListNode, x: Int): ListNode? {
    val lessHead = ListNode(-1)
    val moreHead = ListNode(-1)
    var less = lessHead
    var more = moreHead
    var node: ListNode? = head
    while (node != null) {
        if (node.`val` &amp;lt; x) {
            less.next = ListNode(node.`val`)
            less = less.next!!
        } else {
            more.next = ListNode(node.`val`)
            more = more.next!!
        }
        node = node.next
    }

    less.next = moreHead.next

    return lessHead.next
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/leetcode</category>
      <category>leetcode</category>
      <category>partition list</category>
      <category>twopoint</category>
      <author>jongyun ha</author>
      <guid isPermaLink="true">https://popawaw.tistory.com/342</guid>
      <comments>https://popawaw.tistory.com/342#entry342comment</comments>
      <pubDate>Sat, 22 Apr 2023 19:18:17 +0900</pubDate>
    </item>
    <item>
      <title>Leetcode79. Word Search (w. kotlin)</title>
      <link>https://popawaw.tistory.com/341</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Given an&lt;span&gt;&amp;nbsp;&lt;/span&gt;m x n&lt;span&gt;&amp;nbsp;&lt;/span&gt;grid of characters&lt;span&gt;&amp;nbsp;&lt;/span&gt;board&lt;span&gt;&amp;nbsp;&lt;/span&gt;and a string&lt;span&gt;&amp;nbsp;&lt;/span&gt;word, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;true&lt;span&gt;&amp;nbsp;&lt;/span&gt;if&lt;span&gt;&amp;nbsp;&lt;/span&gt;word&lt;span&gt;&amp;nbsp;&lt;/span&gt;exists in the grid.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;The word can be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #262626; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;322&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KNFvL/btsamXsp0OV/V1QZao1KCKcD7Uk2r47oMk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KNFvL/btsamXsp0OV/V1QZao1KCKcD7Uk2r47oMk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KNFvL/btsamXsp0OV/V1QZao1KCKcD7Uk2r47oMk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKNFvL%2FbtsamXsp0OV%2FV1QZao1KCKcD7Uk2r47oMk%2Fimg.jpg&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;322&quot; height=&quot;242&quot; data-origin-width=&quot;322&quot; data-origin-height=&quot;242&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;pre id=&quot;code_1681624091679&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val board = [[&quot;A&quot;,&quot;B&quot;,&quot;C&quot;,&quot;E&quot;],[&quot;S&quot;,&quot;F&quot;,&quot;C&quot;,&quot;S&quot;],[&quot;A&quot;,&quot;D&quot;,&quot;E&quot;,&quot;E&quot;]]
val word = &quot;SEE&quot;

Output: true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Approach&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제는 Backtracking 을 사용하여 상하좌우 의 문자열을 이어 나가면서 기대하는 Word 와 일치 하는지 에 대한 결과를 구하는 문제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;word = &quot;SEE&quot; 중 S 가 위치한 (row, col) 값을 찾습니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;(1, 0) 에 위치한 S 의 상하좌우 를 DFS 로 탐색합니다. 방문한 곳은 board 에 &quot;*&quot; 로 마킹합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;LEFT (index 를 벗어남) , RIGHT(F 유효하지않음), UP(A 유효하지 않음), DOWN(A 유효하지 않음) 상하좌우 모두 유효하지 않기 때문에 넘어갑니다.&lt;/li&gt;
&lt;li&gt;&quot;*&quot; 로 마킹 한 곳은 다시 문자열을 채워줍니다.&lt;/li&gt;
&lt;li&gt;(1, 3) 에 위치한 S 를 상하좌우 를 DFS 로 탐색합니다. DOWN 에 위치한 (E) 가 유효 하고 E 로 DFS 탐색을 했을시 LEFT 가 유효하여 true 가 retrun 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681624484806&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun exist(board: Array&amp;lt;CharArray&amp;gt;, word: String): Boolean {
    if (board.isEmpty()) return false
    if (word.isBlank()) return true

    val checker = Array(board.size) { BooleanArray(board.first().size) }
    for (i in board.indices) {
        for (j in board[i].indices) {
            if (helper(board, checker, word, i, j, 0)) {
                return true
            }
        }
    }
    return false
}

fun helper(
    board: Array&amp;lt;CharArray&amp;gt;,
    checker: Array&amp;lt;BooleanArray&amp;gt;,
    word: String,
    row: Int,
    col: Int,
    start: Int
): Boolean {
    if (start == word.length) return true
    if (!isValid(row, col, board) || board[row][col] != word[start]) return false

    board[row][col] = '*'
    val result = helper(board, checker, word, row + 1, col, start + 1) ||
            helper(board, checker, word, row - 1, col, start + 1) ||
            helper(board, checker, word, row, col + 1, start + 1) ||
            helper(board, checker, word, row, col - 1, start + 1)
    board[row][col] = word[start]
    return result
}

fun isValid(row: Int, col: Int, board: Array&amp;lt;CharArray&amp;gt;): Boolean {
    return row in (board.indices) &amp;amp;&amp;amp; col in (board.first().indices)
}

fun main() {
    val board = arrayOf(
        charArrayOf('A', 'B', 'C', 'E'),
        charArrayOf('S', 'F', 'C', 'S'),
        charArrayOf('A', 'D', 'E', 'E'),
    )
    val word = &quot;ABCCED&quot;
    exist(board, word).also { println(it) }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/leetcode</category>
      <category>Kotlin</category>
      <category>leetcode</category>
      <category>leetcode79</category>
      <category>Word Search</category>
      <author>jongyun ha</author>
      <guid isPermaLink="true">https://popawaw.tistory.com/341</guid>
      <comments>https://popawaw.tistory.com/341#entry341comment</comments>
      <pubDate>Sun, 16 Apr 2023 14:55:17 +0900</pubDate>
    </item>
    <item>
      <title>Kubenetes 배포시 5xx 이슈에 대한 해결책</title>
      <link>https://popawaw.tistory.com/339</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스를 사용하여 어플리케이션을 배포 할때 5xx 에러를 만날때가 있다. 제일 처음으로 확인해볼건 probe 설정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;livenessProbe&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너가 동작 중인지 여부를 나타낸다. 만약 활성 프로브(liveness probe)에 실패한다면, kubelet은 컨테이너를 죽이고,&lt;br /&gt;해당 컨테이너는&amp;nbsp;&lt;a href=&quot;https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy&quot;&gt;재시작 정책&lt;/a&gt; 의 대상이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 컨테이너가 활성 프로브를 제공하지 않는 경우, 기본 상태는&amp;nbsp;Success&amp;nbsp;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;readnessProbe&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너가 요청을 처리할 준비가 되었는지 여부를 나타낸다. 만약 준비성 프로브(readiness probe)가 실패한다면, 엔드포인트 컨트롤러는 파드에 연관된 모든 서비스들의 엔드포인트에서 파드의 IP주소를 제거한다. 준비성 프로브의 초기 지연 이전의 기본 상태는&amp;nbsp;Failure이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 컨테이너가 준비성 프로브를 지원하지 않는다면, 기본 상태는&amp;nbsp;Success이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;startupProbe&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스를 시작하는 데 오랜 시간이 걸리거나 불규칙적인 컨테이너에 설정하는 데 사용될 수 있다.(예를 들면 third party 에서 특정 데이터를 다운받는 등의 경우) startup probe가 성공하고 나서 liveness, readiness probe가 동작하기 때문에 기동시간이 불규칙적인 애플리케이션이 liveness probe에 의해 기동되기도 전에 재시작 되는 것을 방지할 수 있다.(Readiness probe랑 비슷하지만 방금 말한 부분은 Readiness probe로 해결하기 어렵다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;livenessProbe 와 readnessProbe 의 차이점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너의 상태 체크중에 livenessProbe 의 경우에는 컨테이너가 비정상적으로 작동이 불가능한 경우도 있지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Configuration을 로딩하거나, 많은 데이타를 로딩하거나, 외부 서비스를 호출하는 경우에는 일시적으로 서비스가 불가능한 상태가 될 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우에는 컨테이너를 재시작한다 하더라도 정상적으로 서비스가 불가능할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우에는 컨테이너를 일시적으로 서비스가 불가능한 상태로 마킹해주면 되는데, 이러한 기능을 readnessProbe 가 담당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bcho.tistory.com/1264&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://bcho.tistory.com/1264&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1679665615013&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;쿠버네티스 #9 - HealthCheck&quot; data-og-description=&quot;쿠버네티스 #9Health Check 조대협 (http://bcho.tistory.com) 쿠버네티스는 각 컨테이너의 상태를 주기적으로 체크해서, 문제가 있는 컨테이너를 자동으로 재시작하거나 또는 문제가 있는 컨테이너(Pod를) &quot; data-og-host=&quot;bcho.tistory.com&quot; data-og-source-url=&quot;https://bcho.tistory.com/1264&quot; data-og-url=&quot;https://bcho.tistory.com/1264&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/do3h7P/hyR2Wi8y27/baHZxizeSiN86jGPxmCrLK/img.png?width=800&amp;amp;height=173&amp;amp;face=0_0_800_173,https://scrap.kakaocdn.net/dn/dh8Zpm/hyR2KbXgUf/TVmLdmqrdymJ78JZ6dITVK/img.png?width=800&amp;amp;height=173&amp;amp;face=0_0_800_173,https://scrap.kakaocdn.net/dn/BmjFy/hyR2G8sYsJ/tpmtV6eFfOzKOTIk3uBNuk/img.png?width=1242&amp;amp;height=436&amp;amp;face=0_0_1242_436&quot;&gt;&lt;a href=&quot;https://bcho.tistory.com/1264&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://bcho.tistory.com/1264&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/do3h7P/hyR2Wi8y27/baHZxizeSiN86jGPxmCrLK/img.png?width=800&amp;amp;height=173&amp;amp;face=0_0_800_173,https://scrap.kakaocdn.net/dn/dh8Zpm/hyR2KbXgUf/TVmLdmqrdymJ78JZ6dITVK/img.png?width=800&amp;amp;height=173&amp;amp;face=0_0_800_173,https://scrap.kakaocdn.net/dn/BmjFy/hyR2G8sYsJ/tpmtV6eFfOzKOTIk3uBNuk/img.png?width=1242&amp;amp;height=436&amp;amp;face=0_0_1242_436');&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;쿠버네티스 #9 - HealthCheck&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;쿠버네티스 #9Health Check 조대협 (http://bcho.tistory.com) 쿠버네티스는 각 컨테이너의 상태를 주기적으로 체크해서, 문제가 있는 컨테이너를 자동으로 재시작하거나 또는 문제가 있는 컨테이너(Pod를)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;bcho.tistory.com&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;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정상적으로 Probe 를 구성했음에도 배포시 5xx 에러가 발생할때&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pod 가 생성될때 5xx 에러가 발생한다면 probe 설정이 잘못된건 없는지 확인한다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS ALB(ingress) 를 사용하고 있다면 배포 과정에서 pod 와의 연결이 정상적으로 끊기지 전달 되었거나 또는 신규 Pod 들의 Ready 상태가 반영 되지않고 ALB Target group 에 대상이 등록된 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 개선하기 위해선 preStop 실행 과정에서 sleep 을 사용하여 pod 의 애플리케이션이 정상적으로 기존연결을 끊는지 확인이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Pod 의 readniess 상태를 AWS Loadbalancer Controller 에서 TargetGroup 에 Pod IP 들을 등록하는 과정에서 Readniess probe 상태를 반영하며 작동할 수 있게 하는 Readniess gate 설정도 반드시 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.1/deploy/pod_readiness_gate/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.1/deploy/pod_readiness_gate/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1679665962332&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Pod Readiness Gate - AWS LoadBalancer Controller&quot; data-og-description=&quot;Pod readiness gate AWS Load Balancer controller supports &amp;raquo;Pod readiness gates&amp;laquo; to indicate that pod is registered to the ALB/NLB and healthy to receive traffic. The controller automatically injects the necessary readiness gate configuration to the pod sp&quot; data-og-host=&quot;kubernetes-sigs.github.io&quot; data-og-source-url=&quot;https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.1/deploy/pod_readiness_gate/&quot; data-og-url=&quot;https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.1/deploy/pod_readiness_gate/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.1/deploy/pod_readiness_gate/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.1/deploy/pod_readiness_gate/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;Pod Readiness Gate - AWS LoadBalancer Controller&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Pod readiness gate AWS Load Balancer controller supports &amp;raquo;Pod readiness gates&amp;laquo; to indicate that pod is registered to the ALB/NLB and healthy to receive traffic. The controller automatically injects the necessary readiness gate configuration to the pod sp&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kubernetes-sigs.github.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;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 살펴볼건 Pod 의 application 의 keep alive 설정이 ALB 의 IDLE Timeout 보다 짧게 설정된건 아닌지 확인해볼것&lt;/p&gt;</description>
      <category>Docker</category>
      <category>502</category>
      <category>504</category>
      <category>alb</category>
      <category>K8s</category>
      <category>Probe</category>
      <category>readniess</category>
      <author>jongyun ha</author>
      <guid isPermaLink="true">https://popawaw.tistory.com/339</guid>
      <comments>https://popawaw.tistory.com/339#entry339comment</comments>
      <pubDate>Fri, 24 Mar 2023 22:54:06 +0900</pubDate>
    </item>
    <item>
      <title>spring boot jib 를 사용 하여 배포 자동화 하기 (w. github action)</title>
      <link>https://popawaw.tistory.com/338</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;jib 란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jib는 Dockerfile을 사용하지 않거나 Docker를 설치할 필요 없이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;컨테이너를 빌드할 수 있도록 도와주는 도구&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 자바 컨테이너를 빌드하는 데 사용하는 도구이며, Maven과 Gradle 용 플러그인을 이용해 사용할 수도 있고 Jib 자바 라이브러리를 통해 사용할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;적용해보기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;build.gradle.kts&lt;/p&gt;
&lt;pre id=&quot;code_1679564230113&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plugin {
...
	id(&quot;com.google.cloud.tools.jib&quot;) version &quot;3.1.2&quot; apply false
...
}&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;버전은 해당 spring boot, kotlin, java 버전에 맞게 설정 이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1679564305027&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val stage: String? by project // github action 에서 -Pstage=alpha 옵션으로 주입
val imageTag: String? by project // github action 에서 -PimageTag=AA-BB 옵션으로 주입

jib {
	from {} // 애플리케이션을 빌드할 기본 이미지를 구성
	to {} // 애플리케이션을 빌드할 대상 이미지를 구성
	extraDirectories {} // 이미지에 임의의 파일을 추가하는 데 사용되는 디렉토리를 구성
	container {} // 빌드된 이미지에서 실행되는 컨테이너를 구성
	mainClass = &quot;&quot;
	user = &quot;&quot;
	ports = &quot;&quot; // Dockerfile 의 EXPOSE 와 유사
	creationTime = &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;github action 에서 환경과 imageTag 이름을 주입하기 위해 따로 변수를 생성한다.&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;github action&lt;/p&gt;
&lt;pre id=&quot;code_1679564467192&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- name: Build tag, and push image with jib
  id: build-image
  run: |
    ./gradlew -PcontainerImage=${{ env.DOCKER_REPOSITORY }} -PimageTag=${{ env.IMAGE_TAG }} -Pstage=${{ env.PHASE }} jib --no-daemon&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;테스트 환경에서는 ECR 을 사용하여 docker image 를 관리하고 jib 에 다음과 같이 설정했다.&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;credHelper = &quot;ecr-login&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;jvm custom option&lt;/h2&gt;
&lt;pre id=&quot;code_1679564702029&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;container {
    jvmFlags = when (stage) {
        &quot;dev&quot; -&amp;gt; listOf(&quot;-Xms4g&quot;, &quot;-Xmx4g&quot;)
        &quot;prod&quot; -&amp;gt; listOf(&quot;-Xms8g&quot;, &quot;-Xmx8g&quot;)
        else -&amp;gt; emptyList()
    }

    environment = mapOf(&quot;port&quot; to 8080)
    mainClass = mainClassPath
    user = &quot;user&quot;
    ports = listOf(8080)
    creationTime = containerCreationTime
}&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;체감상 docker build 에서 jib 로 바꾼뒤 캐시가 적중했을때 1분 가까이 차이가 나기도 한다.&lt;/p&gt;</description>
      <category>Kotlin/Spring</category>
      <category>docker</category>
      <category>Jib</category>
      <category>spring boot</category>
      <author>jongyun ha</author>
      <guid isPermaLink="true">https://popawaw.tistory.com/338</guid>
      <comments>https://popawaw.tistory.com/338#entry338comment</comments>
      <pubDate>Thu, 23 Mar 2023 18:46:13 +0900</pubDate>
    </item>
    <item>
      <title>CloudFront 와 Browser cache</title>
      <link>https://popawaw.tistory.com/337</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Cloud front 란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1669458589902&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Amazon CloudFront란 무엇입니까? - Amazon CloudFront&quot; data-og-description=&quot;Amazon CloudFront란 무엇입니까? Amazon CloudFront는 .html, .css, .js 및 이미지 파일과 같은 정적 및 동적 웹 콘텐츠를 사용자에게 더 빨리 배포하도록 지원하는 웹 서비스입니다. CloudFront는 엣지 로케이션&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot; data-og-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eR4eo/hyQH7NozYy/0KZ7w0Eke4CvudaloQhbrk/img.png?width=598&amp;amp;height=500&amp;amp;face=0_0_598_500&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Introduction.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eR4eo/hyQH7NozYy/0KZ7w0Eke4CvudaloQhbrk/img.png?width=598&amp;amp;height=500&amp;amp;face=0_0_598_500');&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;Amazon CloudFront란 무엇입니까? - Amazon CloudFront&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Amazon CloudFront란 무엇입니까? Amazon CloudFront는 .html, .css, .js 및 이미지 파일과 같은 정적 및 동적 웹 콘텐츠를 사용자에게 더 빨리 배포하도록 지원하는 웹 서비스입니다. CloudFront는 엣지 로케이션&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;cloud front 설정의 cache 의 TTL 을 설정할때 min, max default 값이 있따는 것은 Origin (s3) 에서 보낸 Metadata 의 Cache-Control 값을 존중해서 사용한다는 뜻입니다.&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;cloud front 의 Min 보다 작은 값을 Origin 에서 보내오면 min 값을 TTL 값으로 사용하겠다는 뜻이며, cloud front 의 max 값 보다 큰 값을 Origin 에서 보내오면 max 값을 TTL 값으로 사용한다는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, Origin 에서 특정한 Cache-Control 값이 없으면 Default 값을 사용한다는 뜻입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TTL 이 긴데도 불구하고 Cache Miss 가 나는 경우&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처음 요청하는 Object 인 경우&lt;/li&gt;
&lt;li&gt;해당 Region 의 edge 서버 들에 부하가 있어 다른 region 으로 라우팅 되었을 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cache 는 region 별로 달리 저장되기 때문에 다른 region 으로 라우팅 되면 miss 가 발생 할 수 있음&lt;/li&gt;
&lt;/ul&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;cloud front 의 설정은 origin server 의 데이터를 캐싱하는 설정이고 client 에서 ttl 시간 내에 반복적으로 보내온 요청을 origin server 에 물어보지 않고 바로 cloud front 가 처리함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;web browser 가 캐싱 했다가 cf 에 다시 요청해야 하는 기간 TTL 이 만료되고 브라우저에서 CF 로 요청 CF 에 캐싱이 없으면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;origin server 로 요청 customize 로 설정되어 있는 경우 origin server 의 cache control 을 최대한 존중&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Use origin cache headers 일 경우 cache-control 을 그대로 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Status code [200, 304]&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;200 - hit from cloud front&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;304 - hit from cloud front&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#ExpirationDownloadDist&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#ExpirationDownloadDist&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1669460058670&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;콘텐츠가 캐시에 유지되는 기간(만료) 관리 - Amazon CloudFront&quot; data-og-description=&quot;CloudFront가 Cache-Control: no-cache, no-store 및/또는 private 지시문이 포함된 오리진에서 객체를 가져온 다음 나중에 동일한 객체에 대한 다른 최종 사용자 요청을 가져오는 경우 CloudFront는 오리진에 연&quot; data-og-host=&quot;docs.aws.amazon.com&quot; data-og-source-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#ExpirationDownloadDist&quot; data-og-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#ExpirationDownloadDist&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#ExpirationDownloadDist&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/Expiration.html#ExpirationDownloadDist&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;콘텐츠가 캐시에 유지되는 기간(만료) 관리 - Amazon CloudFront&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CloudFront가 Cache-Control: no-cache, no-store 및/또는 private 지시문이 포함된 오리진에서 객체를 가져온 다음 나중에 동일한 객체에 대한 다른 최종 사용자 요청을 가져오는 경우 CloudFront는 오리진에 연&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.aws.amazon.com&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 문서에 따르면 cache-control 이 없으면 browser 에 대한 cache 는 browser 마다 각각 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CF 설정은 TTL 은 cloud front 단에서 관리하는 캐시 설정이므로 browser 에서 캐싱이 만료되면 cf로 요청한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CF 에서 아직 캐싱이 유요하다면 cache hit 이고 cloud front 에 캐싱 된 object etag 와 비교하여 변경된게 없으면 304 status 를 response 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1669460225103&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Browser Request Header
- cache-control: max-age=0 
- if-modified-since: Tue, 27 Sep 2022 02:37:48 GMT
- if-none-match: &quot;7ajsdklfjalskdnvklznxcklvjlzdksjfkla&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;본 헤더의 의미는 Browser에 컨텐츠가 캐시되어 있으며, Browser에 캐시된 컨텐츠를 사용하기 위해 유효한지 확인을 위해 브라우저-&amp;gt;CloudFront로 유효성 검사 요청입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(if-modified-since, if-none-match은 이전에 컨텐츠가 수신/캐시되었을때 응답 헤더에서 확인된 Last-modified, Etag 값 이용)&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;CloudFront에서는 유효성 검사시 위의 값을 비교하여&lt;span&gt;&amp;nbsp; &lt;/span&gt;결과가 유효한 경우 304 Not modified로 응답 헤더만 전달하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유효하지 않은 경우 200 OK로 신규 컨텐츠 전달합니다.&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&gt;해당&lt;/span&gt; &lt;span&gt;요청을&lt;/span&gt; &lt;span&gt;보낸&lt;/span&gt; &lt;span&gt;주체는&lt;/span&gt; Browser&lt;span&gt;이며&lt;/span&gt;, &lt;span&gt;그&lt;/span&gt; &lt;span&gt;요청을&lt;/span&gt; &lt;span&gt;수신하여&lt;/span&gt; &lt;span&gt;맞는&lt;/span&gt; &lt;span&gt;응답을&lt;/span&gt; &lt;span&gt;전달한&lt;/span&gt; &lt;span&gt;것은&lt;/span&gt; CloudFront&lt;span&gt;의&lt;/span&gt; PoP&lt;span&gt;입니다&lt;/span&gt;.&lt;/p&gt;</description>
      <category>Cloud/AWS</category>
      <category>browser cache</category>
      <category>cache</category>
      <category>cloud front</category>
      <category>HTTP</category>
      <category>Status Code</category>
      <author>jongyun ha</author>
      <guid isPermaLink="true">https://popawaw.tistory.com/337</guid>
      <comments>https://popawaw.tistory.com/337#entry337comment</comments>
      <pubDate>Sat, 26 Nov 2022 19:58:08 +0900</pubDate>
    </item>
  </channel>
</rss>