<img src="https://blog.atj.sh/post-attachments/v/0194e507-718f-7380-8cb2-cb96a164684c" width="100%"/> <br /> <p> ์ด ๋ธ๋ก๊ทธ๋ ๋ค์ด๋ฒ ๋ธ๋ก๊ทธ๋ ํฐ์คํ ๋ฆฌ ๋ฑ์ ์๋น์ค ์์ด ์ด์๋๊ณ ์๋ค. ๊ธ์ ์ฒจ๋ถ๋๋ ์ด๋ฏธ์ง๋ค์ ์ํ ๋ณ๋์ ํด๋ผ์ฐ๋ ์๋น์ค ๋ํ ์ฌ์ฉ์ค์ด์ง ์๋ค. ๋ธ๋ก๊ทธ์์ ๋ณด์ฌ์ง๋ ๋ชจ๋ ์ด๋ฏธ์ง๋ PostgreSQL DB์ ์ ์ฅ๋๊ณ , ์ด๋ฏธ์ง ์กฐํ ์์ฒญ์ด ์ค๋ฉด ์๋ฒ๊ฐ DB์ ์ ์ฅ๋ ์ด๋ฏธ์ง ์ด์ง ์ ๋ณด๋ฅผ ๋ถ๋ฌ์์ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ฃผ๊ณ ์๋ค. </p> <h2> ๋๊ธฐ </h2> <p> ์ฒ์ ๋ธ๋ก๊ทธ๋ฅผ ์์ฑํ ๋น์์๋ ์ด๋ฏธ์ง ์ ๋ก๋ ๊ธฐ๋ฅ์ด ์์๋ค. ์ด ์ด๋ฏธ์ง ์ ๋ก๋ ๊ธฐ๋ฅ์ด ์๋ ๊ฒ ๋๋ฌธ์ ๊ธ์ ์ธ ๋ ์์ฌ์ด ์ํฉ์ด ๋ง์์ก๊ณ , ์ด์ ๋ ์ ๋ฐ ๊ตฌํํด๋๊ธฐ๋ก ๊ฒฐ์ ํ๋ค. </p> <p> ์ด ๋ธ๋ก๊ทธ์ ๊ธฐ์ ์คํ์ ์๋์ ๊ฐ๋ค. </p> <ul> <li><a href="https://www.rust-lang.org/" target="_blank">Rust lang</a> - ํ๋ก๊ทธ๋๋ฐ ์ธ์ด</li> <li><a href="https://github.com/tokio-rs/axum"target="_blank">axum</a> - Rust ๊ธฐ๋ฐ ์น ํ๋ ์์ํฌ</li> <li><a href="https://aws.amazon.com/ko/lambda/"target="_blank">AWS Lambda</a> - ์ปดํจํ ์ธํ๋ผ์คํธ๋ญ์ณ</li> <li><a href="https://postgresql.org/"target="_blank">PostgreSQL</a> - DB</li> <li><a href="https://kit.svelte.dev/"target="_blank">SvelteKit</a> - Svelte ๊ธฐ๋ฐ ์น ํ๋ ์์ํฌ</li> <li><a href="https://pages.cloudflare.com/"target="_blank">Cloudflare Pages</a> - ๋ฌด๋ฃ ์น ํธ์คํ ์๋น์ค</li> <li><a href="https://supabase.com/"target="_blank">Supabase</a> - BaaS & ๋ฌด๋ฃ PostgreSQL ํธ์คํ ์๋น์ค</li> </ul> <br /> <p> ๋๋ ์ด ๊ธฐ์ ์คํ์ ๋ณํจ ์์ด ์ ์งํ๊ณ ์ถ์๋ค. ๋ฌด์ธ๊ฐ ์๋น์ค๋ฅผ ๋ํ๊ธฐ๋ ์ซ์๋ค. ์ผ๋จ ์๋ํด๋ดค๋ค. </p> <h2> ๋ฉ์ธ ์์ด๋์ด: DB์ ์ด๋ฏธ์ง๋ฅผ ์ ์ฅํ์ </h2> <p> DB๋ ๋ฐ์ดํฐ๋ฅผ ์ค๋ซ๋์ ์ ์ฅํ๋ ์ญํ ์ ํ๋ค. ์ค๋ฌด์์๋ DB์ ์์น๊ฐ์ด๋ ์ด๋ฉ์ผ ์ ๋ณด์ ๊ฐ์ ์ซ์, ํ ์คํธ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ณค ํ๋ค. </p> <p> ๋ณดํต ์ด๋ฏธ์ง ํ์ผ์ DB๊ฐ ์๋ ๋ค๋ฅธ ๊ณณ์ ์ ์ฅ๋๋ค. ์๋ฅผ ๋ค๋ฉด NAS๋ ํด๋ผ์ฐ๋ ์คํ ๋ฆฌ์ง์ ์ ์ฅ๋๊ณค ํ๋ค. ๊ด๋ฆฌ์ ์ฉ์ด์ฑ๊ณผ ๋ฐ์ดํฐ ์ฑ๊ฒฉ์ ๋ฐ๋ฅธ ๋ถ๋ฆฌ ๋๋ฌธ์ด๋ค. </p> <p> ๊ทธ๋ฐ๋ฐ ๋๋, ์ซ์๋ ํ ์คํธ๋ ์ด๋ฏธ์ง๋ ๊ฒฐ๊ตญ 0๊ณผ 1๋ก ์ด๋ฃจ์ด์ง ์ด์ง ๋ฐ์ดํฐ๋ผ๊ณ ์๊ฐํ๋ค. ๊ทธ๋์ ๊ทธ๋ฅ DB์ ์ ๋ถ ๋ณด๊ดํด๋ณด๊ธฐ๋ก ํ๋ค. </p> <p> ๊ธฐ์ ์ ์ผ๋ก ์ดํด๋ณด๋, ์ง๊ธ ์ฌ์ฉ์ค์ธ DB์ธ <a href="https://www.postgresql.org/docs/current/datatype-binary.html" target="_blank">PostgreSQL์์ ์ด์ง ์ ๋ณด ์ ์ฅ์ ์ง์</a>ํ๋ค๋ ์ฌ์ค์ ํ์ธํ๋ค. ์ด๊ฒ ๋๋ค๋ฉด ์ด๋ฏธ์ง ์ ์ฅ์ด๋ ๋ ๋์๊ฐ์ ์ผ๋ฐ ํ์ผ ์ ์ฅ๋ ๊ฐ๋ฅํด์ง๋ค. </p> <h2> ํ ์ด๋ธ ์ค๊ณ </h2> <p> ํ์ผ์ ์ ์ฅํ๊ธฐ ์ํ ํ ์ด๋ธ์ ๋ค์๊ณผ ๊ฐ์ด ์ค๊ณํ๋ค. </p> <pre> CREATE TABLE public.post_attachment ( id UUID NOT NULL, content BYTEA NOT NULL, written_by_id INTEGER NOT NULL, file_extension VARCHAR(20) NOT NULL DEFAULT '', mimetype VARCHAR(255) NOT NULL, PRIMARY KEY (id) ); </pre> <ul> <li>id: ์ธํฐ๋ท์์ ํ์ผ์ ์ ๊ทผํ๊ธฐ ์ํ URL. UUID ํ์์ด๋ฉฐ, URL์ ๋ค์๊ณผ ๊ฐ์ด ํ ๋น๋๋ค. <code>https://blog.atj.sh/post-attachments/v/<b>0194e521-339c-7e10-b205-a2a9416fdb97</b></code></li> <li>content: ํ์ผ์ ์ด์ง ์ ๋ณด.</li> <li>written_by_id: ํ์ผ์ ์ ๋ก๋ํ ์ฌ๋์ ID.</li> <li>file_extension: ํ์ผ์ ํ์ฅ์. ํ์ผ์ด ์ ๋ก๋๋ ๋ ํ์ผ์ ์ด๋ฆ์์ ๊ฐ์ ธ์ DB์ ์ ์ฅํ๋ค. ํ์ผ์ ์๋ ์ด๋ฆ์ ์ ์ฅ๋์ง ์๊ณ ๋์ ํ์ฅ์๋ง ์ ์ฅ๋๋ค.</li> <li>mimetype: ํ์ผ์ mimetype. ํ์ผ์ด ์ ๋ก๋๋ ๋ <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob#instance_properties"><code>Blob.type()</code></a> ๋ฉ์๋๋ฅผ ํตํด ๊ฐ์ ธ์์ ธ์ DB์ ์ ์ฅ๋๋ค.</li> </ul> <h2> ์ ๋ก๋ ์๋๋ฆฌ์ค </h2> <p> ๋ด๊ฐ ๊ธ์ ์ฐ๋ฉฐ ์ด๋ฏธ์ง๋ฅผ ์ฒจ๋ถํ ๋ ์๋ฒ์์ ์ด๋ฃจ์ด์ง๋ ์์ ์ด๋ค. </p> <img src="https://blog.atj.sh/post-attachments/v/0194e521-339c-7e10-b205-a2a9416fdb97" class="full-unrounded"/> <p> ์ด๋ฏธ์ง ์์ถ์ ๊ฒฝ์ฐ์๋ ์๋ CloudFlare Pages ์๋ฒ๋จ์์ ์ฒ๋ฆฌ๋๋๋ก ํ๋ ค๊ณ ํ๋๋ฐ, <a href="https://community.cloudflare.com/t/rendering-svg-using-canvas-with-cloudflare-workers/90952" target="_blank">์ด๋ฏธ์ง ์์ถ์ ํต์ฌ์ ์ผ๋ก ํ์ํ Canvas API๊ฐ ์ง์๋์ง ์์์ ๊ด๋๊ณ </a>, AWS Lambda์์ ์ฒ๋ฆฌํ๊ธฐ์๋ <a href="https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html" target="_blank">ํ์ฉ ์์ฒญ ํฌ๊ธฐ๊ฐ 6MB ์์ค</a>์ด๋ผ์ ์์ฒญ์ด ๊ฑฐ๋ถ๋๋ ์ํฉ์ด ๋ฐ์ํ ๊ฒ์ผ๋ก ์์ํ๋ค. </p> <p> ๋ฐ๋ผ์ ๋คํธ์ํฌ ์์ฒญ์ ํ๊ธฐ ์ ์ ๋ธ๋ผ์ฐ์ ์์์ ์ด๋ฏธ์ง ์์ถ์ ๋ฏธ๋ฆฌ ์งํํ๋๋ก ๊ตฌํํ๋ค. ๊ฒฐ๋ก ์ ์ผ๋ก๋ ๋คํธ์ํฌ ํธ๋ํฝ์ด ์ ์ฝ๋๊ณ DB์ ์ ์ฅ๋๋ ๋ฐ์ดํฐ์ ํฌ๊ธฐ ๋ํ ์์์ก๋ค. </p> <p> ์์ถ ์๊ณ ๋ฆฌ์ฆ์ <a href="https://ko.wikipedia.org/wiki/WebP">WebP๋ก ์์ถํ๋ ๋ฐฉ๋ฒ</a>์ ์ฌ์ฉํ๋๋ฐ, 12MB ์ด๋ฏธ์ง๋ฅผ 100KB ์ ๋์ ํฌ๊ธฐ๋ก ์์ถํ ์ ๋๋ก ํจ์จ์ด ์ข์๋ค. </p> <h2> ์กฐํ ์๋๋ฆฌ์ค </h2> <p> ๋ฐฉ๋ฌธ์๊ฐ ์ด๋ฏธ์ง๋ฅผ ๋ณผ ๋ ์๋ฒ์์ ์ด๋ฃจ์ด์ง๋ ์์ ์ด๋ค. </p> <img src="https://blog.atj.sh/post-attachments/v/0194e521-2c4a-71d3-bb0b-fcf2bb5419c4" class="full-unrounded"/> <p> CloudFlare Pages์์ ์์ฒด์ ์ผ๋ก ์ง์๋๋ <a href="https://developers.cloudflare.com/workers/runtime-apis/cache/">Cache API</a>๋ฅผ ์ ์ฉํ๋ค. ๋๋ถ์ DB ์กฐํ๋ก ์ธํ ๋ถํ๊ฐ ์กฐ๊ธ์ด๋๋ง ์ค์ด๋ค์๋ค. ๋ํ ๋ธ๋ผ์ฐ์ ์์ ์์์ ์บ์ฑํ ์ ์๋๋ก <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control" target="_blank">Cache-Control ํค๋</a>๋ฅผ ์ ์ฉํ๋ค. </p> <img src="https://blog.atj.sh/post-attachments/v/0194e539-fa72-7c10-a22e-0d1a2bf03c76" width="100%" /> <p> ์ด๋ฏธ์ง ํ์ผ์ ์ ๊ณตํ ๋ ๋ธ๋ผ์ฐ์ ์์ ์์ฐ์ค๋ฝ๊ฒ ์ ๊ณต๋ ์ ์๋๋ก, ์ด๋ฏธ์ง์ ํ์์ HTTP ์๋ต ํค๋์ ์ ํํ๊ฒ ๊ธฐ์ ํ๋ ์์ ์ด ํ์ํ๋ค. ์ด๋ฏธ์ง๊ฐ ์๋ฒ์์ ์กฐํ๋ ๋ <a href="https://github.com/atjsh/rust-blog/blob/ad708e876d7def1683e282fe13576fa14f6b7e94/server/src/routers/post_attachment.rs#L44" target="_blank">์ด๋ฏธ์ง์ ๋ฉํ๋ฐ์ดํฐ๊ฐ HTTP ์๋ต ํค๋์ ์ ๋ด๊ฒจ์ ์ ๋ฌ๋๋๋ก ๊ตฌํ</a>ํ์๋ค. <br /> ๊ฐ์ธ์ ์ผ๋ก๋ ์ด ์์ ์ ํ๋ฉด์ HTTP Mimetype๊ณผ ์ด๋ฏธ์ง ํ์ฅ์์ ์ฐจ์ด๋ฅผ ์ข ๋ ๋ช ํํ๊ฒ ์ ์ ์์๋ค. </p> <h2>๊ฒฐ๋ก : ๊ตฌํ์ ์ฑ๊ณตํ์ง๋ง ๊ฐ์ ์ ์ฌ์ง๋ ์์</h2> <p> ์ด ๊ธ์์ ์ฌ์ฉ๋ ์ด๋ฏธ์ง๋ค์ ๋ชจ๋ ์ ๋ก์ง์ ํตํด DB๋ก๋ถํฐ ์กฐํ๋์ด ๋ธ๋ผ์ฐ์ ์ ๋ ๋๋ง๋ ๊ฒ์ด๋ค. ์ด๋ฏธ์ง๋ค์ด ์ ๋ณด์ธ๋ค๋ฉด ๊ตฌํ์ด ์์ ์ ์ผ๋ก ์๋ฃ๋์๋ค๋ ๋ป์ผ ๊ฒ์ด๋ค. ๋ง์ฝ ์ด๋ฏธ์ง๊ฐ ์ ๋ณด์ธ๋ค๋ฉด, ์ค๊ฐ์์ ๋ฏธ์ฒ ๋ฐ๊ฒฌ ๋ชปํ ๋ฒ๊ทธ๊ฐ ์์ด ๋ธ๋ผ์ฐ์ ๊น์ง ์ด๋ฏธ์ง๊ฐ ๋๋ฌํ์ง ๋ชปํ ๊ฒ์ผ๋ก ๋ณด๋ฉด ๋๋ค. </p> <p> HTTP ์บ์ฑ์ ์ ์ฉํ๊ธด ํ์ง๋ง ์๋ฒฝํ ํ์ ํ์ง ๋ชปํด์ ์ผ๋ถ๋ถ๋ง ๊ตฌํํ๋ค. ๊ธฐํ๊ฐ ๋๋ฉด ๋ ์์ ํ๊ฒ ๊ตฌํํ๊ณ ์ถ๋ค. </p> <p> 1MB ํฌ๊ธฐ๋ณด๋ค ์์ ์ด๋ฏธ์ง ์ ๊ณต์ ์ฑ๊ณตํ์ง๋ง, ๊ทธ๋ณด๋ค ํฐ ์ด๋ฏธ์ง๋ ๋์ฉ๋ ํ์ผ ์ ๊ณต์ ์์์ ์ค๋ช ํ ๋ฐ์ ๊ฐ์ด ์ฌ๋ฌ ์ ํ ๋๋ฌธ์ ํ๋ค๋ค. ์ฌ์ง์ด 10MB ์ ๋์ ํ์ผ ์ ๊ณต๋ ์ง๊ธ์ ๋ถ๊ฐ๋ฅํ ์ํฉ์ด๋ค. ์ด๋ฏธ์ง์ ๊ฒฝ์ฐ์๋ WebP ์์ถ์ด ์๋ ํจ์จ์ ์ด๋ผ ๋ถํธํ ์ ์ด ์๋ ์ํฉ์ด์ง๋ง, ๋ค๋ฅธ ํ์ผ์ ๊ฒฝ์ฐ์๋ ์ฉ๋ ์ ํ์ด ํฌ๊ฒ ๋ค๊ฐ์ฌ ์ ๋ฐ์ ์๋ค. </p> <p> ๊ธฐ์ ์คํ์ ์ ์งํ๋ ๋์์ ๋ ํฐ ํ์ผ์ ์๋นํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ์ฐ๊ตฌํด๋ด์ผ๊ฒ ๋ค. </p> <h2> ์์ค์ฝ๋ </h2> <p>์ด ๋ธ๋ก๊ทธ์ ์์ค์ฝ๋๋ ์คํ์์ค์ด๋ค. ๋ด <a href="https://github.com/atjsh/rust-blog" target="_blank">GitHub</a>์์ ํ์ธ ๊ฐ๋ฅํ๋ค.</p> <p> ์ด๋ฒ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋ ์ปค๋ฐ ๋ด์ญ์ ๋ค์ ๋งํฌ์์ ํ์ธ ๊ฐ๋ฅํ๋ค. <a href="https://github.com/atjsh/rust-blog/compare/89958ca4f61585c1a8c0036d6b31301769cccb3c...ad708e876d7def1683e282fe13576fa14f6b7e94?diff=unified" target="_blank">atjsh/rust-blog - 89958c...ad708e</a> </p> <h2> ๊ต์ฅํ ๋ง์กฑ </h2> <p> ๊ฑฐ์ 2๋ฌ๊ฐ ๋ฏธ๋ฃฌ ์์ ์ธ๋ฐ ํ๋ฃจ๋ง์ ๊ตฌํ์ ๋๋๋ค. ๋๋์ด ๋๋ด์ ์์ด ํ๋ จํ๋ค. </p>