<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자 배트맨의 일상 </title>
    <link>https://g-batman.tistory.com/</link>
    <description>여기에라도 쓰면 내 머리에도 저장이 될까 싶어서..</description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 14:09:38 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>G_Batman</managingEditor>
    <image>
      <title>개발자 배트맨의 일상 </title>
      <url>https://tistory1.daumcdn.net/tistory/5519680/attach/4382f1f6cd414882a915e1e8eaa1d7c4</url>
      <link>https://g-batman.tistory.com</link>
    </image>
    <item>
      <title>[PostgreSQL] DB 복제하기</title>
      <link>https://g-batman.tistory.com/93</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;hmmm-thinking.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;343&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JrnEh/dJMcabXa2IF/XhSE1yt9kNK46fiz2gJXQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JrnEh/dJMcabXa2IF/XhSE1yt9kNK46fiz2gJXQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JrnEh/dJMcabXa2IF/XhSE1yt9kNK46fiz2gJXQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJrnEh%2FdJMcabXa2IF%2FXhSE1yt9kNK46fiz2gJXQk%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;498&quot; height=&quot;343&quot; data-filename=&quot;hmmm-thinking.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;343&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-end=&quot;455&quot; data-start=&quot;237&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;324&quot; data-start=&quot;239&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Production 서버와 Staging 서버를 동시에 운영하다 보면&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;두 DB의 sync를 맞춰야 하는 경우가 발생한다. 현재 운영 중인 서버에서 비슷한 경우가 반복되어&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;스스로 보려고 정리하는 포스팅&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;473&quot; data-start=&quot;462&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;EC2 to EC2&lt;/b&gt;와 &lt;b&gt;EC2 to Local&lt;/b&gt; 모두 가능하니 &lt;span style=&quot;background-color: #ef5369; color: #ffffff;&quot;&gt;&lt;b&gt;EC2 to Local을 기준&lt;/b&gt;&lt;/span&gt;으로 정리&lt;/p&gt;
&lt;h2 data-end=&quot;473&quot; data-start=&quot;462&quot; data-ke-size=&quot;size26&quot;&gt;  환경 요약&lt;/h2&gt;
&lt;h3 data-end=&quot;482&quot; data-start=&quot;475&quot; data-ke-size=&quot;size23&quot;&gt;Production Server&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;573&quot; data-start=&quot;483&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;491&quot; data-start=&quot;483&quot;&gt;Ubuntu&lt;/li&gt;
&lt;li data-end=&quot;521&quot; data-start=&quot;492&quot;&gt;PostgreSQL 16 (Docker 컨테이너)&lt;/li&gt;
&lt;li data-end=&quot;537&quot; data-start=&quot;522&quot;&gt;컨테이너 이름: pg (예시)&lt;/li&gt;
&lt;li data-end=&quot;554&quot; data-start=&quot;538&quot;&gt;DB 이름: appdb&lt;/li&gt;
&lt;li data-end=&quot;573&quot; data-start=&quot;555&quot;&gt;DB 유저: appuser&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;584&quot; data-start=&quot;575&quot; data-ke-size=&quot;size23&quot;&gt;Local&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;678&quot; data-start=&quot;585&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;626&quot; data-start=&quot;585&quot;&gt;Windows + Docker Desktop (Linux engine)&lt;/li&gt;
&lt;li data-end=&quot;656&quot; data-start=&quot;627&quot;&gt;PostgreSQL 16 (Docker 컨테이너)&lt;/li&gt;
&lt;li data-end=&quot;537&quot; data-start=&quot;522&quot;&gt;컨테이너 이름: pg_local (예시)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;721&quot; data-start=&quot;685&quot; data-ke-size=&quot;size26&quot;&gt;1️⃣ EC2에서 &lt;b&gt;plain SQL&lt;/b&gt;로 DB 덤프 뜨기&lt;/h2&gt;
&lt;blockquote data-end=&quot;807&quot; data-start=&quot;723&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;807&quot; data-start=&quot;740&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;784&quot; data-start=&quot;757&quot;&gt;단순 SQL 텍스트로 덤프 (.sql)&lt;/li&gt;
&lt;li data-end=&quot;807&quot; data-start=&quot;787&quot;&gt;파일 크기로 정상 여부 판단&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 data-end=&quot;820&quot; data-start=&quot;809&quot; data-ke-size=&quot;size23&quot;&gt;EC2&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767512459483&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -t pg pg_dump -U appuser -d appdb &amp;gt; appdb.sql&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;910&quot; data-start=&quot;892&quot; data-ke-size=&quot;size23&quot;&gt;덤프 파일 크기 확인&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767512563264&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;ls -lh appdb.sql&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-end=&quot;982&quot; data-start=&quot;941&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;958&quot; data-start=&quot;941&quot;&gt;대략 100 KB ~ &lt;b&gt;수 MB 이상&lt;/b&gt; &amp;rarr; 정상&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;1017&quot; data-start=&quot;989&quot; data-ke-size=&quot;size26&quot;&gt;2️⃣ EC2 &amp;rarr; 로컬로 SQL 파일 가져오기&lt;/h2&gt;
&lt;h3 data-end=&quot;1036&quot; data-start=&quot;1019&quot; data-ke-size=&quot;size23&quot;&gt;로컬 PowerShell&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767512707603&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;scp -i &quot;C:\path\to\key.pem&quot; ubuntu@&amp;lt;EC2_PUBLIC_IP&amp;gt;:/home/ubuntu/appdb.sql &quot;Path to local Project&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;1302&quot; data-start=&quot;1274&quot; data-ke-size=&quot;size26&quot;&gt;3️⃣ 로컬 PostgreSQL 컨테이너 실행&lt;/h2&gt;
&lt;blockquote data-end=&quot;1349&quot; data-start=&quot;1304&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1349&quot; data-start=&quot;1306&quot; data-ke-size=&quot;size16&quot;&gt;로컬에 PostgreSQL이 없다면 Docker로 실행하는 게 가장 깔끔하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767512804462&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d --name {pg_local} ` -e POSTGRES_DB={appdb} ` -e POSTGRES_USER={appuser} ` -e POSTGRES_PASSWORD={localpass} ` -p 5432:5432 ` -v pg_local_data:/var/lib/postgresql/data ` postgres:16&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1571&quot; data-start=&quot;1568&quot; data-ke-size=&quot;size16&quot;&gt;확인&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767513268116&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker ps&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;1629&quot; data-start=&quot;1606&quot; data-ke-size=&quot;size26&quot;&gt;4️⃣ SQL 파일을 컨테이너로 복사&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767513821299&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker cp &quot;Path\Local\project\appdb.sql&quot; pg_local:/tmp/appdb.sql&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1714&quot; data-start=&quot;1708&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1714&quot; data-start=&quot;1708&quot; data-ke-size=&quot;size16&quot;&gt;확인&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767513879913&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -it pg_local ls -lh /tmp/appdb.sql&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;1804&quot; data-start=&quot;1786&quot; data-ke-size=&quot;size26&quot;&gt;5️⃣ psql로 DB 복원&lt;/h2&gt;
&lt;blockquote data-end=&quot;1855&quot; data-start=&quot;1806&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1855&quot; data-start=&quot;1808&quot; data-ke-size=&quot;size16&quot;&gt;pg_restore ❌&lt;br /&gt;&lt;b&gt;plain SQL은 psql로 복원해야 한다&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767513909682&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -it pg_local psql -U appuser -d appdb -f /tmp/appdb.sql&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;1967&quot; data-start=&quot;1949&quot; data-ke-size=&quot;size26&quot;&gt;6️⃣ 복원 성공 여부 확인&lt;/h2&gt;
&lt;h3 data-end=&quot;1982&quot; data-start=&quot;1969&quot; data-ke-size=&quot;size23&quot;&gt;테이블 목록 확인&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767513919003&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -it pg_local psql -U appuser -d appdb -c &quot;\dt&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;2078&quot; data-start=&quot;2061&quot; data-ke-size=&quot;size23&quot;&gt;Django 프로젝트라면&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1767513935766&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -it pg_local psql -U appuser -d appdb -c &quot;select count(*) from django_migrations;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2307&quot; data-start=&quot;2280&quot; data-ke-size=&quot;size16&quot;&gt;정상적으로 row 수가 나오면 &lt;b&gt;복제 완료&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-end=&quot;2332&quot; data-start=&quot;2314&quot; data-ke-size=&quot;size26&quot;&gt;❗ 자주 겪은 문제&lt;/h2&gt;
&lt;h3 data-end=&quot;2365&quot; data-start=&quot;2334&quot; data-ke-size=&quot;size23&quot;&gt;pg_restore: end of file&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2433&quot; data-start=&quot;2366&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2402&quot; data-start=&quot;2366&quot;&gt;원인: custom format dump 손상 or 잘린 파일&lt;/li&gt;
&lt;li data-end=&quot;2433&quot; data-start=&quot;2403&quot;&gt;해결: &lt;b&gt;plain SQL 방식으로 다시 덤프&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;2464&quot; data-start=&quot;2435&quot; data-ke-size=&quot;size23&quot;&gt;PowerShell에서 \ 줄 바꿈 에러&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2518&quot; data-start=&quot;2465&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2489&quot; data-start=&quot;2465&quot;&gt;PowerShell은 \ 지원 안 함&lt;/li&gt;
&lt;li data-end=&quot;2518&quot; data-start=&quot;2490&quot;&gt;&lt;b&gt;한 줄 명령&lt;/b&gt; 또는 &lt;b&gt;백틱(`)&lt;/b&gt; 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>db</category>
      <category>PostgreSQL</category>
      <author>G_Batman</author>
      <guid isPermaLink="true">https://g-batman.tistory.com/93</guid>
      <comments>https://g-batman.tistory.com/93#entry93comment</comments>
      <pubDate>Sun, 4 Jan 2026 17:07:30 +0900</pubDate>
    </item>
    <item>
      <title>[Django] 배포 후 Admin 페이지 CSS 깨짐 현상</title>
      <link>https://g-batman.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;안녕하세요. 배트맨입니다. &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;hmmm-thinking.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;343&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w2g3Z/btsPyrfFQTj/THDssorc4pMUdTW4DwLOa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w2g3Z/btsPyrfFQTj/THDssorc4pMUdTW4DwLOa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w2g3Z/btsPyrfFQTj/THDssorc4pMUdTW4DwLOa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw2g3Z%2FbtsPyrfFQTj%2FTHDssorc4pMUdTW4DwLOa0%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;498&quot; height=&quot;343&quot; data-filename=&quot;hmmm-thinking.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;343&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Django&lt;/b&gt; 프로젝트를 Nginx와 Gunicorn으로 배포한 후, 다른 페이지는 정상적으로 보이지만 &lt;b&gt;Admin 페이지의 UI(CSS)만 깨져 보이는 현상&lt;/b&gt;에 대한 원인 분석 및 해결 과정.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;현상&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹사이트의 일반 페이지들은 CSS가 정상적으로 적용되어 보임.&lt;/li&gt;
&lt;li&gt;Django 관리자 페이지(/admin/)에 접속하면 CSS가 전혀 적용되지 않은 순수 HTML 페이지만 나타남.&lt;/li&gt;
&lt;li&gt;브라우저 개발자 도구(F12)의 '네트워크' 탭을 확인하면, admin 관련 CSS 파일들이 404 (Not Found) 오류를 반환함.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;원인 분석&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; collectstatic 명령어는 프로젝트의 모든 정적 파일(앱 내부의 파일 + Django 자체의 admin용 파일)을 하나의 디렉토리(예: /home/ubuntu/project/staticfiles/)로 모은다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; Nginx는 /static/ URL로 들어오는 요청을 이 디렉토리로 연결해줘야 하는데, nginx 설정 파일에서 이 부분이 잘못되면 파일을 찾지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; Nginx가 Django Admin의 정적 파일을 찾지 못하기 때문이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;진단 과정&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;collectstatic 실행 여부 확인 &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저, admin의 정적 파일들이 staticfiles 디렉토리에 제대로 복사되었는지 확인한다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;ls -l [STATIC_ROOT 경로]/admin/css/
ls -l /home/ubuntu/[project]/staticfiles/admin/css/
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과: 첫 번째 명령어에서 base.css, dark_mode.css 등 다수의 CSS 파일 목록이 정상적으로 출력됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; collectstatic 명령어는 성공적으로 실행되었고, 파일 자체는 올바른 위치에 존재한다.&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: #009a87;&quot;&gt;&lt;b&gt;Nginx 설정 파일 확인&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 적용된 Nginx 설정 내용에서 static 파일 처리 로직을 점검한다.&lt;/p&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;cat /etc/nginx/sites-available/[project]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ 확인된 설정 (문제의 원인):&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;location /static/ {
   root /home/ubuntu/[project]/staticfiles/;
}
&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;Nginx의 root 지시어는 요청된 URI를 root 경로 뒤에 그대로 이어 붙인다.&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;요청 URL: &lt;br /&gt;/static/admin/css/base.css&lt;/li&gt;
&lt;li&gt;Nginx가 찾는 파일 경로: &lt;br /&gt;/home/ubuntu/[project]/staticfiles/ + /static/admin/css/base.css&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;/home/ubuntu/ [project] /staticfiles/static/admin/css/base.css 라는 잘못된 경로를 찾게 되므로 404 오류가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  해결:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nginx의 location 블록에서 root 대신 alias를 사용하여 정확한 경로를 매핑해준다.&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;sudo nano /etc/nginx/sites-available/[project]

# 수정 전:
location /static/ {
    root /home/ubuntu/[project]/staticfiles/;
}

# 수정 후:
location /static/ {
    alias /home/ubuntu/[project]/staticfiles/;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;결과&lt;/b&gt;&lt;/span&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;Admin 페이지의 CSS가 정상적으로 로드되어 UI가 잘 나온다!&lt;/p&gt;</description>
      <category>Backend/Django</category>
      <author>G_Batman</author>
      <guid isPermaLink="true">https://g-batman.tistory.com/92</guid>
      <comments>https://g-batman.tistory.com/92#entry92comment</comments>
      <pubDate>Thu, 24 Jul 2025 19:00:04 +0900</pubDate>
    </item>
    <item>
      <title>[무의도] 우당탕탕 백패킹 일지 | 무렝게티, 주차, 화장실, 편의점, 맛집 정보</title>
      <link>https://g-batman.tistory.com/91</link>
      <description>&lt;p data-end=&quot;248&quot; data-start=&quot;175&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요 배트맨 입니다.&lt;/p&gt;
&lt;p data-end=&quot;248&quot; data-start=&quot;175&quot; data-ke-size=&quot;size16&quot;&gt;살다 보면 계획대로 안 되는 일이 참 많죠.. 백패킹을 다니다 보면 그런 상황을 더 자주 마주하게 되는데 그런 경험이 기억에 더 오래 남는 것 같아요. 이번 포스팅도 우당탕탕 재미있을 테니 잘 봐주세요!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-end=&quot;265&quot; data-start=&quot;250&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;굴업도에 가보자 !! &lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-end=&quot;397&quot; data-start=&quot;267&quot; data-ke-size=&quot;size16&quot;&gt;한국 백패커라면 누구나 꿈꾼다는 &lt;b&gt;한국 백패킹 3대 명소가 있죠!&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;397&quot; data-start=&quot;267&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;제주 비양도&lt;/span&gt;, &lt;span style=&quot;color: #f89009;&quot;&gt;통영 소매물도&lt;/span&gt;, &lt;span style=&quot;color: #009a87;&quot;&gt;인천 굴업도&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;저는 비양도, 소매물도는 다녀왔는데 굴업도는 아직 못 가봤어요. 인기가 많아서 배편을 예약하기도 어려웠어요. 근데 2024년 12월부터 인천-굴업도 직항 배편이 생겨서 굴업도에 가는 게 조금은 더 쉬워졌어요. 그렇게 운 좋게 5월 10일-5월 12일 배편을 예매했는데, 당일에는 비 예보가 있었어요ㅋ.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1445&quot; data-origin-height=&quot;974&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wObUp/btsNWQ3ZMNn/3KkIuTvwgkDKj4ABwC6T90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wObUp/btsNWQ3ZMNn/3KkIuTvwgkDKj4ABwC6T90/img.png&quot; data-alt=&quot;What's in my bag&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wObUp/btsNWQ3ZMNn/3KkIuTvwgkDKj4ABwC6T90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwObUp%2FbtsNWQ3ZMNn%2F3KkIuTvwgkDKj4ABwC6T90%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;500&quot; height=&quot;337&quot; data-origin-width=&quot;1445&quot; data-origin-height=&quot;974&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;What's in my bag&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;397&quot; data-start=&quot;267&quot; data-ke-size=&quot;size16&quot;&gt;하루에도 몇 번씩 비 예보, 결항 여부, 바람 세기, 심지어 '구름 움직임'까지 체크한 저희는 &lt;b&gt;'이 정도면 뜨겠다'&lt;/b&gt;는 생각으로 준비를 했습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-end=&quot;397&quot; data-start=&quot;267&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;출바알!&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;p data-end=&quot;397&quot; data-start=&quot;267&quot; data-ke-size=&quot;size16&quot;&gt;아침 6시에 눈을 뜨고, 제일 먼저 날씨와 결항 여부 체크!&lt;/p&gt;
&lt;p data-end=&quot;397&quot; data-start=&quot;267&quot; data-ke-size=&quot;size16&quot;&gt;오케이 문제없어. 계획대로 추진해!&lt;/p&gt;
&lt;p data-end=&quot;397&quot; data-start=&quot;267&quot; data-ke-size=&quot;size16&quot;&gt;7시에 집을 나섰습니다.&lt;/p&gt;
&lt;p data-end=&quot;449&quot; data-start=&quot;399&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출발 2분 뒤.... 결항.....&lt;/b&gt;&lt;br /&gt;바로 갓길에 차 세우고, 0.3초 정적 후 한숨,,,&lt;/p&gt;
&lt;p data-end=&quot;449&quot; data-start=&quot;399&quot; data-ke-size=&quot;size16&quot;&gt;바로 대책회의 들어감. 궁평항을 가? 집에 가? 다른 데는 없나?&lt;/p&gt;
&lt;p data-end=&quot;477&quot; data-start=&quot;451&quot; data-ke-size=&quot;size16&quot;&gt;막 검색하다가 스쳐가는 섬 하나가 있는데, 바로&lt;/p&gt;
&lt;blockquote data-end=&quot;517&quot; data-start=&quot;479&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;498&quot; data-start=&quot;481&quot; data-ke-size=&quot;size16&quot;&gt;무의도.. &lt;br /&gt;&amp;ldquo;무의도는 한국의 세렝게티다.&amp;rdquo;&lt;/p&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;당장 가자. 무의도로.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-end=&quot;544&quot; data-start=&quot;524&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;무의도 도착&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;596&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오전 9시 무의도&lt;/b&gt;&amp;nbsp;도착.&lt;br /&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;백패킹을 가는 분들은 주차&lt;/span&gt;&lt;/b&gt;에 두 가지 선택지가 있어요.&lt;br /&gt;&lt;b&gt;1. 등산로 초입 바로 앞에 있는 '&lt;span style=&quot;color: #f89009;&quot;&gt;초록 카페&lt;/span&gt;' 앞 도로에 주차 자리가 있고, &lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;596&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 자리가 없다면 '무의광명항 공영주차장'&lt;/b&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&gt;&lt;iframe mapdata=&quot;addr=%EC%9D%B8%EC%B2%9C%20%EC%A4%91%EA%B5%AC%20%EB%AC%B4%EC%9D%98%EB%8F%99%209-11%201%EC%B8%B5&amp;amp;addtype=1&amp;amp;confirmid=164093094&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A374615%2C%22mapCenterY%22%3A1076908%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A374618%2C%22y%22%3A1076914%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%B4%88%EB%A1%9D%EC%B9%B4%ED%8E%98%22%2C%22confirmid%22%3A164093094%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=374615&amp;amp;mapY=1076908&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=2811063000&amp;amp;tel=&amp;amp;title=%EC%B4%88%EB%A1%9D%EC%B9%B4%ED%8E%98&quot; src=&quot;/proxy/plusmapViewer.php?id=maps_1747246661370&quot; id=&quot;maps_1747246661370&quot; width=&quot;540px&quot; height=&quot;350px&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; data-ke-type=&quot;map&quot; data-maps-data=&quot;addr=%EC%9D%B8%EC%B2%9C%20%EC%A4%91%EA%B5%AC%20%EB%AC%B4%EC%9D%98%EB%8F%99%209-11%201%EC%B8%B5&amp;amp;addtype=1&amp;amp;confirmid=164093094&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A374615%2C%22mapCenterY%22%3A1076908%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A374618%2C%22y%22%3A1076914%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EC%B4%88%EB%A1%9D%EC%B9%B4%ED%8E%98%22%2C%22confirmid%22%3A164093094%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=374615&amp;amp;mapY=1076908&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=2811063000&amp;amp;tel=&amp;amp;title=%EC%B4%88%EB%A1%9D%EC%B9%B4%ED%8E%98&quot; data-maps-thumbnail=&quot;https://ssl.daumcdn.net/map3/staticmap/image?center=374615%2C1076908&amp;amp;lv=4&amp;amp;size=540x350&amp;amp;srs=WCONGNAMUL&amp;amp;markers=symbol%3Asc_marker%7Clocation%3A374618%2C1076914&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;596&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;596&quot; data-ke-size=&quot;size16&quot;&gt;초록 카페 앞 주차장에는 자리가 거의 없었고, 겨우 주차 자리 하나가 있어서 주차를 했다.&lt;/p&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;596&quot; data-ke-size=&quot;size16&quot;&gt;주차를 하자마자 피로가 몰려왔습니다. 그래서 &amp;ldquo;딱 30분만&amp;rdquo; 눈 붙이자고 했는데, 당연히 알람을 맞춘 사람은 없었고, 눈 떠보니 &quot;&lt;b&gt;아쉬워 벌써 12시~&quot;&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;900&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boMZgY/btsNWZsqPxI/w9bhII0UNyESO8YE0wOVMk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boMZgY/btsNWZsqPxI/w9bhII0UNyESO8YE0wOVMk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boMZgY/btsNWZsqPxI/w9bhII0UNyESO8YE0wOVMk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboMZgY%2FbtsNWZsqPxI%2Fw9bhII0UNyESO8YE0wOVMk%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;500&quot; height=&quot;281&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;596&quot; data-ke-size=&quot;size16&quot;&gt;시간? 별로 중요하지 않고! 난 배 고프니까 눈앞에 보이는 칼국수집 가자!&lt;/p&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;596&quot; data-ke-size=&quot;size16&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;1433&quot; data-origin-height=&quot;1006&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdgw26/btsNYv5AYBA/kYZi3UXXow1kFw1J3b61xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdgw26/btsNYv5AYBA/kYZi3UXXow1kFw1J3b61xK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdgw26/btsNYv5AYBA/kYZi3UXXow1kFw1J3b61xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbdgw26%2FbtsNYv5AYBA%2FkYZi3UXXow1kFw1J3b61xK%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;500&quot; height=&quot;351&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;1433&quot; data-origin-height=&quot;1006&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;703&quot; data-start=&quot;596&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;홍합에.. 가리비에.. 바지락에.. 국물이 되게 폭력적인 맛이었고, 덕분에 부활~&lt;/p&gt;
&lt;p&gt;&lt;iframe mapdata=&quot;addr=%EC%9D%B8%EC%B2%9C%EA%B4%91%EC%97%AD%EC%8B%9C%20%EC%A4%91%EA%B5%AC%20%EC%9A%A9%EC%9C%A0%EB%8F%99&amp;amp;addtype=1&amp;amp;confirmid=&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A375234%2C%22mapCenterY%22%3A1076954%2C%22mapLevel%22%3A2%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=375234&amp;amp;mapY=1076954&amp;amp;map_hybrid=false&amp;amp;map_level=2&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=2811063000&amp;amp;tel=&amp;amp;title=&quot; src=&quot;/proxy/plusmapViewer.php?id=maps_1747284209922&quot; id=&quot;maps_1747284209922&quot; width=&quot;540px&quot; height=&quot;350px&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; data-ke-type=&quot;map&quot; data-maps-data=&quot;addr=%EC%9D%B8%EC%B2%9C%EA%B4%91%EC%97%AD%EC%8B%9C%20%EC%A4%91%EA%B5%AC%20%EC%9A%A9%EC%9C%A0%EB%8F%99&amp;amp;addtype=1&amp;amp;confirmid=&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A375234%2C%22mapCenterY%22%3A1076954%2C%22mapLevel%22%3A2%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=375234&amp;amp;mapY=1076954&amp;amp;map_hybrid=false&amp;amp;map_level=2&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=2811063000&amp;amp;tel=&amp;amp;title=&quot; data-maps-thumbnail=&quot;https://ssl.daumcdn.net/map3/staticmap/image?center=375234%2C1076954&amp;amp;lv=2&amp;amp;size=540x350&amp;amp;srs=WCONGNAMUL&amp;amp;&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-end=&quot;875&quot; data-start=&quot;846&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;무의도 캠핑장 가는 길&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_KakaoTalk_20250515_022150051_02.jpg&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;886&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btHpBl/btsNXQPgoXT/6TpgxGKWnbknCHu3vUOFeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btHpBl/btsNXQPgoXT/6TpgxGKWnbknCHu3vUOFeK/img.png&quot; data-alt=&quot;PM13:00 드디어 출발하는 으네와 나&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btHpBl/btsNXQPgoXT/6TpgxGKWnbknCHu3vUOFeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtHpBl%2FbtsNXQPgoXT%2F6TpgxGKWnbknCHu3vUOFeK%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;500&quot; height=&quot;765&quot; data-filename=&quot;edited_edited_KakaoTalk_20250515_022150051_02.jpg&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;886&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;PM13:00 드디어 출발하는 으네와 나&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;810&quot; data-end=&quot;839&quot; data-ke-size=&quot;size16&quot;&gt;자 드가자아~~&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;810&quot; data-end=&quot;839&quot; data-ke-size=&quot;size16&quot;&gt;등산로 입구는 초록 카페 뒤편에 있습니다잇!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;810&quot; data-end=&quot;839&quot; 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;KakaoTalk_20250515_021352254.jpg&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;1400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pQBAR/btsNYvjLb3z/XocqVp6dEfZCISq3378ewK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pQBAR/btsNYvjLb3z/XocqVp6dEfZCISq3378ewK/img.jpg&quot; data-alt=&quot;첫번째 갈림길이었던가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pQBAR/btsNYvjLb3z/XocqVp6dEfZCISq3378ewK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpQBAR%2FbtsNYvjLb3z%2FXocqVp6dEfZCISq3378ewK%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;400&quot; height=&quot;533&quot; data-filename=&quot;KakaoTalk_20250515_021352254.jpg&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;1400&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;첫번째 갈림길이었던가&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;810&quot; data-end=&quot;839&quot; 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;900&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boMZgY/btsNWZsqPxI/w9bhII0UNyESO8YE0wOVMk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boMZgY/btsNWZsqPxI/w9bhII0UNyESO8YE0wOVMk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boMZgY/btsNWZsqPxI/w9bhII0UNyESO8YE0wOVMk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboMZgY%2FbtsNWZsqPxI%2Fw9bhII0UNyESO8YE0wOVMk%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;200&quot; height=&quot;112&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-start=&quot;810&quot; data-end=&quot;839&quot; data-ke-size=&quot;size16&quot;&gt;냅다&amp;nbsp;왼쪽으로 가잇!&lt;br /&gt;(  이 표지판 기준으로 왼쪽으로 가는 게 맞습니다. 오해 노노)&lt;/p&gt;
&lt;p data-end=&quot;875&quot; data-start=&quot;846&quot; data-ke-size=&quot;size16&quot;&gt;그 이후로는 사진이 없지만, 중요한 스팟을 기준으로 보면&lt;br /&gt;초입 - 산소 - 과수원 - 위 사진의 갈림길(왼) - 내리막과 오르막 갈래길(오) - 밧줄 타는 절벽&lt;/p&gt;
&lt;p data-end=&quot;875&quot; data-start=&quot;846&quot; data-ke-size=&quot;size16&quot;&gt;여기까지 가면 첫 번째 해변이 나옴&lt;/p&gt;
&lt;p data-end=&quot;875&quot; data-start=&quot;846&quot; data-ke-size=&quot;size16&quot;&gt;여기서 해안 or 산길 중 선택해야 하는데, 밀물 때는 해안길이 닫힌다.&lt;/p&gt;
&lt;p data-end=&quot;875&quot; data-start=&quot;846&quot; data-ke-size=&quot;size16&quot;&gt;(개인적으로 산길이 더 편하고 빠르다)&lt;/p&gt;
&lt;p data-end=&quot;875&quot; data-start=&quot;846&quot; data-ke-size=&quot;size16&quot;&gt;해안길은 누가 봐도 해안길이고, 산길은 찾기가 조금 어려울 수 있는데 입구 나무에 하얀 통을 묶어서 표시해 놓았다.&lt;/p&gt;
&lt;p data-end=&quot;875&quot; data-start=&quot;846&quot; data-ke-size=&quot;size16&quot;&gt;해안길이든 산길이든 다 지나면 드디어&lt;/p&gt;
&lt;p data-end=&quot;875&quot; data-start=&quot;846&quot; 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;KakaoTalk_20250515_022150051.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6z1gC/btsNZen6Xol/tsb0AVUsWafy4eOnSTW5aK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6z1gC/btsNZen6Xol/tsb0AVUsWafy4eOnSTW5aK/img.jpg&quot; data-alt=&quot;손 끝에는 바다가 보인다,,&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6z1gC/btsNZen6Xol/tsb0AVUsWafy4eOnSTW5aK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6z1gC%2FbtsNZen6Xol%2Ftsb0AVUsWafy4eOnSTW5aK%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;400&quot; height=&quot;710&quot; data-filename=&quot;KakaoTalk_20250515_022150051.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;손 끝에는 바다가 보인다,,&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;998&quot; data-start=&quot;978&quot; data-ke-size=&quot;size16&quot;&gt;등산로 중간에 뷰가 좋은 포인트에서 찍은 사진이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 텐트 피칭을 해볼까!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-end=&quot;1023&quot; data-start=&quot;1005&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;시원한 바람,, 앗 이건,,&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-end=&quot;1138&quot; data-start=&quot;1025&quot; data-ke-size=&quot;size16&quot;&gt;캠프사이트에 도착하자마자 &lt;b&gt;바람이 장난이 아니었다. &lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1138&quot; data-start=&quot;1025&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;'앗..이건..! 제주도다..!'&lt;/b&gt;&lt;br /&gt;바람이 잦아들 때까지 무작정 기다리는 건 내 스타일이 아니고, 그냥 바람을 뚫고 텐트를 피칭한다.&lt;/p&gt;
&lt;p data-end=&quot;1138&quot; data-start=&quot;1025&quot; data-ke-size=&quot;size16&quot;&gt;강한 바람에 정신이 없었지만 우당탕탕 피치 완료!&lt;/p&gt;
&lt;p data-end=&quot;1138&quot; data-start=&quot;1025&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;그리고 제주에서 돌담을 수도 없이 본 짬바로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;직접 돌담을 쌓아버린&lt;/b&gt;다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5OKNU/btsNYYFMnSa/dkpTKUTcLok5qMGrcX6tB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5OKNU/btsNYYFMnSa/dkpTKUTcLok5qMGrcX6tB1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;1274&quot; data-filename=&quot;edited_KakaoTalk_20250515_022150051_01.jpg&quot; width=&quot;500&quot; height=&quot;888&quot; data-widthpercent=&quot;49.98&quot; style=&quot;width: 49.3998%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5OKNU/btsNYYFMnSa/dkpTKUTcLok5qMGrcX6tB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5OKNU%2FbtsNYYFMnSa%2FdkpTKUTcLok5qMGrcX6tB1%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;849&quot; height=&quot;1274&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o6uAk/btsNYWgUWCz/0HS2qjKzOqzfOkatKGrFTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o6uAk/btsNYWgUWCz/0HS2qjKzOqzfOkatKGrFTK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1351&quot; data-filename=&quot;edited_KakaoTalk_20250515_022150051_07.jpg&quot; style=&quot;width: 49.4374%;&quot; data-widthpercent=&quot;50.02&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o6uAk/btsNYWgUWCz/0HS2qjKzOqzfOkatKGrFTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo6uAk%2FbtsNYWgUWCz%2F0HS2qjKzOqzfOkatKGrFTK%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;901&quot; height=&quot;1351&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;돌담 장인,, 섬남,,&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1171&quot; data-start=&quot;1140&quot; 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;edited_KakaoTalk_20250515_022150051_04.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1201&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VfjcF/btsNX38ZzXI/tKWiwpmXxZzucqKyNLl830/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VfjcF/btsNX38ZzXI/tKWiwpmXxZzucqKyNLl830/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VfjcF/btsNX38ZzXI/tKWiwpmXxZzucqKyNLl830/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVfjcF%2FbtsNX38ZzXI%2FtKWiwpmXxZzucqKyNLl830%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;500&quot; height=&quot;888&quot; data-filename=&quot;edited_KakaoTalk_20250515_022150051_04.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1201&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-end=&quot;1197&quot; data-start=&quot;1178&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;자 이제 밥 먹자&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-end=&quot;1266&quot; data-start=&quot;1199&quot; data-ke-size=&quot;size16&quot;&gt;텐트 치고 누웠는데 기절할 뻔했다,, 간신히 몸을 일으켜서 나왔고,&lt;/p&gt;
&lt;p data-end=&quot;1266&quot; data-start=&quot;1199&quot; data-ke-size=&quot;size16&quot;&gt;이른 저녁을 먹기로 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1266&quot; data-start=&quot;1199&quot; 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-end=&quot;1266&quot; data-start=&quot;1199&quot; data-ke-size=&quot;size16&quot;&gt;근데&lt;/p&gt;
&lt;blockquote data-end=&quot;1281&quot; data-start=&quot;1268&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1281&quot; data-start=&quot;1270&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt; 어라?&amp;nbsp; &lt;span style=&quot;text-align: start;&quot;&gt;오늘의 메인 디쉬 지코바가&amp;nbsp;&lt;/span&gt;&lt;b&gt;술&amp;nbsp;&lt;b&gt;세 잔&lt;/b&gt;에 박살이 나부렀네?&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;이건 계획에 없던 건데..?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;1393&quot; data-start=&quot;1283&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1393&quot; data-start=&quot;1283&quot; data-ke-size=&quot;size16&quot;&gt;(대책 회의 진행)&lt;br /&gt;&lt;b&gt;편의점은 왔던 산길을 되돌아가야 하고, 왕복 4km 거리..!&lt;/b&gt;&lt;br /&gt;정신을 차려보니 숨도 안 쉬고 2km 산길을 달리고 있었다..!&lt;/p&gt;
&lt;p data-end=&quot;1393&quot; data-start=&quot;1283&quot; data-ke-size=&quot;size16&quot;&gt;분명히 처음 올 때는 50분 걸렸는데, 25분 만에 도착했다ㅋㅋㅋㅋㅋㅋ&lt;/p&gt;
&lt;p data-end=&quot;1393&quot; data-start=&quot;1283&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;두 번은 못 온다며 삼겹살, 햇반, 맥주, 과자 등 필요한 걸 잔뜩&lt;/b&gt;&amp;nbsp;사들고 다시 2km를 복귀한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7TVnL/btsNWmPbzV5/FaEtDApxOlxU3PNjdOsoJ0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7TVnL/btsNWmPbzV5/FaEtDApxOlxU3PNjdOsoJ0/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;901&quot; data-filename=&quot;KakaoTalk_20250515_022150051_05.jpg&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7TVnL/btsNWmPbzV5/FaEtDApxOlxU3PNjdOsoJ0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7TVnL%2FbtsNWmPbzV5%2FFaEtDApxOlxU3PNjdOsoJ0%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;1600&quot; height=&quot;901&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzfxo8/btsNX1cigN1/INDwBmrhbBIEdQNbKkjilK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzfxo8/btsNX1cigN1/INDwBmrhbBIEdQNbKkjilK/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;901&quot; data-filename=&quot;KakaoTalk_20250515_022150051_03.jpg&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzfxo8/btsNX1cigN1/INDwBmrhbBIEdQNbKkjilK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdzfxo8%2FbtsNX1cigN1%2FINDwBmrhbBIEdQNbKkjilK%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;1600&quot; height=&quot;901&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;양손 가득. 다시 포토 스팟.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1393&quot; data-start=&quot;1283&quot; data-ke-size=&quot;size16&quot;&gt;(&lt;s&gt;삼겹살 생각에 눈이 돌아서&lt;/s&gt;배낭이 없어서 몸이 가벼웠던 거 같다.)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-end=&quot;1456&quot; data-start=&quot;1440&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;평화 그리고 낭만&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250515_022150051_17.jpg&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;1400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RUTrw/btsNW0dL9CK/NePtNbYClOTnSllj1gLTkk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RUTrw/btsNW0dL9CK/NePtNbYClOTnSllj1gLTkk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RUTrw/btsNW0dL9CK/NePtNbYClOTnSllj1gLTkk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRUTrw%2FbtsNW0dL9CK%2FNePtNbYClOTnSllj1gLTkk%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;450&quot; height=&quot;600&quot; data-filename=&quot;KakaoTalk_20250515_022150051_17.jpg&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;1400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMKx3p/btsNYp5m09P/APRvPU507QEfEU4wgVQggk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMKx3p/btsNYp5m09P/APRvPU507QEfEU4wgVQggk/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot; data-filename=&quot;KakaoTalk_20250515_022150051_08.jpg&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMKx3p/btsNYp5m09P/APRvPU507QEfEU4wgVQggk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMKx3p%2FbtsNYp5m09P%2FAPRvPU507QEfEU4wgVQggk%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;901&quot; height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0Rk0o/btsNWKbzXTC/56bRkUXKG5kHRnYuFsNS5K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0Rk0o/btsNWKbzXTC/56bRkUXKG5kHRnYuFsNS5K/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot; data-filename=&quot;KakaoTalk_20250515_022150051_14.jpg&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0Rk0o/btsNWKbzXTC/56bRkUXKG5kHRnYuFsNS5K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0Rk0o%2FbtsNWKbzXTC%2F56bRkUXKG5kHRnYuFsNS5K%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;901&quot; height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1636&quot; data-start=&quot;1553&quot; data-ke-size=&quot;size16&quot;&gt;알록달록한 텐풍, 밤하늘, 멋진 세렝게티 풍경...&lt;/p&gt;
&lt;p data-end=&quot;1636&quot; data-start=&quot;1553&quot; data-ke-size=&quot;size16&quot;&gt;10시쯤까지 밖에서 잔잔하게 즐기다가 들어갔습니다.&lt;/p&gt;
&lt;p data-end=&quot;1636&quot; data-start=&quot;1553&quot; data-ke-size=&quot;size16&quot;&gt;(밤 사이에 고양이인지 쓰레기봉투를 다 헤집어놔서 식겁했어요.. 바로 텐트 안으로 들고 들어갔어요ㅎㅎ)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;text-align: center;&quot; data-end=&quot;1673&quot; data-start=&quot;1643&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;집 가자;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;1673&quot; data-start=&quot;1643&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;(feat. 해안길 포토 스팟)&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style4&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-end=&quot;1740&quot; data-start=&quot;1675&quot; data-ke-size=&quot;size16&quot;&gt;다음날 아침엔 커피 끓여 먹고, 장비를 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;하나하나&lt;span&gt; &lt;/span&gt;&lt;/span&gt;정리하고, 천천히 출발했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/otgfA/btsNXrpuEOO/4SVcZ3GJI41KcJtabgDeVk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/otgfA/btsNXrpuEOO/4SVcZ3GJI41KcJtabgDeVk/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot; data-filename=&quot;KakaoTalk_20250515_022150051_10.jpg&quot; style=&quot;width: 42.3803%; margin-right: 10px;&quot; data-widthpercent=&quot;42.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/otgfA/btsNXrpuEOO/4SVcZ3GJI41KcJtabgDeVk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FotgfA%2FbtsNXrpuEOO%2F4SVcZ3GJI41KcJtabgDeVk%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;901&quot; height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTHx4a/btsNYWIq20S/lV86fCq1hjiBVJijYkBrGk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTHx4a/btsNYWIq20S/lV86fCq1hjiBVJijYkBrGk/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;1501&quot; data-filename=&quot;KakaoTalk_20250515_022150051_11.jpg&quot; style=&quot;width: 56.4569%;&quot; data-widthpercent=&quot;57.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTHx4a/btsNYWIq20S/lV86fCq1hjiBVJijYkBrGk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTHx4a%2FbtsNYWIq20S%2FlV86fCq1hjiBVJijYkBrGk%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;1126&quot; height=&quot;1501&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&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;KakaoTalk_20250515_022150051_12.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1mieJ/btsNWSt5ytB/WhWQkioDBUc3WlFo50S2aK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1mieJ/btsNWSt5ytB/WhWQkioDBUc3WlFo50S2aK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1mieJ/btsNWSt5ytB/WhWQkioDBUc3WlFo50S2aK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1mieJ%2FbtsNWSt5ytB%2FWhWQkioDBUc3WlFo50S2aK%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;400&quot; height=&quot;710&quot; data-filename=&quot;KakaoTalk_20250515_022150051_12.jpg&quot; data-origin-width=&quot;901&quot; data-origin-height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1790&quot; data-start=&quot;1742&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;유명한 포토 스팟에서 사진도 찍고!!&lt;/p&gt;
&lt;p data-end=&quot;1790&quot; data-start=&quot;1742&quot; data-ke-size=&quot;size16&quot;&gt;아 근데 저기 올라가는 게 생각보다 위험하더라고요,, 무거운 배낭을 메고 바위를 오르내리다 보면 안전사고가 있을 수 있으니 조심하셔야 해요!!!&lt;/p&gt;
&lt;p data-end=&quot;1863&quot; data-start=&quot;1792&quot; data-ke-size=&quot;size16&quot;&gt;또 해안길은 돌길로 되어있고 불규칙해서 생각보다 난이도가 있었지만, 한 번 정도는 감수하고 가볼 만했습니다.&lt;/p&gt;
&lt;hr data-end=&quot;1868&quot; data-start=&quot;1865&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-end=&quot;1876&quot; data-start=&quot;1870&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1958&quot; data-start=&quot;1878&quot; data-ke-size=&quot;size16&quot;&gt;계획이 다 틀어지고, 무의도는 &lt;b&gt;급하게 결정된 목적지였지만, 너무 멋졌고 잊을 수 없는 곳&lt;/b&gt;이었습니다.&lt;br /&gt;굴업도는 5월 말에 재도전! 그땐 배 뜨겠지~&lt;/p&gt;
&lt;blockquote data-end=&quot;2001&quot; data-start=&quot;1960&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1981&quot; data-start=&quot;1962&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;중요한 건 계획이 아니라 대응이다.&amp;rdquo;&lt;/p&gt;
&lt;p data-end=&quot;2001&quot; data-start=&quot;1986&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ndash; 배트맨 &lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>G_Batman</author>
      <guid isPermaLink="true">https://g-batman.tistory.com/91</guid>
      <comments>https://g-batman.tistory.com/91#entry91comment</comments>
      <pubDate>Fri, 16 May 2025 08:11:39 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] DTO란? Class 방식과 Record 방식</title>
      <link>https://g-batman.tistory.com/87</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 프로젝트에서 Spring 백엔드를 담당하며 Record로 DTO를 구현해 봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Record를 처음 써봤고, 공식 문서를 보면 '고정된 값들을 담는 얕은 불변성의 투명한 매개체'라고 설명이 되어있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;62&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEShuN/btsNZgsJuQx/vmW821iXyjZN8qKgReC4Jk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEShuN/btsNZgsJuQx/vmW821iXyjZN8qKgReC4Jk/img.png&quot; data-alt=&quot;Java17 버전 공식문서&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEShuN/btsNZgsJuQx/vmW821iXyjZN8qKgReC4Jk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEShuN%2FbtsNZgsJuQx%2FvmW821iXyjZN8qKgReC4Jk%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;1674&quot; height=&quot;62&quot; data-origin-width=&quot;1674&quot; data-origin-height=&quot;62&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Java17 버전 공식문서&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1747275610790&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;[Java] Shallow Immutable? Deep Immutable?&quot; data-og-description=&quot;얕은 불변성과 깊은 불변성??Java Record Object의 공식 문서를 읽다가 등장한 Shallow Immutable... Deep Immutable과 어떤 차이가 있을까요?shallowly immutable 이란?공식 docs에서는 관련 내용을 찾기 어려웠고, 스&quot; data-og-host=&quot;g-batman.tistory.com&quot; data-og-source-url=&quot;https://g-batman.tistory.com/90&quot; data-og-url=&quot;https://g-batman.tistory.com/90&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jmaF3/hyYRlSshKv/FSDo3KA2X5qYfOpJSaBKkK/img.png?width=533&amp;amp;height=424&amp;amp;face=0_0_533_424,https://scrap.kakaocdn.net/dn/DURvF/hyYTaI8iBZ/c924HPnvDIQX0dAWA2JOt1/img.png?width=533&amp;amp;height=424&amp;amp;face=0_0_533_424&quot;&gt;&lt;a href=&quot;https://g-batman.tistory.com/90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://g-batman.tistory.com/90&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jmaF3/hyYRlSshKv/FSDo3KA2X5qYfOpJSaBKkK/img.png?width=533&amp;amp;height=424&amp;amp;face=0_0_533_424,https://scrap.kakaocdn.net/dn/DURvF/hyYTaI8iBZ/c924HPnvDIQX0dAWA2JOt1/img.png?width=533&amp;amp;height=424&amp;amp;face=0_0_533_424');&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;[Java] Shallow Immutable? Deep Immutable?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;얕은 불변성과 깊은 불변성??Java Record Object의 공식 문서를 읽다가 등장한 Shallow Immutable... Deep Immutable과 어떤 차이가 있을까요?shallowly immutable 이란?공식 docs에서는 관련 내용을 찾기 어려웠고, 스&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;g-batman.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;figure id=&quot;og_1747274519419&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;Record (Java SE 17 &amp;amp; JDK 17)&quot; data-og-description=&quot;Direct Known Subclasses: UnixDomainPrincipal public abstract class Record extends Object This is the common base class of all Java language record classes. More information about records, including descriptions of the implicitly declared methods synthesize&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Record.html&quot; data-og-url=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Record.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Record.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Record.html&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;Record (Java SE 17 &amp;amp; JDK 17)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Direct Known Subclasses: UnixDomainPrincipal public abstract class Record extends Object This is the common base class of all Java language record classes. More information about records, including descriptions of the implicitly declared methods synthesize&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.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;제가 구현했던 DTO는 모임을 생성할 때 필요한 정보들을 담는 CreateMeetRequest dto입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Class 방식으로 구현&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1747275706913&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class CreateMeetRequest {
    private String meetIntro;
    private String meetType;
    private String address;
    private String addressDescription;
    private LocalDateTime meetAt;
    private int totalCost;
    private int memberLimit;

    public CreateMeetRequest(...) { ... }
    
    public String getMeetIntro() { return meetIntro; }
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;Record 방식으로 구현&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1747275823521&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public record CreateMeetRequest(
    String meetIntro,
    String meetType,
    String address,
    String addressDescription,
    LocalDateTime meetAt,
    int totalCost,
    int memberLimit
) {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1489&quot; data-start=&quot;1481&quot; data-ke-size=&quot;size16&quot;&gt;Record로 작성하면 내부적으로 멤버 변수가&amp;nbsp; &lt;b&gt;private final&lt;/b&gt;로 선언이 됩니다. 그리고 &lt;b&gt;getter, toString, equals 등의 메소드가 자동으로 생성&lt;/b&gt;이 됩니다. 덕분에 &lt;b&gt;코드가 간결&lt;/b&gt;해지고, &lt;b&gt;불변성이 보장&lt;/b&gt;이 되는 장점이 있었습니다.&lt;/p&gt;
&lt;p data-end=&quot;1489&quot; data-start=&quot;1481&quot; 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;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;또 클래스를 사용했을 때는 @AllArgConstructor, @Getter 등의 어노테이션을 DTO마다 모두 선언해 주었습니다. 이러한 보일러플레이트 코드를 줄임으로써 핵심적인 구성요소만 남으니 편하고 가독성도 좋았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;257&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TXzhg/btsNWUdW1kS/BAJq7UyVqtkaNxCCaED2n0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TXzhg/btsNWUdW1kS/BAJq7UyVqtkaNxCCaED2n0/img.jpg&quot; data-alt=&quot;좋잖아?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TXzhg/btsNWUdW1kS/BAJq7UyVqtkaNxCCaED2n0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTXzhg%2FbtsNWUdW1kS%2FBAJq7UyVqtkaNxCCaED2n0%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;257&quot; height=&quot;196&quot; data-origin-width=&quot;257&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;좋잖아?&lt;/figcaption&gt;
&lt;/figure&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;단순 DTO나 응답 전용 객체 &amp;rarr; record ✅&lt;br /&gt;&lt;br /&gt;복잡한 유효성 검사나 상태를 가지는 도메인 객체 &amp;rarr; class 사용이 안전 ✅&lt;/blockquote&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 style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; text-align: start;&quot;&gt;실제 코드&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #333333; text-align: start;&quot;&gt;(Description, Validation 등을 추가)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1744247980758&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Schema(description = &quot;모임 생성 요청 DTO&quot;)
public record CreateMeetRequest(
    @Schema(description = &quot;모임 설명&quot;, example = &quot;제주 올레길 탐방&quot;)
    @NotBlank
    @Size(max = 30)
    String meetIntro,

    @Schema(description = &quot;모임 유형 ('이동', '운동', '빨래' 등)&quot;, example = &quot;여행&quot;)
    @NotBlank
    @Size(max = 10)
    String meetType,

    @Schema(description = &quot;주소&quot;, example = &quot;제주특별자치도 제주시 월성로 4길 19&quot;)
    @NotBlank
    @Size(max = 40)
    String address,

    @Schema(description = &quot;주소 설명&quot;, example = &quot;노블레스 관광 호텔 로비&quot;)
    @NotBlank
    @Size(max = 20)
    String addressDescription,

    @Schema(description = &quot;출발 시간&quot;, example = &quot;2025-05-20T18:00:00&quot;)
    @NotNull
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = &quot;yyyy-MM-dd'T'HH:mm:ss&quot;)
    @Future(message = &quot;모임 날짜는 현재보다 이후여야 합니다.&quot;)
    LocalDateTime meetAt,

    @Schema(description = &quot;총 비용 (0~10,000,000)&quot;, example = &quot;10000&quot;)
    @NotNull
    @Min(0)
    @Max(10_000_000)
    int totalCost,

    @Schema(description = &quot;최대 인원 수 (1~30)&quot;, example = &quot;5&quot;)
    @NotNull
    @Min(2)
    @Max(30)
    int memberLimit
) {}&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Backend/Spring</category>
      <author>G_Batman</author>
      <guid isPermaLink="true">https://g-batman.tistory.com/87</guid>
      <comments>https://g-batman.tistory.com/87#entry87comment</comments>
      <pubDate>Thu, 15 May 2025 21:13:53 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Shallow Immutable? Deep Immutable?</title>
      <link>https://g-batman.tistory.com/90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;얕은 불변성과 깊은 불변성??&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java Record Object의 공식 문서를 읽다가 등장한 Shallow Immutable... Deep Immutable과 어떤 차이가 있을까요?&lt;/p&gt;
&lt;h4 data-end=&quot;145&quot; data-start=&quot;117&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;shallowly immutable 이란?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;247&quot; data-start=&quot;147&quot; data-ke-size=&quot;size16&quot;&gt;공식 docs에서는 관련 내용을 찾기 어려웠고, 스택오버플로우에서 내용을 찾았습니다.&lt;/p&gt;
&lt;p data-end=&quot;247&quot; data-start=&quot;147&quot; data-ke-size=&quot;size16&quot;&gt;shallow immutability는 &lt;b&gt;record 객체 자체의 필드 값은 변경할 수 없지만, 그 필드가 참조하고 있는 객체의 내부 상태는 변경될 수 있다&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;533&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KvmZO/btsNXYfB8d2/eWalbJkK0HRuAWeqoXR5EK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KvmZO/btsNXYfB8d2/eWalbJkK0HRuAWeqoXR5EK/img.png&quot; data-alt=&quot;무슨말이지??&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KvmZO/btsNXYfB8d2/eWalbJkK0HRuAWeqoXR5EK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKvmZO%2FbtsNXYfB8d2%2FeWalbJkK0HRuAWeqoXR5EK%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;250&quot; height=&quot;199&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;무슨말이지??&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다섯 번 정도 읽어보니 '필드가 Int라면 값을 변경할 수 없지만 List를 참조하고 있으면 그 내부의 값은 변경할 수 있다' 정도의 예시가 생각이 났습니다. 간단한 예시 코드를 작성해 봤습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1747275388063&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.List;

public record Person(String name, List&amp;lt;String&amp;gt; hobbies) {}

public class Main {
    public static void main(String[] args) {
        List&amp;lt;String&amp;gt; hobbyList = List.of(&quot;축구&quot;, &quot;헬스&quot;);
        Person p = new Person(&quot;Batman&quot;, new ArrayList&amp;lt;&amp;gt;(hobbyList));

        System.out.println(p); // Person[name=Batman, hobbies=[축구, 헬스]]

        // hobbies 리스트 내부 데이터 추가
        p.hobbies().add(&quot;등산&quot;);

        System.out.println(p); // Person[name=Batman, hobbies=[축구, 헬스, 등산]]
    }
}&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;여기서 p.hobbies()는 final이기 때문에 &lt;b&gt;다른 List로 대체할 수는 없습니다. &lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;하지만 List 객체 자체는 &lt;/span&gt;&lt;b&gt;mutable 하기&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 때문에, 그 &lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Deep Immutable&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>Backend/Spring</category>
      <category>java</category>
      <author>G_Batman</author>
      <guid isPermaLink="true">https://g-batman.tistory.com/90</guid>
      <comments>https://g-batman.tistory.com/90#entry90comment</comments>
      <pubDate>Thu, 15 May 2025 11:19:34 +0900</pubDate>
    </item>
    <item>
      <title>[DB] 우리 서비스에 가장 적합한 RDBMS는? MySQL편</title>
      <link>https://g-batman.tistory.com/89</link>
      <description>&lt;h4 data-end=&quot;187&quot; data-start=&quot;174&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;테스트 목적&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;388&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kI6pQ/btsNHMMG3IS/p4n5MjtCubmVx1oYC2RjAK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kI6pQ/btsNHMMG3IS/p4n5MjtCubmVx1oYC2RjAK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kI6pQ/btsNHMMG3IS/p4n5MjtCubmVx1oYC2RjAK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkI6pQ%2FbtsNHMMG3IS%2Fp4n5MjtCubmVx1oYC2RjAK%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;388&quot; height=&quot;264&quot; data-origin-width=&quot;388&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;357&quot; data-start=&quot;189&quot; data-ke-size=&quot;size16&quot;&gt;MODiE 서비스에서 가장 적합한 RDBMS를 선정하기 위해, 동일한 조건에서 &lt;b&gt;MySQL&lt;/b&gt;, &lt;b&gt;PostgreSQL&lt;/b&gt;을 대상으로 성능을 비교해보려고 합니다. 단순 수치 비교가 아닌, 실제 서비스 환경과 유사한 시나리오로 부하를 유발하며, &lt;b&gt;쿼리 튜닝 및 병목 요인 제거&lt;/b&gt;까지 포함한 실험입니다. 오늘은 MySQL편~&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;377&quot; data-start=&quot;364&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;테스트 환경&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 157px;&quot; border=&quot;1&quot; data-end=&quot;613&quot; data-start=&quot;379&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;b&gt;값&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot; data-end=&quot;448&quot; data-start=&quot;404&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;415&quot; data-start=&quot;404&quot;&gt;&lt;b&gt;EC2 인스턴스&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;448&quot; data-start=&quot;415&quot;&gt;m5.large (2 vCPU, 8GiB RAM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot; data-end=&quot;476&quot; data-start=&quot;449&quot;&gt;
&lt;td style=&quot;height: 17px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;454&quot; data-start=&quot;449&quot;&gt;&lt;b&gt;OS&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;476&quot; data-start=&quot;454&quot;&gt;Ubuntu 24.04.2 LTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot; data-end=&quot;513&quot; data-start=&quot;477&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;483&quot; data-start=&quot;477&quot;&gt;&lt;b&gt;디스크&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;513&quot; data-start=&quot;483&quot;&gt;Amazon EBS (gp3, NVMe SSD)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot; data-end=&quot;548&quot; data-start=&quot;514&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;521&quot; data-start=&quot;514&quot;&gt;&lt;b&gt;네트워크&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;548&quot; data-start=&quot;521&quot;&gt;동일 VPC 내 private subnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot; data-end=&quot;562&quot; data-start=&quot;549&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;556&quot; data-start=&quot;549&quot;&gt;&lt;b&gt;DB 서버 수&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;562&quot; data-start=&quot;556&quot;&gt;1대&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot; data-end=&quot;592&quot; data-start=&quot;563&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;571&quot; data-start=&quot;563&quot;&gt;&lt;b&gt;구조&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;592&quot; data-start=&quot;571&quot;&gt;Controller, Worker, DB 용 EC2 별도 구성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot; data-end=&quot;613&quot; data-start=&quot;593&quot;&gt;
&lt;td style=&quot;height: 20px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;602&quot; data-start=&quot;593&quot;&gt;&lt;b&gt;모니터링 툴&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot; data-end=&quot;613&quot; data-start=&quot;602&quot; data-col-size=&quot;sm&quot;&gt;JMeter, Netdata&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;h4 data-end=&quot;635&quot; data-start=&quot;620&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;테스트 시나리오&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  Test data&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-end=&quot;295&quot; data-start=&quot;278&quot; data-ke-size=&quot;size23&quot;&gt;  데이터 스키마 요약&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서비스 운영 6개월~1년 차 수준의 데이터 규모&lt;/b&gt;를 가정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;csv 파일을 사용해서 빠른 삽&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;476&quot; data-start=&quot;297&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;테이블&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;td&gt;레코드 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;378&quot; data-start=&quot;349&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;358&quot; data-start=&quot;349&quot;&gt;user&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;367&quot; data-start=&quot;358&quot;&gt;사용자 정보&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;378&quot; data-start=&quot;367&quot;&gt;500,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;407&quot; data-start=&quot;379&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;388&quot; data-start=&quot;379&quot;&gt;meet&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;396&quot; data-start=&quot;388&quot;&gt;모임 정보&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;407&quot; data-start=&quot;396&quot;&gt;500,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;447&quot; data-start=&quot;408&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;422&quot; data-start=&quot;408&quot;&gt;user_meet&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;436&quot; data-start=&quot;422&quot;&gt;유저-모임 참여 관계&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;447&quot; data-start=&quot;436&quot;&gt;500,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;476&quot; data-start=&quot;448&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;457&quot; data-start=&quot;448&quot;&gt;chat&lt;/td&gt;
&lt;td data-end=&quot;465&quot; data-start=&quot;457&quot; data-col-size=&quot;sm&quot;&gt;채팅 기록&lt;/td&gt;
&lt;td data-end=&quot;476&quot; data-start=&quot;465&quot; data-col-size=&quot;sm&quot;&gt;500,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #000000; text-align: start;&quot;&gt; &lt;/span&gt;&lt;b&gt;사용한 최종 쿼리 - 아래 쿼리에서 Read 90% Create 10% 비율로 사용 &lt;b&gt;(접은글)&lt;/b&gt; &lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1746082220944&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1. 모임 목록 조회
SELECT m.*
FROM meet m
WHERE m.owner_id = 'user_0000001'
  AND m.meet_type = '운동'
  AND m.completed_at IS NULL
  AND m.deleted_at IS NULL

UNION

SELECT m.*
FROM meet m
JOIN user_meet um ON um.meet_id = m.meet_id
WHERE um.user_id = 'user_000003'
  AND um.deleted_at IS NULL
  AND m.meet_type = '운동'
  AND m.completed_at IS NULL
  AND m.deleted_at IS NULL
ORDER BY meet_at ASC;

-- 2. 모임 상세 조회

SELECT 
  m.meet_id, 
  m.meet_intro, 
  m.meet_type, 
  m.address, 
  m.address_description, 
  m.meet_at, 
  m.total_cost, 
  m.member_limit, 
  m.created_at, 
  m.updated_at, 
  m.deleted_at, 
  m.completed_at,
  u.user_name AS owner_name
FROM meet m
JOIN user u ON m.owner_id = u.user_id
WHERE m.meet_id = ?;

-- 3. 모임 참여자 목록 조회
SELECT 
  u.user_id, 
  u.user_name
FROM user_meet um
JOIN user u ON um.user_id = u.user_id
WHERE um.meet_id = ?
  AND um.deleted_at IS NULL;

-- 4. 채팅 내용 조회
SELECT
  c.message_id,
  c.user_id,
  u.user_name,
  c.message_content,
  c.created_at,
  c.meet_id
FROM chat c
JOIN user u ON c.user_id = u.user_id
WHERE c.meet_id = ?
ORDER BY c.created_at DESC
LIMIT 25;

-- 5. 모임 생성
INSERT INTO meet (
  address,
  address_description,
  completed_at,
  created_at,
  deleted_at,
  meet_at,
  meet_intro,
  meet_type,
  member_limit,
  total_cost,
  updated_at,
  owner_id
)
VALUES (
  CONCAT('서울시_', ${__counter(FALSE)}),
  '건물 1층 로비',
  NULL,
  NOW(),
  NULL,
  NOW() + INTERVAL 1 DAY,
  CONCAT('소개글_', ${__counter(FALSE)}),
  '이동',
  FLOOR(5 + RAND() * 15),
  FLOOR(1000 + RAND() * 9000),
  NULL,
  'user_0000001'
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;649&quot; data-start=&quot;637&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  VU Max 추정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;741&quot; data-start=&quot;651&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;685&quot; data-start=&quot;651&quot;&gt;2 vCPU &amp;rarr; &lt;b&gt;2 * 1000 VU 수준에서 포화 예상&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot; data-start=&quot;620&quot; data-end=&quot;635&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;테스트 결과&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;990&quot; data-start=&quot;762&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr data-end=&quot;849&quot; data-start=&quot;826&quot;&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;831&quot; data-start=&quot;826&quot;&gt;Virtual User 수&lt;/td&gt;
&lt;td style=&quot;width: 18.7209%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;837&quot; data-start=&quot;831&quot;&gt;Ramp-up 시간&lt;/td&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;844&quot; data-start=&quot;837&quot;&gt;CPU 사용량&lt;/td&gt;
&lt;td style=&quot;width: 16.0465%;&quot; data-end=&quot;849&quot; data-start=&quot;844&quot; data-col-size=&quot;sm&quot;&gt;QPS&lt;/td&gt;
&lt;td style=&quot;width: 30.3489%;&quot;&gt;특이사항&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;872&quot; data-start=&quot;850&quot;&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;855&quot; data-start=&quot;850&quot;&gt;100&lt;/td&gt;
&lt;td style=&quot;width: 18.7209%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;861&quot; data-start=&quot;855&quot;&gt;60초&lt;/td&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-end=&quot;866&quot; data-start=&quot;861&quot; data-col-size=&quot;sm&quot;&gt;4%&lt;/td&gt;
&lt;td style=&quot;width: 16.0465%;&quot; data-end=&quot;872&quot; data-start=&quot;866&quot; data-col-size=&quot;sm&quot;&gt;16&lt;/td&gt;
&lt;td style=&quot;width: 30.3489%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;896&quot; data-start=&quot;873&quot;&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;879&quot; data-start=&quot;873&quot;&gt;200&lt;/td&gt;
&lt;td style=&quot;width: 18.7209%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;885&quot; data-start=&quot;879&quot;&gt;60초&lt;/td&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-end=&quot;890&quot; data-start=&quot;885&quot; data-col-size=&quot;sm&quot;&gt;8%&lt;/td&gt;
&lt;td style=&quot;width: 16.0465%;&quot; data-end=&quot;896&quot; data-start=&quot;890&quot; data-col-size=&quot;sm&quot;&gt;34&lt;/td&gt;
&lt;td style=&quot;width: 30.3489%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;921&quot; data-start=&quot;897&quot;&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;903&quot; data-start=&quot;897&quot;&gt;500&lt;/td&gt;
&lt;td style=&quot;width: 18.7209%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;909&quot; data-start=&quot;903&quot;&gt;60초&lt;/td&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;915&quot; data-start=&quot;909&quot;&gt;12%&lt;/td&gt;
&lt;td style=&quot;width: 16.0465%;&quot; data-end=&quot;921&quot; data-start=&quot;915&quot; data-col-size=&quot;sm&quot;&gt;91&lt;/td&gt;
&lt;td style=&quot;width: 30.3489%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;948&quot; data-start=&quot;922&quot;&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;929&quot; data-start=&quot;922&quot;&gt;1000&lt;/td&gt;
&lt;td style=&quot;width: 18.7209%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;935&quot; data-start=&quot;929&quot;&gt;60초&lt;/td&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;941&quot; data-start=&quot;935&quot;&gt;18%&lt;/td&gt;
&lt;td style=&quot;width: 16.0465%;&quot; data-end=&quot;948&quot; data-start=&quot;941&quot; data-col-size=&quot;sm&quot;&gt;182&lt;/td&gt;
&lt;td style=&quot;width: 30.3489%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;990&quot; data-start=&quot;949&quot;&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;956&quot; data-start=&quot;949&quot;&gt;3000&lt;/td&gt;
&lt;td style=&quot;width: 18.7209%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;962&quot; data-start=&quot;956&quot;&gt;60초&lt;/td&gt;
&lt;td style=&quot;width: 17.3256%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;968&quot; data-start=&quot;962&quot;&gt;53%&lt;/td&gt;
&lt;td style=&quot;width: 16.0465%;&quot; data-end=&quot;990&quot; data-start=&quot;968&quot; data-col-size=&quot;sm&quot;&gt;546&lt;/td&gt;
&lt;td style=&quot;width: 30.3489%;&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #d44c47;&quot; data-token-index=&quot;0&quot;&gt;peek 94% &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;(⚠️ 서버 불안정 판단)&lt;/span&gt; &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  전체 메모리 사용량 1 GiB 미만 &amp;rarr; 병목 없음 확인&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;진행 중 트러블 슈팅&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-end=&quot;193&quot; data-start=&quot;143&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Trouble 1: 쿼리 성능 병목 (Index 미사용 + 불필요한 Full Scan)&lt;/b&gt;&lt;/h4&gt;
&lt;h4 data-end=&quot;205&quot; data-start=&quot;195&quot; data-ke-size=&quot;size20&quot;&gt;  상황&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;368&quot; data-start=&quot;207&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;261&quot; data-start=&quot;207&quot;&gt;테스트 초반 &lt;b&gt;10 VU / QPS 10&lt;/b&gt; 수준임에도 CPU 사용률이 &lt;b&gt;99%에 육박&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;380&quot; data-start=&quot;370&quot; data-ke-size=&quot;size20&quot;&gt;  분석&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;451&quot; data-start=&quot;382&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;413&quot; data-start=&quot;382&quot;&gt;의심 쿼리: 모임 목록 조회&lt;/li&gt;
&lt;li data-end=&quot;413&quot; data-start=&quot;382&quot;&gt;&lt;span data-state=&quot;closed&quot;&gt;&lt;/span&gt;Netdata로 확인한 결과, iowait 없이 user 영역이 급등 &amp;rarr; 병목 지점 확인&lt;/li&gt;
&lt;li data-end=&quot;413&quot; data-start=&quot;382&quot;&gt;EXPLAIN 명령어로 확인 시 Full Scan 탐색이었고, 50만 행을 순회한 것을 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;768&quot; data-start=&quot;753&quot; data-ke-size=&quot;size20&quot;&gt;  시도한 해결책&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;847&quot; data-start=&quot;770&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;814&quot; data-start=&quot;770&quot;&gt;&lt;b&gt;쿼리 재작성 전&lt;/b&gt;: OR 조건이 포함된 경우, 인덱스가 완전히 무시됨&lt;/li&gt;
&lt;li data-end=&quot;847&quot; data-start=&quot;815&quot;&gt;&lt;b&gt;UNION 사용&lt;/b&gt;으로 분리 &amp;rarr; 인덱스 타기 시작&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-end=&quot;861&quot; data-start=&quot;849&quot; data-ke-size=&quot;size20&quot;&gt;✅ 최종 해결&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;886&quot; data-start=&quot;863&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;886&quot; data-start=&quot;863&quot;&gt;아래 복합 인덱스 생성으로 완전히 해결&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1746084582380&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE INDEX idx_meet_owner_type_completion ON meet(owner_id, meet_type, completed_at, deleted_at);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1106&quot; data-start=&quot;1000&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1077&quot; data-start=&quot;1000&quot;&gt;이후 EXPLAIN 결과에서 type = range, key = idx_meet_owner_type_completion 확인&lt;/li&gt;
&lt;li data-end=&quot;1106&quot; data-start=&quot;1078&quot;&gt;CPU 사용률 &lt;b&gt;99% &amp;rarr; 1%로 감소&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1157&quot; data-start=&quot;1113&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;1157&quot; data-start=&quot;1113&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Trouble 2: MySQL 연결 수 초과 (max_connections)&lt;/b&gt;&lt;/h4&gt;
&lt;h4 data-end=&quot;1169&quot; data-start=&quot;1159&quot; data-ke-size=&quot;size20&quot;&gt;  상황&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1327&quot; data-start=&quot;1171&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1215&quot; data-start=&quot;1171&quot;&gt;&lt;b&gt;200 VU&lt;/b&gt; 이상부터 쿼리 Error 급증&lt;/li&gt;
&lt;li data-end=&quot;1254&quot; data-start=&quot;1216&quot;&gt;500 VU에서 75% 이상 요청 실패&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;1339&quot; data-start=&quot;1329&quot; data-ke-size=&quot;size20&quot;&gt;  분석&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1447&quot; data-start=&quot;1341&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1380&quot; data-start=&quot;1341&quot;&gt;JMeter 로그 분석
&lt;pre id=&quot;code_1746084819749&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;java.sql.SQLException: Too many connections&lt;/code&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/li&gt;
&lt;li data-end=&quot;1380&quot; data-start=&quot;1341&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;MySQL SHOW VARIABLES로 기본 max_connections 값이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;b&gt;151&lt;/b&gt;&lt;/b&gt;임을 확인&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;pre id=&quot;code_1746084878722&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;SHOW VARIABLES LIKE 'max_connections';&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;1458&quot; data-start=&quot;1449&quot; data-ke-size=&quot;size20&quot;&gt;✅ 해결&lt;/h4&gt;
&lt;p data-end=&quot;1458&quot; data-start=&quot;1449&quot; data-ke-size=&quot;size16&quot;&gt;1. 설정 변경 (영구 적용)&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1746085019825&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf

[mysqld] max_connections = 5000 # 내용 추가&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 서비스 재시작&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1746085065435&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo systemctl restart mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;적용 확인&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1746085085020&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SHOW VARIABLES LIKE 'max_connections';&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1794&quot; data-start=&quot;1782&quot; data-ke-size=&quot;size16&quot;&gt;4. &lt;span style=&quot;color: #333333; font-size: 16px; letter-spacing: 0px;&quot;&gt;VU 수변경 전 에러율변경 후 에러율&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2002&quot; data-start=&quot;1796&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6744%;&quot;&gt;VU&lt;/td&gt;
&lt;td style=&quot;width: 39.3023%;&quot;&gt;기존 에러율&lt;/td&gt;
&lt;td style=&quot;width: 37.907%;&quot;&gt;수정 이후 에러율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1914&quot; data-start=&quot;1871&quot;&gt;
&lt;td style=&quot;width: 22.6744%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1879&quot; data-start=&quot;1871&quot;&gt;200&lt;/td&gt;
&lt;td style=&quot;width: 39.3023%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1896&quot; data-start=&quot;1879&quot;&gt;25%&lt;/td&gt;
&lt;td style=&quot;width: 37.907%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1914&quot; data-start=&quot;1896&quot;&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1958&quot; data-start=&quot;1915&quot;&gt;
&lt;td style=&quot;width: 22.6744%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1923&quot; data-start=&quot;1915&quot;&gt;500&lt;/td&gt;
&lt;td style=&quot;width: 39.3023%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1940&quot; data-start=&quot;1923&quot;&gt;75%&lt;/td&gt;
&lt;td style=&quot;width: 37.907%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1958&quot; data-start=&quot;1940&quot;&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2002&quot; data-start=&quot;1959&quot;&gt;
&lt;td style=&quot;width: 22.6744%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1967&quot; data-start=&quot;1959&quot;&gt;1000&lt;/td&gt;
&lt;td style=&quot;width: 39.3023%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1984&quot; data-start=&quot;1967&quot;&gt;미측정 (85% 예상)&lt;/td&gt;
&lt;td style=&quot;width: 37.907%;&quot; data-col-size=&quot;sm&quot; data-end=&quot;2002&quot; data-start=&quot;1984&quot;&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;느낀 점&lt;/span&gt;&lt;/b&gt;&lt;/h4&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 data-end=&quot;372&quot; data-start=&quot;248&quot;&gt;&lt;b&gt;&amp;ldquo;쿼리 한 줄이 CPU를 잡아먹는다.&amp;rdquo;&lt;/b&gt;&lt;br /&gt;인덱스가 빠진 쿼리 하나로 CPU가 99%를 점유하며 전체 서비스가 느려졌습니다.&lt;br /&gt;&lt;b&gt;EXPLAIN과 인덱스 튜닝은 선택이 아닌 필수&lt;/b&gt;임을 몸소 느꼈습니다.&lt;/li&gt;
&lt;li data-end=&quot;522&quot; data-start=&quot;374&quot;&gt;&lt;b&gt;&amp;ldquo;DB 설정은 &amp;lsquo;기본값&amp;rsquo;이면 안 된다.&amp;rdquo;&lt;/b&gt;&lt;br /&gt;max_connections 기본값 151은 테스트 중 200VU부터 대규모 에러를 유발했습니다.&lt;br /&gt;초기 설정값이 얼마나 보수적인지, 그리고 서비스에 맞는 튜닝이 얼마나 중요한지를 알게 되었습니다.&lt;/li&gt;
&lt;li data-end=&quot;647&quot; data-start=&quot;524&quot;&gt;&lt;b&gt;&amp;ldquo;부하 테스트는 단순 QPS 측정이 아니다.&amp;rdquo;&lt;/b&gt;&lt;br /&gt;JMeter를 단순히 돌리는 것이 아니라, 요청 흐름을 잘 설계하고 &lt;b&gt;트래픽 패턴과 쿼리 병목을 찾아내는 과정 그 자체가 실무에 가까운 훈련&lt;/b&gt;이었습니다.&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;다음은 PostgreSQL 이다잇!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Backend</category>
      <author>G_Batman</author>
      <guid isPermaLink="true">https://g-batman.tistory.com/89</guid>
      <comments>https://g-batman.tistory.com/89#entry89comment</comments>
      <pubDate>Thu, 1 May 2025 16:57:35 +0900</pubDate>
    </item>
    <item>
      <title>[OS] 교착상태와 데드락, 뮤텍스와 세마포어</title>
      <link>https://g-batman.tistory.com/88</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;laptop-2620118_1280.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXzJZ2/btsNt7FfRRw/uFPXUWx4RkZIUWwF1SKlcK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXzJZ2/btsNt7FfRRw/uFPXUWx4RkZIUWwF1SKlcK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXzJZ2/btsNt7FfRRw/uFPXUWx4RkZIUWwF1SKlcK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXzJZ2%2FbtsNt7FfRRw%2FuFPXUWx4RkZIUWwF1SKlcK%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;1280&quot; height=&quot;853&quot; data-filename=&quot;laptop-2620118_1280.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-end=&quot;229&quot; data-start=&quot;199&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;임계영역(Critical Section)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;324&quot; data-start=&quot;230&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;임계영역(Critical Section)&lt;/b&gt;이란 여러 프로세스 또는 스레드가 동시에 자원에 접근할 경우 문제가 발생할 수 있는&lt;b&gt;&amp;nbsp;코드 영역&lt;/b&gt;을 말합니다.&lt;/p&gt;
&lt;p data-end=&quot;401&quot; data-start=&quot;326&quot; data-ke-size=&quot;size16&quot;&gt;임계영역에서는 아래 3가지 조건을 만족해야 교착상태를 피할 수 있습니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;633&quot; data-start=&quot;403&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;481&quot; data-start=&quot;403&quot;&gt;&lt;b&gt;상호 배제(Mutual Exclusion)&lt;/b&gt;&lt;br /&gt;하나의 프로세스가 임계영역에 있다면, 다른 프로세스는 들어갈 수 없다.&lt;/li&gt;
&lt;li data-end=&quot;554&quot; data-start=&quot;483&quot;&gt;&lt;b&gt;진행(Progress)&lt;/b&gt;&lt;br /&gt;임계영역에 아무도 없는 상태라면, 진입을 요청하는 프로세스 중 &lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;어느 것이 들어갈지를 적절히 결정해주어야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;633&quot; data-start=&quot;556&quot;&gt;&lt;b&gt;한정 대기(Bounded Waiting)&lt;/b&gt;&lt;br /&gt;한 프로세스가 계속해서 임계영역에 들어가지 못하는 일이 없도록 보장해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;h4 data-end=&quot;656&quot; data-start=&quot;640&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;뮤텍스(Mutex)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;721&quot; data-start=&quot;658&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;뮤텍스(Mutual Exclusion Object)&lt;/b&gt;는 임계영역에 대한 접근을 제어하는 락(Lock)입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;827&quot; data-start=&quot;723&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;775&quot; data-start=&quot;723&quot;&gt;하나의 스레드만 락을 획득할 수 있으며, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;락을 획득한 스레드만 해제&lt;/span&gt;할 수 있습니다.&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;827&quot; data-start=&quot;776&quot;&gt;락을 통해 &lt;b&gt;동시성 제어&lt;/b&gt;를 하며, 동시에 하나의 스레드만 접근 가능하도록 만듭니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;935&quot; data-start=&quot;914&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;세마포어(Semaphore)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;1000&quot; data-start=&quot;937&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;세마포어&lt;/b&gt;는 뮤텍스보다 유연한 동기화 도구입니다. 자원의 &lt;b&gt;동시 접근 가능 개수&lt;/b&gt;를 제어할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1105&quot; data-start=&quot;1002&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1061&quot; data-start=&quot;1002&quot;&gt;counting semaphore: 0 이상의 값을 가질 수 있음 &amp;rarr; 동시에 여러 스레드 접근 가능&lt;/li&gt;
&lt;li data-end=&quot;1105&quot; data-start=&quot;1062&quot;&gt;binary semaphore: 0 또는 1만 가짐 &amp;rarr; 뮤텍스처럼 동작하지만 역시나 제어권은 스레드에 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1114&quot; data-start=&quot;1107&quot; 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-end=&quot;1209&quot; data-start=&quot;1115&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1151&quot; data-start=&quot;1115&quot;&gt;세마포어는 다른 스레드가 signal로 값을 증가시킬 수 있음&lt;/li&gt;
&lt;li data-end=&quot;1209&quot; data-start=&quot;1152&quot;&gt;wait() &amp;rarr; 자원 접근 대기&lt;br /&gt;signal() &amp;rarr; 자원 해제 및 다른 프로세스에 접근 허용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;1235&quot; data-start=&quot;1216&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;교착상태(Deadlock)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;1346&quot; data-start=&quot;1237&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;교착상태&lt;/b&gt;란 여러 프로세스가 &lt;b&gt;서로가 가진 자원을 기다리며 무한 대기&lt;/b&gt;에 빠지는 상태입니다.&lt;/p&gt;
&lt;p data-end=&quot;1346&quot; data-start=&quot;1237&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1372&quot; data-start=&quot;1348&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;교착 상태 발생 조건 (점순이 비상ㅋ)&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1606&quot; data-start=&quot;1374&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1440&quot; data-start=&quot;1374&quot;&gt;&lt;b&gt;상호 배제(Mutual Exclusion)&lt;/b&gt;&lt;br /&gt;자원은 한 번에 하나의 프로세스만 사용할 수 있어야 함&lt;/li&gt;
&lt;li data-end=&quot;1501&quot; data-start=&quot;1441&quot;&gt;&lt;b&gt;점유와 대기(Hold and Wait)&lt;/b&gt;&lt;br /&gt;자원을 가진 상태에서 다른 자원을 기다리는 상태&lt;/li&gt;
&lt;li data-end=&quot;1549&quot; data-start=&quot;1502&quot;&gt;&lt;b&gt;비선점(No Preemption)&lt;/b&gt;&lt;br /&gt;자원을 강제로 빼앗을 수 없음&lt;/li&gt;
&lt;li data-end=&quot;1606&quot; data-start=&quot;1550&quot;&gt;&lt;b&gt;원형 대기(Circular Wait)&lt;/b&gt;&lt;br /&gt;프로세스 간 자원 요청이 원형 구조를 이룸&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;p data-end=&quot;1630&quot; data-start=&quot;1613&quot; 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-end=&quot;1871&quot; data-start=&quot;1632&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1690&quot; data-start=&quot;1632&quot;&gt;&lt;b&gt;예방(Prevention)&lt;/b&gt;&lt;br /&gt;위 조건 중 하나를 &lt;b&gt;사전에 제거&lt;/b&gt;하여 발생 자체를 막음&lt;/li&gt;
&lt;li data-end=&quot;1795&quot; data-start=&quot;1691&quot;&gt;&lt;b&gt;회피(Avoidance)&lt;/b&gt;&lt;br /&gt;대표 알고리즘: &lt;b&gt;은행가 알고리즘(Banker's Algorithm)&lt;/b&gt;&lt;br /&gt;시스템 상태를 계속 평가하여 &lt;b&gt;안전한 경우에만 자원 할당&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1871&quot; data-start=&quot;1796&quot;&gt;&lt;b&gt;발생 후 회복(Recovery)&lt;/b&gt;&lt;br /&gt;교착상태가 감지되면&lt;br /&gt;&amp;rarr; &lt;b&gt;프로세스를 종료하거나&lt;/b&gt; 자원을 &lt;b&gt;강제로 회수&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Computer Science/OS</category>
      <author>G_Batman</author>
      <guid isPermaLink="true">https://g-batman.tistory.com/88</guid>
      <comments>https://g-batman.tistory.com/88#entry88comment</comments>
      <pubDate>Thu, 24 Apr 2025 01:24:01 +0900</pubDate>
    </item>
    <item>
      <title>[Jeju] 카카오테크 부트캠프 Hackathon</title>
      <link>https://g-batman.tistory.com/85</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;제주도에 와서 인생 첫 해커톤을 경험했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3박 4일간 진행했고, 총 7팀으로 진행되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종 2등으로 대회를 마쳤고, 이제 그 회고를 해보려고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1013&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsImRF/btsMEzhBhvY/vGhJ32rJzyOCRuYQS82mpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsImRF/btsMEzhBhvY/vGhJ32rJzyOCRuYQS82mpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsImRF/btsMEzhBhvY/vGhJ32rJzyOCRuYQS82mpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsImRF%2FbtsMEzhBhvY%2FvGhJ32rJzyOCRuYQS82mpK%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;1013&quot; height=&quot;375&quot; data-origin-width=&quot;1013&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;해커톤 개요&lt;/b&gt;&lt;/span&gt;&lt;/h4&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&gt;대회&lt;/span&gt; 기간: 2025.03.04 - 2025.03.07 (3박 4일)&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;대회 장소: 구름 스퀘어 in 제주&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;대회 규모: 42명 참가(7개 팀 각 6명)&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 data-token-index=&quot;0&quot;&gt;사회 문제(환경, 교육, 건강, 교통 등)&lt;/span&gt; &lt;span data-token-index=&quot;0&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;iframe mapdata=&quot;addr=%EC%A0%9C%EC%A3%BC%ED%8A%B9%EB%B3%84%EC%9E%90%EC%B9%98%EB%8F%84%20%EC%A0%9C%EC%A3%BC%EC%8B%9C%20%EC%9D%B4%EB%8F%84%EC%9D%B4%EB%8F%99%201921&amp;amp;addtype=1&amp;amp;confirmid=155933853&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A391195%2C%22mapCenterY%22%3A-1547%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A391198%2C%22y%22%3A-1545%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EA%B5%AC%EB%A6%84%EC%8A%A4%ED%80%98%EC%96%B4%20%EC%9D%B8%20%EC%A0%9C%EC%A3%BC%22%2C%22confirmid%22%3A155933853%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=391195&amp;amp;mapY=-1547&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=5011054000&amp;amp;tel=&amp;amp;title=%EA%B5%AC%EB%A6%84%EC%8A%A4%ED%80%98%EC%96%B4%20%EC%9D%B8%20%EC%A0%9C%EC%A3%BC&quot; src=&quot;/proxy/plusmapViewer.php?id=maps_1741501870492&quot; id=&quot;maps_1741501870492&quot; width=&quot;540px&quot; height=&quot;350px&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; data-ke-type=&quot;map&quot; data-maps-data=&quot;addr=%EC%A0%9C%EC%A3%BC%ED%8A%B9%EB%B3%84%EC%9E%90%EC%B9%98%EB%8F%84%20%EC%A0%9C%EC%A3%BC%EC%8B%9C%20%EC%9D%B4%EB%8F%84%EC%9D%B4%EB%8F%99%201921&amp;amp;addtype=1&amp;amp;confirmid=155933853&amp;amp;docid=&amp;amp;idx=1&amp;amp;ifrH=362px&amp;amp;ifrW=490px&amp;amp;mapHeight=362&amp;amp;mapInfo=%7B%22version%22%3A2%2C%22mapWidth%22%3A490%2C%22mapHeight%22%3A362%2C%22mapCenterX%22%3A391195%2C%22mapCenterY%22%3A-1547%2C%22mapLevel%22%3A4%2C%22coordinate%22%3A%22wcongnamul%22%2C%22markInfo%22%3A%5B%7B%22markerType%22%3A%22standPlace%22%2C%22coordinate%22%3A%22wcongnamul%22%2C%22x%22%3A391198%2C%22y%22%3A-1545%2C%22clickable%22%3Atrue%2C%22draggable%22%3Atrue%2C%22icon%22%3A%7B%22width%22%3A35%2C%22height%22%3A56%2C%22offsetX%22%3A17%2C%22offsetY%22%3A56%2C%22src%22%3A%22%2F%2Ft1.daumcdn.net%2Flocalimg%2Flocalimages%2F07%2F2012%2Fattach%2Fpc_img%2Fico_marker2_150331.png%22%7D%2C%22content%22%3A%22%EA%B5%AC%EB%A6%84%EC%8A%A4%ED%80%98%EC%96%B4%20%EC%9D%B8%20%EC%A0%9C%EC%A3%BC%22%2C%22confirmid%22%3A155933853%7D%5D%2C%22graphicInfo%22%3A%5B%5D%2C%22roadviewInfo%22%3A%5B%5D%7D&amp;amp;mapWidth=490&amp;amp;mapX=391195&amp;amp;mapY=-1547&amp;amp;map_hybrid=false&amp;amp;map_level=4&amp;amp;map_type=TYPE_MAP&amp;amp;rcode=5011054000&amp;amp;tel=&amp;amp;title=%EA%B5%AC%EB%A6%84%EC%8A%A4%ED%80%98%EC%96%B4%20%EC%9D%B8%20%EC%A0%9C%EC%A3%BC&quot; data-maps-thumbnail=&quot;https://ssl.daumcdn.net/map3/staticmap/image?center=391195%2C-1547&amp;amp;lv=4&amp;amp;size=540x350&amp;amp;srs=WCONGNAMUL&amp;amp;markers=symbol%3Asc_marker%7Clocation%3A391198%2C-1545&quot;&gt;&lt;/iframe&gt;&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;span style=&quot;color: #009a87;&quot;&gt;목표와 기대&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;개인적인 목표로는 세 가지 정도를 꼽을 수 있는데, &lt;b&gt;깔끔하고 재밌는 발표&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;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀 빌딩이 끝나고 첫 회의에서, 주제에 대한 MVP를 정하고 불필요한 건 하나씩 다 떼버렸는데...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람 1: &lt;b&gt;&quot;MVP인데 로그인 필요해요?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체: &lt;b&gt;&quot;뗄까요?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람 2: &lt;b&gt;&quot;로그인 떼면 저희 서비스에 DB가 필요해요?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체: &lt;b&gt;&quot;음.. 그럼 뗄까요?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람 3:&lt;b&gt; &quot;DB 뗄 거면 백엔드 서버 굳이 필요할까요?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체:&lt;b&gt; &quot;음.. 떼시죠?&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;목표와 기대&quot; 목차에 대한 마무리는 아무래도 초기 목표에 대한 결과가 되어야겠지?&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;그리고 저번 팀 회고 대회에서 1등을 하고 발표가 아주 인상적이었다는 피드백을 많이 받고 기분이 좋았었다. 근데 그런 칭찬들을 받으면서 조금 거만해졌을까 마음속으로 '내 발표 스타일이 짱이야'라는 생각을 하다가 이번 발표가 다 끝나고 느낀 점은 사람마다 발표 스타일은 다 다르고 그걸 인정할 줄 알아야겠다고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기술적인 성장&lt;/b&gt; - 이 부분에 대해서는 조금 아쉬웠다. 이번에 써드 파티 API 세 가지를 써서 그것들을 합친 서비스를 개발했는데 기술적인 난이도가 아주 낮았었다. 그래서 추후에 서비스를 고도화한다면 백엔드 서버를 개발하면서 성장하고 싶다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;팀 분위기&lt;/b&gt; - 100% 만족스럽지 못했다. 회고를 해보니 그 이유가 두 가지인 것 같은데, 첫 번째는 팀원 대부분이 해커톤에 익숙하지 않았고, 초기에 R&amp;amp;R에 대해서 제대로 정하지 않았었다. 그래서 서로가 무슨 작업을 하는지 잘 몰랐고, 공유가 잘 안 되고 리소스가 실제로 낭비된 순간이 있었다. 나랑 같은 생각이신 분이 있었는데 그분이 2일 차에 문제 제기를 해주셨고 그 이후로는 내가 컨트롤 타워 역할을 했다. (팀장이 분명히 계셨는데....ㅠ)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 이유는 팀장을 하셨던 분이 많이 조급해하셨었다. 그래서 작은 충돌이 있었다. 카페에서 새벽까지 하다가 다들 능률이 떨어지는 거 같아 세 시쯤 &quot;오늘은 이쯤 하시죠&quot; 하고 말씀드렸을 때 &quot;저희 아무것도 안되었는데 어떻게 가요? 가실 분들은 가세요&quot;라고 조금 예민한 반응을 하셨다. 팀장이라서 더 부담을 느끼셨을 수도 있다고 생각은 했지만 팀장이라면 팀 전체를 보는 능력이 필요하다고 생각한다. 해커톤이 끝나고 팀장으로서 역할을 안 하셔서 미안했다고 하시면서 훈훈하게 마무리됐다.&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 style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;잘한 점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;맥주 마시면서 아이디어톤&lt;/b&gt; - 1일 차 저녁에 라포형성을 위해서 맥주를 마시는 자리가 있었는데, 그때까지 마음에 드는 아이디어가 안 나왔었다. 그래서 태블릿에 오만 아이디어를 다 적다가 &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_IMG_0839.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m1sn3/btsMFFAWbcb/eehOGOIL7FMCgkACPo7Rs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m1sn3/btsMFFAWbcb/eehOGOIL7FMCgkACPo7Rs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m1sn3/btsMFFAWbcb/eehOGOIL7FMCgkACPo7Rs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm1sn3%2FbtsMFFAWbcb%2FeehOGOIL7FMCgkACPo7Rs1%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;2002&quot; height=&quot;580&quot; data-filename=&quot;edited_IMG_0839.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caHIrv/btsMEpzxgwH/PWk3YkIdeebVUz30AFrspK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caHIrv/btsMEpzxgwH/PWk3YkIdeebVUz30AFrspK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2136&quot; data-origin-height=&quot;1296&quot; data-filename=&quot;edited_IMG_0837.png&quot; style=&quot;width: 48.5605%; margin-right: 10px;&quot; data-widthpercent=&quot;49.13&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caHIrv/btsMEpzxgwH/PWk3YkIdeebVUz30AFrspK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaHIrv%2FbtsMEpzxgwH%2FPWk3YkIdeebVUz30AFrspK%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;2136&quot; height=&quot;1296&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhjjZA/btsMEUFKdsa/VevBTg68GqLwR8M49J1avk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhjjZA/btsMEUFKdsa/VevBTg68GqLwR8M49J1avk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2162&quot; data-origin-height=&quot;1267&quot; data-filename=&quot;edited_IMG_0838.png&quot; style=&quot;width: 50.2767%;&quot; data-widthpercent=&quot;50.87&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhjjZA/btsMEUFKdsa/VevBTg68GqLwR8M49J1avk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhjjZA%2FbtsMEUFKdsa%2FVevBTg68GqLwR8M49J1avk%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;2162&quot; height=&quot;1267&quot;/&gt;&lt;/span&gt;&lt;/div&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MVP 설정&lt;/b&gt; - 전화 통화 시뮬레이션이라는 핵심 기능에 집중해서 필요 없는 기능을 다 버리는 걸 잘했다고 생각한다. 해커톤의 취지에 맞게 잘해서 수상할 수 있었다고 생각한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;아쉬운 점&lt;/b&gt;&lt;/span&gt;&lt;/h4&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;팀장 선정&lt;/b&gt; - 사실 팀장을 맡으셨던 분한테 뭐라고 할 수도 없는 게 팀장을 하고 싶어 하셨던 것도 아니고 무슨 합리적인 이유 없이 우르르 여론 형성으로 얼떨결에 맡으셨다. 팀장의 리딩 없이 진행되다 보니 우왕좌왕할 일이 많았던 거 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;R&amp;amp;R 공수 선정&lt;/b&gt; - 개인적인 생각이지만 어떤 업무에 더 무게를 실어야 할지를 잘못 설정해서 디자인만 하루종일 하신 분도 계셨다. 다행히 중간에 기술 멘토님한테 개발 공수에 대한 피드백을 받고 조금 방향성을 잡을 수 있었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;배운 점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;새로운 기술/도구 활용 경험: &lt;/b&gt;GPT API, Firebase, TTS/STT&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;해커톤 경험&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;다음 해커톤에서 개선할 점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시간 배분 및 공수 전략 변경&lt;/b&gt;: 기획 20%, 개발 60%, 발표 준비 20% 정도가 적당하다고 생각한다. 또 하나는 자잘한 디테일(디자인 등)부터 잡고 들어가면 결국 리소스 낭비로 이어진다는 생각이 조금 생겼다. 디테일은 몇 번이고 수정될 가능성이 많으니까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;의사소통 방식 개선&lt;/b&gt; - 중간 공유가 필수다. 하루에 최소 두 번 이상은 스크럼을 하던지 해서 공유를 하면 좋을 거 같다!&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;총평&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 해커톤이었는데 걱정했던 거보다 할만했다. 라포 형성이 아주 중요한 요소임을 알 수 있었다. 또 소프트 스킬을 많이 얻어가는 거 같아서 참 좋았다! 상 받아서 기분 좋았다!&lt;/p&gt;</description>
      <author>G_Batman</author>
      <guid isPermaLink="true">https://g-batman.tistory.com/85</guid>
      <comments>https://g-batman.tistory.com/85#entry85comment</comments>
      <pubDate>Sun, 9 Mar 2025 18:51:14 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 상속(Inheritance)</title>
      <link>https://g-batman.tistory.com/84</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;axios (6).png&quot; data-origin-width=&quot;6912&quot; data-origin-height=&quot;3456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bI7HKP/btsMyTF1Po9/udx203YVwMBYI50NljkLoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bI7HKP/btsMyTF1Po9/udx203YVwMBYI50NljkLoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bI7HKP/btsMyTF1Po9/udx203YVwMBYI50NljkLoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbI7HKP%2FbtsMyTF1Po9%2Fudx203YVwMBYI50NljkLoK%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;6912&quot; height=&quot;3456&quot; data-filename=&quot;axios (6).png&quot; data-origin-width=&quot;6912&quot; data-origin-height=&quot;3456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&lt;br /&gt;상속이란?&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;즉, &lt;b&gt;부모(상위) 클래스&lt;/b&gt;가 가진 기능을 &lt;b&gt;자식(하위) 클래스&lt;/b&gt;가 이어받아서 재사용하거나 확장할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;사용 이유&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;코드 재사용성 향상&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;유지보수 용이&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;확장성 증가&lt;/b&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;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;상속의 기본 문법&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서 클래스를 상속할 때는 &lt;b&gt;extends&lt;/b&gt; 키워드를 사용합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(예시 코드)&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;// 부모 클래스
class Animal {
    String name;

    void eat() {
        System.out.println(&quot;먹고 있습니다&quot;);
    }
}

// 자식 클래스
class Dog extends Animal {
    void bark() {
        System.out.println(&quot;멍멍&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();  // Dog는 Animal을 상속받았으므로
        dog.name = &quot;마루&quot;;      // Animal 클래스의 name 필드 사용 가능
        dog.eat();            // Animal 클래스의 eat 메서드 사용 가능
        dog.bark();           // Dog 클래스에서 새로 정의한 bark 메서드
    }
}
&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;자식 클래스 Dog는 extends Animal을 통해 &lt;b&gt;Animal 클래스의 필드와 메서드를 물려받았습니다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Dog 객체를 만들면 Animal에서 정의된 기능(예: name, eat())도 그대로 사용할 수 있습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;부모와 자식 클래스&lt;/b&gt;&lt;/span&gt;&lt;/h4&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;: 다른 클래스에게 물려줄 공통된 기능을 가진 클래스&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자식(하위) 클래스&lt;/b&gt;: 부모 클래스로부터 기능을 물려받아 쓰는 클래스&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 클래스는 부모 클래스의 모든 멤버를 갖지만 &lt;b&gt;접근 제어자&lt;/b&gt;(public, protected, private 등)에 따라 실제 사용 가능 여부가 달라집니다&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;// Parent.java
class Parent {
    public String publicField = &quot;누구나 접근 가능&quot;;
    protected String protectedField = &quot;자식 클래스에서 접근 가능&quot;;
    private String privateField = &quot;해당 클래스에서만 접근 가능&quot;;
    
    public void publicMethod() {
        System.out.println(&quot;public 메서드&quot;);
    }
    
    protected void protectedMethod() {
        System.out.println(&quot;protected 메서드&quot;);
    }
    
    private void privateMethod() {
        System.out.println(&quot;private 메서드&quot;);
    }
}

// Child.java
class Child extends Parent {
    void accessTest() {
        System.out.println(publicField);      // 가능
        System.out.println(protectedField);   // 가능
        // System.out.println(privateField);  // 불가능 - 컴파일 에러
        
        publicMethod();      // 가능
        protectedMethod();   // 가능
        // privateMethod();  // 불가능 - 컴파일 에러
    }
}
&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;위 두 개의 자바 코드를 같은 패키지에 넣고 테스트해보시면 그 차이를 금방 확인할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;메서드 오버라이딩(Overriding)&lt;/b&gt;&lt;/span&gt;&lt;/h4&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;부모의 메서드를 자식이 덮어써서 새롭게 만드는 것&lt;/b&gt;을 말합니다&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Animal {
    void eat() {
        System.out.println(&quot;동물이 먹고 있습니다&quot;);
    }
}

class Dog extends Animal {
    @Override
    void eat() {
        System.out.println(&quot;강아지가 사료를 먹고 있습니다&quot;);
    }
}
&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;&lt;b&gt;@Override&lt;/b&gt; 어노테이션은 자식 클래스가 부모 클래스의 메서드를 재정의했다는 표시입니다.&lt;/li&gt;
&lt;li&gt;메서드 이름을 일치시켜야합니다.&lt;/li&gt;
&lt;li&gt;이렇게 재정의하면 &lt;b&gt;자식 클래스의 메서드&lt;/b&gt;가 우선적으로 호출됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style4&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;super 키워드&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오버라이딩된 메서드 안에서 &lt;b&gt;부모 메서드를 호출&lt;/b&gt;하고 싶다면 &lt;b&gt;super&lt;/b&gt; 키워드를 사용할 수 있습니다&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Animal {
    void eat() {
        System.out.println(&quot;동물이 먹고 있습니다&quot;);
    }
}

class Dog extends Animal {
    @Override
    void eat() {
        super.eat(); // 부모의 eat() 호출
        System.out.println(&quot;강아지가 사료를 먹고 있습니다&quot;);
    }
}
&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;이렇게 하면 &lt;b&gt;부모의 기능을 살리면서&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;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;한 단계 더 나아가기&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;다중 상속이 불가능한 이유&lt;/b&gt;&lt;/span&gt;&lt;/h4&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;하나의 부모 클래스&lt;/b&gt;만을 상속받을 수 있습니다&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;인터페이스&lt;/b&gt;를 사용해 다중 구현을 지원하는 방식으로 자바는 구조화되어 있습니다&lt;/p&gt;</description>
      <author>G_Batman</author>
      <guid isPermaLink="true">https://g-batman.tistory.com/84</guid>
      <comments>https://g-batman.tistory.com/84#entry84comment</comments>
      <pubDate>Thu, 27 Feb 2025 01:47:17 +0900</pubDate>
    </item>
    <item>
      <title>관계형 데이터베이스 - 릴레이션(Relation), 튜플(Tuple), 속성(Attribute), 도메인(Domain)</title>
      <link>https://g-batman.tistory.com/83</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;안녕하세요&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #666666; text-align: start;&quot;&gt;배트맨 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 정보처리기사 공부 중 DB과목에서 자주 출제되는 문제의 내용을 다루어보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;DALL&amp;amp;middot;E 2025-02-10 16.27.59 - A modern, minimalistic thumbnail image representing relational databases. The image features a sleek database icon (stacked disks) connected with mult.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rFjVN/btsMcQDNQ21/jNXaYKDddjJjJBdLzNK0X0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rFjVN/btsMcQDNQ21/jNXaYKDddjJjJBdLzNK0X0/img.webp&quot; data-alt=&quot;Ai 생성 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rFjVN/btsMcQDNQ21/jNXaYKDddjJjJBdLzNK0X0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrFjVN%2FbtsMcQDNQ21%2FjNXaYKDddjJjJBdLzNK0X0%2Fimg.webp&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;500&quot; height=&quot;500&quot; data-filename=&quot;DALL&amp;middot;E 2025-02-10 16.27.59 - A modern, minimalistic thumbnail image representing relational databases. The image features a sleek database icon (stacked disks) connected with mult.webp&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Ai 생성 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&lt;br /&gt;관계형 데이터베이스&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;- 관계형 데이터베이스(Relational Database, RDB)는 데이터를 2차원적인 표(Table)형식으로 저장하고, 데이터 간의 관계를 정의하는 데이터베이스이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;- 개체(Entity)와 관계(Relationship)를 표현하는데, 이를 각각 개체 릴레이션과 관계 릴레이션이라고 한다. 여기서 릴레이션(Relation)은 표(Table)라고 보면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;- 장점&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터를 이해하기에 간결하고 편리하다&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다른 데이터베이스 시스템과의 변환이 비교적 쉽다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;- 단점&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터가 복잡해질수록 성능이 다소 떨어짐&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;릴레이션 구조&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 릴레이션(Relation)은 데이터를 표 형식으로 표현한 것으로, 구조를 나타내는 릴레이션 스키마와 실제 값들인 릴레이션 인스턴스로 구성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR2EZX/btsMcSn346F/7tCJUkREwtKxuw4rogsOk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR2EZX/btsMcSn346F/7tCJUkREwtKxuw4rogsOk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR2EZX/btsMcSn346F/7tCJUkREwtKxuw4rogsOk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR2EZX%2FbtsMcSn346F%2F7tCJUkREwtKxuw4rogsOk0%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;454&quot; height=&quot;426&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;튜플(Tuple)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&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;: &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;릴레이션을 구성하는 행&lt;/b&gt;(Row)&lt;/span&gt;으로, &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;여러 속성(Attribute)&lt;/b&gt;&lt;/span&gt;의 모임이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;튜플의 개수&lt;/b&gt;: &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;카디널리티(Cardinality) &lt;/b&gt;&lt;/span&gt;또는 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;기수&lt;/b&gt;&lt;/span&gt;라고 부른다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;속성(Attribute)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&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;: 데이터베이스를 구성하는 가장 작은 논리적 단위로, 개체의 특성을 나타낸다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;속성의 개수&lt;/b&gt;: &lt;b&gt;디그리(Degree)&lt;/b&gt; 또는 &lt;b&gt;차수&lt;/b&gt;라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;도메인(Domain)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&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;: 하나의 속성이 가질 수 있는 값들의 집합.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;역할&lt;/b&gt;: 속성 값이 허용된 범위를 벗어나지 않도록 검증하는 데 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #5c5c5c; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;릴레이션의 특징&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&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;
&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;&lt;b&gt;튜플 간의 순서는 의미가 없음&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;시간에 따라 릴레이션 인스턴스는 변화할 수 있음&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;속성들의 순서는 중요하지 않음&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;속성의 명칭은 유일해야 함&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;속성 값은 동일한 값이 존재할 수 있음&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;튜플을 식별하기 위해 키(Key)를 설정&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;속성의 값은 원자적(Atomic)이어야 함&lt;/b&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>G_Batman</author>
      <guid isPermaLink="true">https://g-batman.tistory.com/83</guid>
      <comments>https://g-batman.tistory.com/83#entry83comment</comments>
      <pubDate>Mon, 10 Feb 2025 16:29:22 +0900</pubDate>
    </item>
  </channel>
</rss>