[GCP] Cloud Spanner

[์›๋ณธ ๋งํฌ]

Cloud Spanner๋Š” GCP์—์„œ ์ž์ฒด์ ์œผ๋กœ ๊ตฌํ˜„, ๊ตฌ์ถ•ํ•ด์„œ ์ œ๊ณตํ•˜๋Š” ์ดˆ๋Œ€ํ˜• ๋ถ„์‚ฐ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„œ๋น„์Šค๋‹ค.
์ „์„ธ๊ณ„์— ์ง€๋ฆฌ์ ์œผ๋กœ ๋ถ„ํฌ๋˜๋Š” ์‹œ์Šคํ…œ์— ์ ํ•ฉํ•˜๋‹ค.

ํ˜„์กดํ•˜๋Š” ๋ฉ€ํ‹ฐ๋ฆฌ์ „-๋ฉ€ํ‹ฐ๋…ธ๋“œ-๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ํด๋ผ์šฐ๋“œ ์„œ๋น„์Šค ์ค‘์—์„œ ๊ฐ€์žฅ ๋นผ์–ด๋‚œ ์„ฑ๋Šฅ๊ณผ ์™„์„ฑ๋„๋ฅผ ์ž๋ž‘ํ•œ๋‹ค.

๊ทผ๋ž˜ ๋ถ€์ƒํ•œ CockroachDB๋งŒ ํ•ด๋„ Spanner ์ถœ์‹  ๊ฐœ๋ฐœ์ž๋“ค์ด ๋›ฐ์ณ๋‚˜์™€์„œ ๊ฒฝ์Ÿํ•˜๋ ค๊ณ  ๊ฑฐ์˜ ๋น„์Šทํ•˜๊ฒŒ ๋งŒ๋“  ๊ฒƒ์ธ๋ฐ, ์•„์ง ๊ทธ ์•„์„ฑ์— ๋„๋‹ฌํ•  ์ •๋„๋Š” ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.




๋น„์šฉ

์ž์„ธํ•œ ๊ฒƒ์€ ์‚ฌ์ดํŠธ๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
https://cloud.google.com/spanner/pricing?hl=ko

์ด๋งŒํ•œ ์„œ๋น„์Šค๊ฐ€ ๋”ฑํžˆ ์—†๋Š”๋งŒํผ, ๊ฐ€๊ฒฉ๋„ ๋งค์šฐ ๋น„์‹ผ ํŽธ์ด๋‹ค.

DB ๋…ธ๋“œ ๊ฐœ์ˆ˜, ๋ฉ€ํ‹ฐ๋ฆฌ์ „ ์—ฌ๋ถ€, ์‚ฌ์šฉํ•œ ์Šคํ† ๋ฆฌ์ง€ ์ด๋Ÿ‰์„ ๊ธฐ์ค€์œผ๋กœ ์š”๊ธˆ์„ ๋ถ€๊ณผํ•œ๋‹ค.
๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ™์€๊ฑด ๋˜ ๊ทธ๊ฒƒ๋Œ€๋กœ ๋น„์šฉ์ด ๋‚˜๊ฐˆ ๊ฒƒ์ด๋‹ค

์ผ๋‹จ ์‹ค์ œ๋กœ ๋…ธ๋“œ๊ฐ€ ๋– ์žˆ๋Š” ๊ฐœ์ˆ˜์™€ ์‹œ๊ฐ„์— ๋น„๋ก€ํ•ด์„œ ๊ณ ์ • ์š”๊ธˆ์ด ๋‚˜๊ฐ„๋‹ค.

์ผ๋‹จ ์„œ์šธ์— ๊ทธ๋ƒฅ ๋…ธ๋“œ๋ฅผ ํ•˜๋‚˜๋งŒ ๋„์šด๋‹ค๊ณ  ํ•ด๋„, ์‹œ๊ฐ„๋‹น 1.17 ๋‹ฌ๋Ÿฌ๋‹ˆ๊นŒ ํ•œ๋‹ฌ์— ๊ฑฐ์˜ 5๋งŒ์› ๋ˆ์ด ๋‚˜๊ฐ„๋‹ค.


๊ทผ๋ฐ ๋˜ ๋ฉ€ํ‹ฐ๋ฆฌ์ „์œผ๋กœ ํ•˜๋ฉด ์‹œ๊ฐ„๋‹น 3.90๋‹ฌ๋Ÿฌ, ํ•œ๋‹ฌ์— 117๋‹ฌ๋Ÿฌ=15๋งŒ์› ์ •๋„ ๋‚˜๊ฐ„๋‹ค.

๋˜ ์‚ฌ์šฉํ•œ ์Šคํ† ๋ฆฌ์ง€ ์šฉ๋Ÿ‰๋งŒํผ๋„ ๋น„์šฉ์„ ์ง€๋ถˆํ•œ๋‹ค.

์„œ์šธ์ด ๊ธฐ๊ฐ€๋‹น 0.39๋‹ฌ๋Ÿฌ๋‹ˆ๊นŒ, DB์— 500๊ธฐ๊ฐ€ ์ •๋„ ์ €์žฅํ•œ๋‹ค ์น˜๋ฉด ํ•œ๋‹ฌ์— 195๋‹ฌ๋Ÿฌ=25๋งŒ์›์ด ๋‚˜๊ฐ€๋Š” ์…ˆ์ด๋‹ค.

๋ฐฑ์—… ์Šคํ† ๋ฆฌ์ง€๋Š” ๊ธฐ๋ณธ ์Šคํ† ๋ฆฌ์ง€๋ณด๋‹ค๋Š” ์‹ธ์ง€๋งŒ, ๊ทธ๋ž˜๋„ ์—ฌ์ „ํžˆ ๋น„์‹ธ๋‹ค.

์ด๋Ÿฌ๋ฉด ์•„๋ฌด๋ฆฌ ์ž‘๊ฒŒ์žก์•„๋„ ์ตœ์†Œ ํ•œ๋‹ฌ์— ๋ฐฑ๋งŒ์›์€ ์žก์•„์•ผ ํ•  ๊ฒƒ ๊ฐ™๊ณ , ์ œ๋Œ€๋กœ ์“ฐ๋‹ค๋ณด๋ฉด ์ˆ˜๋ฐฑ๋งŒ-์ˆ˜์ฒœ๋งŒ์›์€ ์‰ฝ๊ฒŒ ๊นจ์งˆ ๊ฒƒ ๊ฐ™๋‹ค.




์ธ์Šคํ„ด์Šค ๋งŒ๋“ค๊ธฐ

์šฐ์„  Cloud Spanner ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ด์„œ ์„œ๋น„์Šค๋ฅผ ํ™œ์„ฑํ™”ํ•œ๋‹ค.
์•„์ง ์จ๋ณธ ์ ์ด ์—†๋‹ค๋ฉด, 3๊ฐœ์›”๋™์•ˆ ์ œํ•œ์ ์ธ ๋ฌด๋ฃŒ์ฒดํ—˜์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์ด๋ฆ„ ์ง“๊ณ , ๋ฆฌ์ „์„ ์„ ํƒํ•œ๋‹ค.

์ฒดํ—˜ํŒ์—์„œ๋Š” ๋ช‡๊ฐ€์ง€ ์ œํ•œ์ ์ธ ๋ฆฌ์ „๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


๊ทธ๋ž˜์„œ ์ด๋Ÿฐ ๋Œ€์‹œ๋ณด๋“œ๊ฐ€ ๋œจ๋ฉด ์ผ๋‹จ์€ ์ƒ์„ฑ์ด ๋œ ๊ฒƒ์ด๋‹ค.




๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ƒ์„ฑ

๊ทธ๋Ÿผ ์ด์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ฒ ๋‹ค.
์ด๊ฒƒ๋„ ๋ญ ์–ด๋ ค์šธ ๊ฒƒ์€ ์—†๋‹ค.

๊ทธ๋ƒฅ ์ด๋ฆ„ ์ง“๊ณ , SQL ํ˜ธํ™˜์„ฑ๋งŒ ๊ณจ๋ผ์ค€๋‹ค.

Google SQL์€ ๊ตฌ๊ธ€ ์ž์ฒด ๊ทœ๊ฒฉ์ด๊ณ ,
Postgresql์€ ์™„์ „ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ Postgres ๋ฌธ๋ฒ•์„ ์–ด๋А์ •๋„ ์ง€์›ํ•œ๋‹ค.

๋‚˜๋Š” ์ข€๋” ์ž๋ฃŒ๊ฐ€ ๋งŽ๊ณ  ๋ฒ”์šฉ์„ฑ์ด ์ข‹์€ Postgres๋ฅผ ๋”ฐ๋ฅด๊ฒ ๋‹ค...

๊ทธ๋ž˜์„œ ์ด๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด์ง€๋ฉด ๋œ ๊ฒƒ์ด๋‹ค.




ํ…Œ์ด๋ธ” ๋งŒ๋“ค๊ธฐ

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ๋งŒ๋“ค์–ด์กŒ์œผ๋ฉด, ํ…Œ์ด๋ธ” ์ƒ์„ฑ ๋ฒ„ํŠผ์ด๋‚˜ SQL ํŽธ์ง‘๊ธฐ๋ฅผ ํ†ตํ•ด์„œ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

ํƒ€์ž…์— serial์ด ์•ˆ๋“ค์–ด๊ฐ„๋‹ค๊ฑฐ๋‚˜, default์— now()๋ฅผ ์ง‘์–ด๋„ฃ์„ ์ˆ˜ ์—†๋‹ค๊ฑฐ๋‚˜ ํ•˜๋Š” ์ œํ•œ์ด ์ข€ ์ƒ๊ธฐ๊ธด ํ–ˆ๋Š”๋ฐ, ๊ทธ๋ž˜๋„ ๋Œ€์ฒด๋กœ๋Š” postgres์™€ ์—‡๋น„์Šทํ•˜๊ฒŒ ์งค ์ˆ˜๋Š” ์žˆ๋‹ค.

๊ทธ๋ ‡๊ฒŒ ํ•ด์„œ ๋งŒ๋“ค๋ฉด

์ด๋Ÿฐ์‹์œผ๋กœ ์ƒ์„ฑ์ด ๋˜์—ˆ์„ ๊ฒƒ์ด๊ณ 

ํŽธ์ง‘๊ธฐ๋ฅผ ํ†ตํ•ด์„œ ๊ฐ€์ง€๊ณ  ๋†€ ์ˆ˜ ์žˆ๊ฒ ๋‹ค.

๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ์šฉ ๋„๊ตฌ๋„ ์žˆ๊ณ 

APM์šฉ ๋ชจ๋‹ˆํ„ฐ๋ง ๊ธฐ๋Šฅ๋“ค๋„ ์žˆ๊ณ 

๋Œ€์ถฉ ์žˆ์„๊ฑด ๋‹ค ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.




์ฝ”๋“œ์—์„œ ์ ‘์†ํ•˜๊ธฐ (Node.js)

ํ”„๋กœ๊ทธ๋žจ์—์„œ spanner์— ์ ‘์†ํ•ด์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, ๋ณดํ†ต ์ „์šฉ ๋ชจ๋“ˆ์„ ์„ค์น˜ํ•˜๊ณ , gcloud๋กœ ์ธ์ฆ์„ ๋จน์ธ ์ƒํƒœ์—์„œ ์จ๋จน์œผ๋ฉด ๋œ๋‹ค.
Node.js์˜ ๊ฒฝ์šฐ์—๋Š” ๋‹ค์Œ ๋ชจ๋“ˆ์ด ํ•„์š”ํ•˜๋‹ค.

npm i @google-cloud/spanner

์•„๋ž˜๋Š” Singers์™€ Albums ํ…Œ์ด๋ธ”์„ ๋งŒ๋“œ๋Š” ๊ฐ„๋‹จํ•œ ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค.

// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
const projectId = 'ํ”„๋กœ์ ํŠธID';
const instanceId = 'test-spanner';
const databaseId = 'test-db';

// Creates a client
const spanner = new Spanner({
  projectId: projectId,
});

const instance = spanner.instance(instanceId);

// Note: Cloud Spanner interprets Node.js numbers as FLOAT64s, so they
// must be converted to strings before being inserted as INT64s
const request = {
  schema: [
    `CREATE TABLE Singers (
      SingerId    INT64 NOT NULL,
      FirstName   STRING(1024),
      LastName    STRING(1024),
      SingerInfo  BYTES(MAX),
      FullName    STRING(2048) AS (ARRAY_TO_STRING([FirstName, LastName], " ")) STORED,
    ) PRIMARY KEY (SingerId)`,
    `CREATE TABLE Albums (
      SingerId    INT64 NOT NULL,
      AlbumId     INT64 NOT NULL,
      AlbumTitle  STRING(MAX)
    ) PRIMARY KEY (SingerId, AlbumId),
    INTERLEAVE IN PARENT Singers ON DELETE CASCADE`,
  ],
};

async function main() {
    // Creates a database
    const [database, operation] = await instance.createDatabase(
        databaseId,
        request
    );

    console.log(`Waiting for operation on ${database.id} to complete...`);
    await operation.promise();

    console.log(`Created database ${databaseId} on instance ${instanceId}.`);
}

main()


์ฐธ์กฐ
https://cloud.google.com/spanner/docs/getting-started/nodejs?hl=ko