Spanner untuk pengguna Cassandra

Dokumen ini membandingkan konsep dan praktik Apache Cassandra dan Spanner. Panduan ini mengasumsikan bahwa Anda sudah terbiasa dengan Cassandra dan ingin memigrasikan aplikasi yang ada atau mendesain aplikasi baru saat menggunakan Spanner sebagai database.

Cassandra dan Spanner adalah database terdistribusi berskala besar yang dibuat untuk aplikasi yang memerlukan skalabilitas tinggi dan latensi rendah. Meskipun kedua database ini dapat mendukung beban kerja NoSQL yang berat, Spanner menyediakan fitur lanjutan untuk pemodelan data, kueri, dan operasi transaksional. Untuk informasi selengkapnya tentang cara Spanner memenuhi kriteria database NoSQL, lihat Spanner untuk workload non-relasional.

Bermigrasi dari Cassandra ke Spanner

Untuk bermigrasi dari Cassandra ke Spanner, Anda dapat menggunakan Adaptor Proxy Cassandra ke Spanner. Alat open source ini memungkinkan Anda memigrasikan beban kerja dari Cassandra ke Spanner tanpa perubahan pada logika aplikasi Anda.

Konsep inti

Bagian ini membandingkan konsep utama Cassandra dan Spanner.

Terminologi

Cassandra Spanner
Cluster Instance

Cluster Cassandra setara dengan instance Spanner - kumpulan server dan resource penyimpanan. Karena Spanner adalah layanan terkelola, Anda tidak perlu mengonfigurasi hardware atau software yang mendasarinya. Anda hanya perlu menentukan jumlah node yang ingin dicadangkan untuk instance atau memilih penskalaan otomatis untuk menskalakan instance secara otomatis. Instance bertindak seperti penampung untuk database, dan topologi replikasi data (regional, region ganda, atau multi-region) dipilih di tingkat instance.
Keyspace Database

Keyspace Cassandra setara dengan database Spanner, yang merupakan kumpulan tabel dan elemen skema lainnya (misalnya, indeks dan peran). Tidak seperti ruang kunci, Anda tidak perlu mengonfigurasi faktor replikasi. Spanner secara otomatis mereplikasi data Anda ke region yang ditetapkan di instance Anda.
Tabel Tabel

Di Cassandra dan Spanner, tabel adalah kumpulan baris yang diidentifikasi oleh kunci utama yang ditentukan dalam skema tabel.
Partisi Pisahkan

Cassandra dan Spanner diskalakan dengan melakukan sharding data. Di Cassandra, setiap shard disebut partisi, sedangkan di Spanner, setiap shard disebut bagian. Cassandra menggunakan partisi hash, yang berarti setiap baris ditetapkan secara independen ke node penyimpanan berdasarkan hash kunci utama. Spanner memiliki shard rentang, yang berarti baris yang berdekatan di ruang kunci utama juga berdekatan dalam penyimpanan (kecuali di batas pemisahan). Spanner menangani pemisahan dan penggabungan berdasarkan beban dan penyimpanan, dan ini bersifat transparan untuk aplikasi. Implikasi utama adalah bahwa tidak seperti Cassandra, pemindaian rentang pada awalan kunci utama adalah operasi yang efisien di Spanner.
Baris Baris

Di Cassandra dan Spanner, baris adalah kumpulan kolom yang diidentifikasi secara unik oleh kunci utama. Seperti Cassandra, Spanner mendukung kunci utama gabungan. Tidak seperti Cassandra, Spanner tidak membedakan antara kunci partisi dan kunci pengurutan, karena data di-shard rentang. Anda dapat menganggap Spanner hanya memiliki kunci pengurutan, dengan partisi yang dikelola di balik layar.
Kolom Kolom

Di Cassandra dan Spanner, kolom adalah kumpulan nilai data yang memiliki jenis yang sama. Ada satu nilai untuk setiap baris tabel. Untuk mengetahui informasi selengkapnya tentang cara membandingkan jenis kolom Cassandra dengan Spanner, lihat Jenis Data.

Arsitektur

Cluster Cassandra terdiri dari sekumpulan server dan penyimpanan yang ditempatkan bersama dengan server tersebut. Fungsi hash memetakan baris dari ruang kunci partisi ke node virtual (vnode). Kumpulan vnode kemudian ditetapkan secara acak ke setiap server untuk menayangkan sebagian ruang kunci cluster. Penyimpanan untuk vnode terpasang secara lokal ke node penayangan. Driver klien terhubung langsung ke node penayangan dan menangani load balancing serta perutean kueri.

Instance Spanner terdiri dari kumpulan server dalam topologi replikasi. Spanner secara dinamis melakukan sharding setiap tabel ke dalam rentang baris berdasarkan penggunaan CPU dan disk. Shard ditetapkan ke node komputasi untuk ditayangkan. Data disimpan secara fisik di Colossus, sistem file terdistribusi Google, terpisah dari node komputasi. Driver klien terhubung ke server frontend Spanner yang melakukan pemilihan rute permintaan dan load balancing. Untuk mempelajari lebih lanjut, lihat laporan resmi Proses Operasi Baca & Tulis Spanner.

Pada tingkat tinggi, kedua arsitektur diskalakan saat resource ditambahkan ke cluster yang mendasarinya. Pemisahan komputasi dan penyimpanan Spanner memungkinkan beban di antara node komputasi diimbangi dengan lebih cepat sebagai respons terhadap perubahan beban kerja. Tidak seperti Cassandra, pemindahan shard tidak melibatkan pemindahan data karena data tetap berada di Colossus. Selain itu, partisi berbasis rentang Spanner mungkin lebih alami untuk aplikasi yang mengharapkan data diurutkan berdasarkan kunci partisi. Sisi lain dari partisi berbasis rentang adalah beban kerja yang menulis ke salah satu ujung ruang kunci (misalnya, tabel yang diberi kunci berdasarkan stempel waktu saat ini) mungkin mengalami hotspotting tanpa pertimbangan desain skema tambahan. Untuk mengetahui informasi selengkapnya tentang teknik untuk mengatasi hotspot, lihat Praktik terbaik desain skema.

Konsistensi

Dengan Cassandra, Anda harus menentukan tingkat konsistensi untuk setiap operasi. Jika Anda menggunakan tingkat konsistensi kuorum, mayoritas node replika harus merespons node koordinator agar operasi dianggap berhasil. Jika Anda menggunakan level konsistensi satu, Cassandra memerlukan satu node replika untuk merespons agar operasi dianggap berhasil.

Spanner memberikan konsistensi yang kuat. Spanner API tidak mengekspos replika ke klien. Klien Spanner berinteraksi dengan Spanner seolah-olah itu adalah satu database mesin. Operasi tulis selalu ditulis ke sebagian besar replika sebelum dikonfirmasi kepada pengguna. Setiap operasi baca berikutnya akan mencerminkan data yang baru ditulis. Aplikasi dapat memilih untuk membaca snapshot database pada satu waktu di masa lalu, yang mungkin memiliki manfaat performa dibandingkan dengan pembacaan yang kuat. Untuk mengetahui informasi selengkapnya tentang properti konsistensi Spanner, lihat Ringkasan transaksi.

Spanner dibuat untuk mendukung konsistensi dan ketersediaan yang diperlukan dalam aplikasi skala besar. Spanner memberikan konsistensi yang kuat dalam skala besar dan dengan performa tinggi. Untuk kasus penggunaan yang memerlukannya, Spanner mendukung pembacaan snapshot yang melonggarkan persyaratan keaktualan.

Pemodelan data

Bagian ini membandingkan model data Cassandra dan Spanner.

Deklarasi tabel

Sintaksis deklarasi tabel cukup mirip di Cassandra dan Spanner. Anda menentukan nama tabel, nama dan jenis kolom, serta kunci utama yang secara unik mengidentifikasi baris. Perbedaan utamanya adalah Cassandra dipartisi hash dan membuat perbedaan antara kunci partisi dan kunci pengurutan, sedangkan Spanner dipartisi rentang. Spanner dapat dianggap hanya memiliki kunci pengurutan, dengan partisi yang otomatis dikelola di balik layar. Seperti Cassandra, Spanner mendukung kunci utama gabungan.

Satu bagian kunci utama

Perbedaan antara Cassandra dan Spanner terletak pada nama jenis dan lokasi klausa kunci utama.

Cassandra Spanner
CREATE TABLE users (
  user_id    bigint,
  first_name text,
  last_name  text,
  PRIMARY KEY (user_id)
)
    
CREATE TABLE users (
  user_id    int64,
  first_name string(max),
  last_name  string(max),
) PRIMARY KEY (user_id)
    

Beberapa bagian kunci utama

Untuk Cassandra, bagian kunci utama pertama adalah "kunci partisi" dan bagian kunci utama berikutnya adalah "kunci pengurutan". Untuk Spanner, tidak ada kunci partisi terpisah. Data disimpan dan diurutkan berdasarkan seluruh kunci utama komposit.

Cassandra Spanner
CREATE TABLE user_items (
  user_id    bigint,
  item_id    bigint,
  first_name text,
  last_name  text,
  PRIMARY KEY (user_id, item_id)
)
    
CREATE TABLE user_items (
  user_id    int64,
  item_id    int64,
  first_name string(max),
  last_name  string(max),
) PRIMARY KEY (user_id, item_id)
    

Kunci partisi gabungan

Untuk Cassandra, kunci partisi dapat berupa gabungan. Tidak ada kunci partisi terpisah di Spanner. Data disimpan dan diurutkan berdasarkan seluruh kunci utama komposit.

Cassandra Spanner
CREATE TABLE user_category_items (
  user_id     bigint,
  category_id bigint,
  item_id     bigint,
  first_name  text,
  last_name   text,
  PRIMARY KEY ((user_id, category_id), item_id)
)
    
CREATE TABLE user_category_items (
  user_id     int64,
  category_id int64,
  item_id     int64,
  first_name  string(max),
  last_name   string(max),
) PRIMARY KEY (user_id, category_id, item_id)
    

Jenis data

Bagian ini membandingkan jenis data Cassandra dan Spanner. Untuk mengetahui informasi selengkapnya tentang jenis Spanner, lihat Jenis data di GoogleSQL.

Cassandra Spanner
Jenis Numerik Bilangan bulat standar:

bigint (bilangan bulat 64-bit yang telah ditandai)
int (bilangan bulat 32-bit yang telah ditandai)
smallint (bilangan bulat 16-bit yang telah ditandai)
tinyint (bilangan bulat 8-bit yang telah ditandai)
int64 (Bilangan bulat 64-bit yang telah ditandai)

Spanner mendukung satu jenis data lebar 64-bit untuk bilangan bulat yang telah ditandai.
Floating point standar:

double (floating point IEEE-754 64-bit)
float (floating point IEEE-754 32-bit)
float64 (floating point IEEE-754 64-bit)
float32 (floating point IEEE-754 32-bit)
Angka presisi variabel:

varint (bilangan bulat presisi variabel)
decimal (desimal presisi variabel)
Untuk angka desimal presisi tetap, gunakan numeric (presisi 38 skala 9). Jika tidak, gunakan string bersama dengan library bilangan bulat presisi variabel lapisan aplikasi.
Jenis String text
varchar
string(max)

text dan varchar menyimpan serta memvalidasi string UTF-8. Di Spanner, kolom string harus menentukan panjang maksimumnya (tidak ada dampak pada penyimpanan; ini untuk tujuan validasi).
blob bytes(max)

Untuk menyimpan data biner, gunakan jenis data bytes.
Jenis Tanggal dan Waktu date date
duration int64

Spanner tidak mendukung jenis data durasi khusus. Gunakan int64 untuk menyimpan durasi nanodetik.
time int64

Spanner tidak mendukung jenis data waktu dalam hari khusus. Gunakan int64 untuk menyimpan offset nanosekon dalam sehari.
timestamp timestamp
Jenis Penampung Jenis yang ditentukan pengguna json atau proto
list array

Gunakan array untuk menyimpan daftar objek yang diketik.
map json atau proto

Spanner tidak mendukung jenis peta khusus. Gunakan kolom json atau proto untuk mewakili peta. Untuk informasi selengkapnya, lihat Menyimpan peta besar sebagai tabel yang diselingi.
set array

Spanner tidak mendukung jenis set khusus. Gunakan kolom array untuk mewakili set, dengan aplikasi yang mengelola keunikan yang ditetapkan. Untuk mengetahui informasi selengkapnya, lihat Menyimpan peta besar sebagai tabel yang diselingi, yang juga dapat digunakan untuk menyimpan set besar.

Pola penggunaan dasar

Contoh kode berikut menunjukkan perbedaan antara kode klien Cassandra dan Spanner di Go. Untuk informasi selengkapnya, lihat Library klien Spanner.

Inisialisasi klien

Di klien Cassandra, Anda membuat objek cluster yang mewakili cluster Cassandra yang mendasarinya, membuat instance objek sesi yang memisahkan koneksi ke cluster, dan mengeluarkan kueri pada sesi. Di Spanner, Anda membuat objek klien yang terikat ke database tertentu, dan mengeluarkan permintaan database pada objek klien.

Contoh Cassandra

Go

import "github.com/gocql/gocql"

...

cluster := gocql.NewCluster("<address>")
cluster.Keyspace = "<keyspace>"
session, err := cluster.CreateSession()
if err != nil {
  return err
}
defer session.Close()

// session.Query(...)

Contoh Spanner

Go

import "cloud.google.com/go/spanner"

...

client, err := spanner.NewClient(ctx,
    fmt.Sprintf("projects/%s/instances/%s/databases/%s", project, instance, database))
defer client.Close()

// client.Apply(...)

Membaca data

Operasi baca di Spanner dapat dilakukan melalui API gaya nilai kunci dan API kueri. Sebagai pengguna Cassandra, Anda mungkin merasa lebih akrab dengan API kueri. Perbedaan utama dalam API kueri adalah Spanner memerlukan argumen bernama (tidak seperti argumen posisional ? di Cassandra). Nama argumen dalam kueri Spanner harus diawali dengan @.

Contoh Cassandra

Go

stmt := `SELECT
           user_id, first_name, last_name
         FROM
           users
         WHERE
           user_id = ?`

var (
  userID    int
  firstName string
  lastName  string
)

err := session.Query(stmt, 1).Scan(&userID, &firstName, &lastName)

Contoh Spanner

Go

stmt := spanner.Statement{
  SQL: `SELECT
          user_id, first_name, last_name
        FROM
          users
        WHERE
          user_id = @user_id`,
  Params: map[string]any{"user_id": 1},
}

var (
  userID    int64
  firstName string
  lastName  string
)

err := client.Single().Query(ctx, stmt).Do(func(row *spanner.Row) error {
  return row.Columns(&userID, &firstName, &lastName)
})

Masukkan data

INSERT Cassandra setara dengan INSERT OR UPDATE Spanner. Anda harus menentukan kunci utama lengkap untuk penyisipan. Spanner mendukung DML dan API mutasi gaya nilai kunci. API mutasi gaya nilai kunci direkomendasikan untuk penulisan yang tidak penting karena latensi yang lebih rendah. Spanner DML API memiliki lebih banyak fitur karena mendukung platform SQL lengkap (termasuk penggunaan ekspresi dalam pernyataan DML).

Contoh Cassandra

Go

stmt := `INSERT INTO
           users (user_id, first_name, last_name)
         VALUES
           (?, ?, ?)`
err := session.Query(stmt, 1, "John", "Doe").Exec()

Contoh Spanner

Go

_, err := client.Apply(ctx, []*spanner.Mutation{
  spanner.InsertOrUpdateMap(
    "users", map[string]any{
      "user_id":    1,
      "first_name": "John",
      "last_name":  "Doe",
    }
  )})

Menyisipkan data secara batch

Di Cassandra, Anda dapat menyisipkan beberapa baris menggunakan pernyataan batch. Di Spanner, operasi commit dapat berisi beberapa mutasi. Spanner menyisipkan mutasi ini ke database secara atomik.

Contoh Cassandra

Go

stmt := `INSERT INTO
           users (user_id, first_name, last_name)
         VALUES
           (?, ?, ?)`
b := session.NewBatch(gocql.UnloggedBatch)
b.Entries = []gocql.BatchEntry{
  {Stmt: stmt, Args: []any{1, "John", "Doe"}},
  {Stmt: stmt, Args: []any{2, "Mary", "Poppins"}},
}
err = session.ExecuteBatch(b)

Contoh Spanner

Go

_, err := client.Apply(ctx, []*spanner.Mutation{
  spanner.InsertOrUpdateMap(
    "users", map[string]any{
       "user_id":    1,
       "first_name": "John",
       "last_name":  "Doe"
    },
  ),
  spanner.InsertOrUpdateMap(
    "users", map[string]any{
       "user_id":    2,
       "first_name": "Mary",
       "last_name":  "Poppins",
    },
  ),
})

Menghapus data

Penghapusan Cassandra memerlukan penentuan kunci utama baris yang akan dihapus. Hal ini mirip dengan mutasi DELETE di Spanner.

Contoh Cassandra

Go

stmt := `DELETE FROM
           users
         WHERE
           user_id = ?`
err := session.Query(stmt, 1).Exec()

Contoh Spanner

Go

_, err := client.Apply(ctx, []*spanner.Mutation{
  spanner.Delete("users", spanner.Key{1}),
})

Topik lanjutan

Bagian ini berisi informasi tentang cara menggunakan fitur Cassandra yang lebih canggih di Spanner.

Menulis stempel waktu

Cassandra memungkinkan mutasi menentukan stempel waktu tulis secara eksplisit untuk sel tertentu menggunakan klausa USING TIMESTAMP. Biasanya, fitur ini digunakan untuk memanipulasi semantik last-writer-wins Cassandra.

Spanner tidak mengizinkan klien menentukan stempel waktu setiap penulisan. Setiap sel ditandai secara internal dengan stempel waktu TrueTime pada saat nilai sel di-commit. Karena Spanner menyediakan antarmuka yang sangat konsisten dan dapat diserialisasi secara ketat, sebagian besar aplikasi tidak memerlukan fungsi USING TIMESTAMP.

Jika Anda mengandalkan USING TIMESTAMP Cassandra untuk logika khusus aplikasi, Anda dapat menambahkan kolom TIMESTAMP tambahan ke skema Spanner, yang dapat melacak waktu perubahan di tingkat aplikasi. Pembaruan pada baris kemudian dapat digabungkan dalam transaksi baca-tulis. Contoh:

Contoh Cassandra

Go

stmt := `INSERT INTO
           users (user_id, first_name, last_name)
         VALUES
           (?, ?, ?)
         USING TIMESTAMP
           ?`
err := session.Query(stmt, 1, "John", "Doe", ts).Exec()

Contoh Spanner

  1. Buat skema dengan kolom stempel waktu pembaruan eksplisit.

    GoogleSQL

    CREATE TABLE users (
      user_id    INT64,
      first_name STRING(MAX),
      last_name  STRING(MAX),
      update_ts  TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
    ) PRIMARY KEY (user_id)
  2. Sesuaikan logika untuk memperbarui baris dan menyertakan stempel waktu.

    Go

    func ShouldUpdateRow(ctx context.Context, txn *spanner.ReadWriteTransaction, updateTs time.Time) (bool, error) {
      // Read the existing commit timestamp.
      row, err := txn.ReadRow(ctx, "users", spanner.Key{1}, []string{"update_ts"})
    
      // Treat non-existent row as NULL timestamp - the row should be updated.
      if spanner.ErrCode(err) == codes.NotFound {
        return true, nil
      }
    
      // Propagate unexpected errors.
      if err != nil {
        return false, err
      }
    
      // Check if the committed timestamp is newer than the update timestamp.
      var committedTs *time.Time
      err = row.Columns(&committedTs)
      if err != nil {
        return false, err
      }
      if committedTs != nil && committedTs.Before(updateTs) {
        return false, nil
      }
    
      // Committed timestamp is older than update timestamp - the row should be updated.
      return true, nil
    }
  3. Periksa kondisi kustom sebelum memperbarui baris.

    Go

    _, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
      // Check if the row should be updated.
      ok, err := ShouldUpdateRow(ctx, txn, time.Now())
      if err != nil {
        return err
      }
      if !ok {
        return nil
      }
    
      // Update the row.
      txn.BufferWrite([]*spanner.Mutation{
        spanner.InsertOrUpdateMap("users", map[string]any{
          "user_id":    1,
          "first_name": "John",
          "last_name":  "Doe",
          "update_ts":  spanner.CommitTimestamp,
        })})
    
      return nil
    })

Mutasi bersyarat

Pernyataan INSERT ... IF EXISTS di Cassandra setara dengan pernyataan INSERT di Spanner. Dalam kedua kasus tersebut, penyisipan akan gagal jika baris sudah ada.

Di Cassandra, Anda juga dapat membuat pernyataan DML yang menentukan kondisi, dan pernyataan akan gagal jika kondisi bernilai salah. Di Spanner, Anda dapat menggunakan mutasi UPDATE kondisional dalam transaksi baca-tulis. Misalnya, untuk memperbarui baris hanya jika kondisi tertentu ada:

Contoh Cassandra

Go

stmt := `UPDATE
           users
         SET
           last_name = ?
         WHERE
           user_id = ?
         IF
           first_name = ?`
err := session.Query(stmt, 1, "Smith", "John").Exec()

Contoh Spanner

  1. Sesuaikan logika untuk memperbarui baris dan menyertakan kondisi.

    Go

    func ShouldUpdateRow(ctx context.Context, txn *spanner.ReadWriteTransaction) (bool, error) {
      row, err := txn.ReadRow(ctx, "users", spanner.Key{1}, []string{"first_name"})
      if err != nil {
        return false, err
      }
    
      var firstName *string
      err = row.Columns(&firstName)
      if err != nil {
        return false, err
      }
      if firstName != nil && firstName == "John" {
        return false, nil
      }
      return true, nil
    }
  2. Periksa kondisi kustom sebelum memperbarui baris.

    Go

    _, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
      ok, err := ShouldUpdateRow(ctx, txn, time.Now())
      if err != nil {
        return err
      }
      if !ok {
        return nil
      }
    
      txn.BufferWrite([]*spanner.Mutation{
        spanner.InsertOrUpdateMap("users", map[string]any{
          "user_id":    1,
          "last_name":  "Smith",
          "update_ts":  spanner.CommitTimestamp,
        })})
    
      return nil
    })

TTL

Cassandra mendukung penetapan nilai time to live (TTL) di tingkat baris atau kolom. Di Spanner, TTL dikonfigurasi di tingkat baris, dan Anda menetapkan kolom bernama sebagai waktu habis masa berlaku untuk baris. Untuk mengetahui informasi selengkapnya, lihat Ringkasan waktu tunggu (TTL).

Contoh Cassandra

Go

stmt := `INSERT INTO
           users (user_id, first_name, last_name)
         VALUES
           (?, ?, ?)
         USING TTL 86400
           ?`
err := session.Query(stmt, 1, "John", "Doe", ts).Exec()

Contoh Spanner

  1. Membuat skema dengan kolom stempel waktu pembaruan eksplisit

    GoogleSQL

    CREATE TABLE users (
      user_id    INT64,
      first_name STRING(MAX),
      last_name  STRING(MAX),
      update_ts  TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
    ) PRIMARY KEY (user_id),
      ROW DELETION POLICY (OLDER_THAN(update_ts, INTERVAL 1 DAY));
  2. Sisipkan baris dengan stempel waktu commit.

    Go

    _, err := client.Apply(ctx, []*spanner.Mutation{
      spanner.InsertOrUpdateMap("users", map[string]any{
                  "user_id":    1,
                  "first_name": "John",
                  "last_name":  "Doe",
                  "update_ts":  spanner.CommitTimestamp}),
    })

Menyimpan peta besar sebagai tabel sisipan.

Cassandra mendukung jenis map untuk menyimpan key-value pair yang diurutkan. Untuk menyimpan jenis map yang berisi data dalam jumlah kecil di Spanner, Anda dapat menggunakan jenis JSON atau PROTO, yang memungkinkan Anda menyimpan data semi-terstruktur dan terstruktur. Pembaruan pada kolom tersebut mengharuskan seluruh nilai kolom ditulis ulang. Jika Anda memiliki kasus penggunaan dengan data dalam jumlah besar yang disimpan di map Cassandra, dan hanya sebagian kecil map yang perlu diperbarui, menggunakan tabel INTERLEAVED mungkin cocok. Misalnya, untuk mengaitkan data nilai kunci dalam jumlah besar dengan pengguna tertentu:

Contoh Cassandra

CREATE TABLE users (
  user_id     bigint,
  attachments map<string, string>,
  PRIMARY KEY (user_id)
)

Contoh Spanner

CREATE TABLE users (
  user_id  INT64,
) PRIMARY KEY (user_id);

CREATE TABLE user_attachments (
  user_id        INT64,
  attachment_key STRING(MAX),
  attachment_val STRING(MAX),
) PRIMARY KEY (user_id, attachment_key);

Dalam hal ini, baris lampiran pengguna disimpan bersama dengan baris pengguna yang sesuai, dan dapat diambil serta diperbarui secara efisien bersama dengan baris pengguna. Anda dapat menggunakan API baca-tulis di Spanner untuk berinteraksi dengan tabel yang diselingi. Untuk mengetahui informasi selengkapnya tentang interleaving, lihat Membuat tabel induk dan turunan.

Pengalaman developer

Bagian ini membandingkan alat developer Spanner dan Cassandra.

Pengembangan lokal

Anda dapat menjalankan Cassandra secara lokal untuk pengembangan dan pengujian unit. Spanner menyediakan lingkungan yang serupa untuk pengembangan lokal melalui emulator Spanner. Emulator menyediakan lingkungan fidelitas tinggi untuk pengembangan interaktif dan pengujian unit. Untuk mengetahui informasi selengkapnya, lihat Mengemulasi Spanner secara lokal.

Command line

Spanner yang setara dengan nodetool Cassandra adalah Google Cloud CLI. Anda dapat melakukan operasi bidang kontrol dan bidang data menggunakan gcloud spanner. Untuk mengetahui informasi selengkapnya, lihat panduan referensi Spanner Google Cloud CLI.

Jika memerlukan antarmuka REPL untuk mengeluarkan kueri ke Spanner yang mirip dengan cqlsh, Anda dapat menggunakan alat spanner-cli. Untuk menginstal dan menjalankan spanner-cli di Go:

go install github.com/cloudspannerecosystem/spanner-cli@latest

$(go env GOPATH)/bin/spanner-cli

Untuk mengetahui informasi selengkapnya, lihat repositori GitHub spanner-cli.