Menyimpan data ke dalam cache dengan Memorystore

Aplikasi web berperforma tinggi yang skalabel sering menggunakan cache data dalam memori yang terdistribusi di depan atau sebagai pengganti penyimpanan persisten yang kuat untuk beberapa tugas. Sebaiknya gunakan Memorystore for Redis sebagai layanan penyimpanan data ke dalam cache. Perlu diketahui bahwa Memorystore for Redis tidak menyediakan paket gratis. Lihat Harga Memorystore untuk mengetahui detail selengkapnya.

Sebelum memulai, pastikan aplikasi Anda tidak melebihi kuota Memorystore for Redis.

Waktu penggunaan cache memori

Data sesi, preferensi pengguna, dan data lain yang ditampilkan oleh kueri untuk halaman web adalah pilihan yang baik untuk disimpan ke dalam cache. Secara umum, jika kueri yang sering dijalankan menampilkan serangkaian hasil yang tidak harus segera muncul di aplikasi, Anda dapat menyimpan hasilnya ke dalam cache. Permintaan berikutnya dapat memeriksa cache dan hanya membuat kueri database jika hasilnya tidak ada atau sudah tidak berlaku.

Jika Anda hanya menyimpan nilai di Memorystore tanpa mencadangkannya di penyimpanan persisten, pastikan aplikasi Anda memiliki perilaku yang dapat diterima jika nilainya sudah tidak berlaku dan dihapus dari cache. Misalnya, sesi akan gagal berfungsi jika secara tiba-tiba data sesi pengguna tidak tersedia. Oleh karena itu, data tersebut mungkin harus disimpan dalam database selain Memorystore.

Memahami izin Memorystore

Setiap interaksi dengan layanan Google Cloud perlu diotorisasi. Misalnya, untuk berinteraksi dengan database Redis yang dihosting oleh Memorystore, aplikasi Anda harus menyediakan kredensial akun yang memiliki otorisasi untuk mengakses Memorystore.

Secara default, aplikasi Anda akan memberikan kredensial akun layanan default App Engine, yang memiliki otorisasi untuk mengakses database dalam project yang sama dengan aplikasi Anda.

Jika salah satu kondisi berikut terpenuhi, Anda harus menggunakan teknik autentikasi alternatif yang secara eksplisit memberikan kredensial:

  • Aplikasi Anda dan database Memorystore berada di project Google Cloud yang berbeda.

  • Anda telah mengubah peran yang ditetapkan ke akun layanan App Engine default.

Untuk mengetahui informasi tentang teknik autentikasi alternatif, lihat Menyiapkan Autentikasi untuk Aplikasi Produksi Server ke Server.

Ringkasan penggunaan Memorystore

Untuk menggunakan Memorystore di aplikasi Anda:

  1. Siapkan Memorystore for Redis, yang mengharuskan Anda untuk membuat instance Redis pada Memorystore dan membuat Akses VPC Serverless yang digunakan aplikasi Anda untuk berkomunikasi dengan instance Redis.

  2. Instal library klien untuk Redis dan gunakan perintah Redis untuk menyimpan data ke dalam cache.

    Memorystore for Redis kompatibel dengan library klien apa pun untuk Redis.

    Go

    Panduan ini menjelaskan penggunaan library klien redigo untuk mengirim perintah Redis dari aplikasi Anda.

    Java

    Panduan ini menjelaskan penggunaan library klien Jedis untuk mengirim perintah Redis dari aplikasi Anda. Untuk mengetahui detail selengkapnya tentang cara menggunakan Jedis, lihat wiki Jedis.

    Node.js

    Panduan ini menjelaskan penggunaan library klien node_redis untuk mengirim perintah Redis dari aplikasi Anda.

    PHP

    Panduan ini menjelaskan penggunaan library klien PHPRedis untuk mengirim perintah Redis dari aplikasi Anda.

    Python

    Panduan ini menjelaskan penggunaan library klien redis-py 3.0 untuk mengirim perintah Redis dari aplikasi Anda.

    Ruby

    Panduan ini menjelaskan penggunaan library klien redis-rb untuk mengirim perintah Redis dari aplikasi Anda.

  3. Uji pembaruan Anda.

  4. Deploy aplikasi Anda ke App Engine.

Menyiapkan Memorystore for Redis

Untuk menyiapkan Memorystore for Redis:

  1. Buat instance Redis di Memorystore.

    Saat diminta memilih region untuk instance Redis, pilih region yang sama dengan lokasi aplikasi App Engine Anda berada.

  2. Catat alamat IP dan nomor port instance Redis yang Anda buat. Anda akan menggunakan informasi ini saat membuat klien Redis dalam kode.

  3. Hubungkan App Engine Anda ke jaringan VPC. Aplikasi Anda hanya dapat berkomunikasi dengan Memorystore melalui konektor VPC.

    Pastikan untuk menambahkan informasi koneksi VPC ke file app.yaml Anda, seperti yang dijelaskan dalam Mengonfigurasi aplikasi menggunakan konektor.

Menginstal dependensi

Go

Agar library klien redigo tersedia untuk aplikasi Anda saat dijalankan di App Engine, tambahkan library ke dependensi aplikasi Anda. Misalnya, jika Anda menggunakan file go.mod untuk mendeklarasikan dependensi, tambahkan baris berikut ke file go.mod Anda:

modul github.com/GoogleCloudPlatform/golang-samples/tree/master/memorystore/redis

Pelajari lebih lanjut cara menentukan dependensi untuk aplikasi Go Anda.

Java

Agar library klien Jedis tersedia untuk aplikasi Anda saat dijalankan di App Engine, tambahkan library ke dependensi aplikasi Anda. Misalnya, jika Anda menggunakan Maven, tambahkan dependensi berikut di file pom.xml Anda:

<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>5.1.0</version>
</dependency>

Node.js

Agar library klien node_redis tersedia untuk aplikasi Anda saat dijalankan di App Engine, tambahkan library ke file package.json aplikasi Anda.

Contoh:

{
  "name": "memorystore-redis",
  "description": "An example of using Memorystore(Redis) with Node.js",
  "version": "0.0.1",
  "private": true,
  "license": "Apache Version 2.0",
  "author": "Google Inc.",
  "engines": {
    "node": ">=16.0.0"
  },
  "dependencies": {
    "redis": "^4.0.0"
  }
}

Pelajari lebih lanjut cara menentukan dependensi untuk aplikasi Node.js.

PHP

Agar library klien PHPRedis tersedia untuk aplikasi Anda saat dijalankan di App Engine, tambahkan ekstensi redis.so ke file php.ini aplikasi Anda. Contoh:

; Enable the Redis extension on App Engine
extension=redis.so

Untuk informasi selengkapnya tentang cara mengaktifkan ekstensi PHP di App Engine, lihat Ekstensi yang dapat dimuat secara dinamis.

Python

Agar library klien redis-py tersedia untuk aplikasi Anda saat dijalankan di App Engine, tambahkan baris berikut ke file requirements.txt aplikasi:

  redis

Runtime App Engine Python 3 akan otomatis mengupload semua library file requirements.txt aplikasi Anda saat men-deploy aplikasi.

Untuk pengembangan lokal, sebaiknya instal dependensi di lingkungan virtual seperti venv.

Ruby

Agar library klien redis-rb tersedia untuk aplikasi Anda saat berjalan di App Engine, tambahkan library ke file Gemfile aplikasi Anda.

  source "https://cloud.google.com/memorystore"

  gem "redis-rb"

Membuat klien Redis

Untuk berinteraksi dengan database Redis, kode Anda perlu membuat klien Redis untuk mengelola koneksi ke database Redis. Bagian berikut menjelaskan pembuatan klien Redis menggunakan library klien Redis.

Menentukan variabel lingkungan

Library klien Redis menggunakan dua variabel lingkungan untuk menyusun URL database Redis Anda:

  • Variabel untuk mengidentifikasi alamat IP database Redis yang Anda buat di Memorystore.
  • Variabel untuk mengidentifikasi nomor port database Redis yang Anda buat di Memorystore.

Sebaiknya tentukan variabel ini dalam file app.yaml aplikasi, bukan menentukannya secara langsung di dalam kode. Cara ini memudahkan Anda untuk menjalankan aplikasi di lingkungan yang berbeda, seperti lingkungan lokal dan App Engine. Pelajari variabel lingkungan lebih lanjut di halaman referensi app.yaml.

Go

Misalnya, tambahkan baris berikut ke file app.yaml Anda:

  env_variables:
       REDISHOST: '10.112.12.112'
       REDISPORT: '6379'

Java

Misalnya, tambahkan baris berikut ke file app.yaml Anda:

  env_variables:
       redis.host: '10.112.12.112'
       redis.port: '6379'

Node.js

Misalnya, tambahkan baris berikut ke file app.yaml Anda:

  env_variables:
       REDISHOST: '10.112.12.112'
       REDISPORT: '6379'

PHP

Misalnya, tambahkan baris berikut ke file app.yaml Anda:

  env_variables:
       REDIS_HOST: '10.112.12.112'
       REDIS_PORT: '6379'

Python

Misalnya, tambahkan baris berikut ke file app.yaml Anda:

  env_variables:
       REDISHOST: '10.112.12.112'
       REDISPORT: '6379'

Ruby

Misalnya, tambahkan baris berikut ke file app.yaml Anda:

  env_variables:
       REDISHOST: '10.112.12.112'
       REDISPORT: '6379'

Mengimpor Redis dan membuat klien

Go

Setelah Anda menentukan variabel lingkungan REDISHOST dan REDISPORT, gunakan baris berikut untuk mengimpor library redigo, membuat kumpulan koneksi, lalu mengambil klien Redis dari kumpulan tersebut:


// Command redis is a basic app that connects to a managed Redis instance.
package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/gomodule/redigo/redis"
)

var redisPool *redis.Pool

func incrementHandler(w http.ResponseWriter, r *http.Request) {
	conn := redisPool.Get()
	defer conn.Close()

	counter, err := redis.Int(conn.Do("INCR", "visits"))
	if err != nil {
		http.Error(w, "Error incrementing visitor counter", http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "Visitor number: %d", counter)
}

func main() {
	redisHost := os.Getenv("REDISHOST")
	redisPort := os.Getenv("REDISPORT")
	redisAddr := fmt.Sprintf("%s:%s", redisHost, redisPort)

	const maxConnections = 10
	redisPool = &redis.Pool{
		MaxIdle: maxConnections,
		Dial:    func() (redis.Conn, error) { return redis.Dial("tcp", redisAddr) },
	}

	http.HandleFunc("/", incrementHandler)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	log.Printf("Listening on port %s", port)
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatal(err)
	}
}

Java

Saat menggunakan library Jedis, sebaiknya buat JedisPool, lalu gunakan kumpulan tersebut untuk membuat klien. Baris kode berikut menggunakan variabel lingkungan redis.host dan redis.port yang Anda tentukan sebelumnya untuk membuat kumpulan:


package com.example.redis;

import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@WebListener
public class AppServletContextListener implements ServletContextListener {

  private Properties config = new Properties();

  private JedisPool createJedisPool() throws IOException {
    String host;
    Integer port;
    config.load(
        Thread.currentThread()
            .getContextClassLoader()
            .getResourceAsStream("application.properties"));
    host = config.getProperty("redis.host");
    port = Integer.valueOf(config.getProperty("redis.port", "6379"));

    JedisPoolConfig poolConfig = new JedisPoolConfig();
    // Default : 8, consider how many concurrent connections into Redis you will need under load
    poolConfig.setMaxTotal(128);

    return new JedisPool(poolConfig, host, port);
  }

  @Override
  public void contextDestroyed(ServletContextEvent event) {
    JedisPool jedisPool = (JedisPool) event.getServletContext().getAttribute("jedisPool");
    if (jedisPool != null) {
      jedisPool.destroy();
      event.getServletContext().setAttribute("jedisPool", null);
    }
  }

  // Run this before web application is started
  @Override
  public void contextInitialized(ServletContextEvent event) {
    JedisPool jedisPool = (JedisPool) event.getServletContext().getAttribute("jedisPool");
    if (jedisPool == null) {
      try {
        jedisPool = createJedisPool();
        event.getServletContext().setAttribute("jedisPool", jedisPool);
      } catch (IOException e) {
        // handle exception
      }
    }
  }
}

Untuk membuat klien dari kumpulan tersebut, gunakan metode JedisPool.getResource(). Contoh:


package com.example.redis;

import java.io.IOException;
import java.net.SocketException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

@WebServlet(name = "Track visits", value = "")
public class VisitCounterServlet extends HttpServlet {

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    try {
      JedisPool jedisPool = (JedisPool) req.getServletContext().getAttribute("jedisPool");

      if (jedisPool == null) {
        throw new SocketException("Error connecting to Jedis pool");
      }
      Long visits;

      try (Jedis jedis = jedisPool.getResource()) {
        visits = jedis.incr("visits");
      }

      resp.setStatus(HttpServletResponse.SC_OK);
      resp.getWriter().println("Visitor counter: " + String.valueOf(visits));
    } catch (Exception e) {
      resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
    }
  }
}

Node.js

Setelah menentukan variabel lingkungan REDISHOST dan REDISPORT, Anda dapat menggunakan baris berikut untuk mengimpor library node_redis dan membuat klien Redis:

'use strict';
const http = require('http');
const redis = require('redis');

const REDISHOST = process.env.REDISHOST || 'localhost';
const REDISPORT = process.env.REDISPORT || 6379;

const client = redis.createClient(REDISPORT, REDISHOST);
client.on('error', err => console.error('ERR:REDIS:', err));

// create a server
http
  .createServer((req, res) => {
    // increment the visit counter
    client.incr('visits', (err, reply) => {
      if (err) {
        console.log(err);
        res.status(500).send(err.message);
        return;
      }
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end(`Visitor number: ${reply}\n`);
    });
  })
  .listen(8080);

PHP

Setelah menentukan variabel lingkungan REDIS_HOST dan REDIS_PORT, Anda dapat menggunakan baris berikut untuk membuat klien Redis:

<?php
/**
 * Copyright 2019 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Only serve traffic from "/"
switch (@parse_url($_SERVER['REQUEST_URI'])['path']) {
    case '/':
        break;
    default:
        http_response_code(404);
        exit('Not Found');
}

// Connect to Memorystore from App Engine.
if (!$host = getenv('REDIS_HOST')) {
    throw new Exception('The REDIS_HOST environment variable is required');
}

# Memorystore Redis port defaults to 6379
$port = getenv('REDIS_PORT') ?: '6379';

try {
    $redis = new Redis();
    $redis->connect($host, $port);
} catch (Exception $e) {
    return print('Error: ' . $e->getMessage());
}

$value = $redis->incr('counter');

printf('Visitor number: %s', $value);

Python

Setelah Anda menentukan variabel lingkungan REDISHOST dan REDISPORT, gunakan baris berikut untuk mengimpor library redis-py dan membuat klien:

  import redis

  redis_host = os.environ.get('REDISHOST', 'localhost')
  redis_port = int(os.environ.get('REDISPORT', 6379))
  redis_client = redis.Redis(host=redis_host, port=redis_port)

Jika menggunakan versi lama redis-py untuk aplikasi lain, Anda mungkin menggunakan class StrictClient, bukan Client. Namun, redis-py sekarang merekomendasikan Client, bukan StrictClient.

Ruby

Tidak ada informasi tambahan untuk runtime ini.

Menggunakan perintah Redis untuk menyimpan dan mengambil data dalam cache

Meskipun database Memorystore Redis mendukung sebagian besar perintah Redis, Anda hanya perlu menggunakan beberapa perintah untuk menyimpan dan mengambil data dari cache. Tabel berikut menampilkan rekomendasi perintah Redis yang dapat Anda gunakan untuk menyimpan data ke dalam cache. Untuk mengetahui cara memanggil perintah tersebut dari aplikasi Anda, lihat dokumentasi library klien.

Tugas Perintah Redis
Buat entri dalam cache data dan
tetapkan waktu habis masa berlaku untuk entri
SETNX
MSETNX
Mengambil data dari cache GET
MGET
Mengganti nilai cache yang ada SETEL
MSET
Menambahkan atau mengurangi nilai cache numerik INCR
INCRBY
DECR
DECRBY
Menghapus entri dari cache DEL
UNLINK
Mendukung interaksi serentak dengan cache Lihat detail tentang transaksi Redis.

Untuk Python 3, library klien redis-py mengharuskan semua transaksi terjadi di pipeline.

Menguji update Anda

Saat Anda menguji aplikasi secara lokal, pertimbangkan untuk menjalankan instance lokal Redis gun menghindari interaksi dengan data produksi (Memorystore tidak menyediakan emulator). Untuk menginstal dan menjalankan Redis secara lokal, ikuti petunjuk dalam dokumentasi Redis. Perhatikan bahwa saat ini menjalankan Redis secara lokal di Windows tidak dapat dilakukan.

Untuk mengetahui informasi selengkapnya tentang pengujian aplikasi, lihat Menguji dan men-deploy aplikasi Anda.

Men-deploy aplikasi Anda

Setelah aplikasi Anda berjalan di server pengembangan lokal tanpa error:

  1. Menguji aplikasi di App Engine.

  2. Jika aplikasi berjalan tanpa error, gunakan pemisahan traffic untuk meningkatkan traffic untuk aplikasi yang diupdate secara perlahan. Pantau aplikasi dengan cermat untuk menemukan masalah database sebelum mengarahkan lebih banyak traffic ke aplikasi yang telah diupdate.