Введение в Redis
Redis (полное имя: Remote Dictionary Server) — это высокопроизводительная система хранения данных с открытым исходным кодом, которая является быстрой, гибкой и масштабируемой. Это система хранения структур данных на основе памяти, которую можно использовать в качестве базы данных, кэша и брокера сообщений.
Redis поддерживает различные структуры данных, включая строку, хэш, список, набор и отсортированный набор. Эти структуры данных предоставляют богатый набор рабочих команд, что позволяет разработчикам легко обрабатывать различные потребности в данных. Кроме того, Redis также предоставляет два метода сохранения, а именно создание снимков и добавление журналов (файл только для добавления, AOF). Метод моментального снимка записывает данные памяти Redis на диск в двоичном формате, а AOF обеспечивает постоянство путем добавления и записи команд операций Redis.
Redis также поддерживает модель публикации/подписки и может использоваться в качестве брокера сообщений. Издатели отправляют сообщения по назначенным каналам, а подписчики могут получать и обрабатывать эти сообщения. Этот шаблон полезен в таких сценариях, как создание коммуникаций в реальном времени, систем, управляемых событиями, и очередей сообщений. Кроме того, Redis также может обеспечить распределенное хранилище и высокую доступность данных за счет репликации и сегментирования «главный-подчиненный». Репликация «главный-подчиненный» позволяет копировать данные на несколько подчиненных узлов для обеспечения разделения чтения и записи и резервного копирования данных. Шардинг может распределять данные по нескольким узлам Redis для достижения горизонтального расширения и балансировки нагрузки.
Подробное объяснение случая
Далее давайте перейдем к делу и представим, как программисты крупных производителей используют Redis.Первый классический случай — непрерывный вход в систему.
Каждый должен быть знаком с проблемой непрерывного входа в систему. Логика заключается в том, что у пользователей есть одна возможность войти в систему каждый день. Если вход прерван, счетчик непрерывных входов вернется к 0. Определение непрерывного входа: вы должны войти в систему до 23:59:59 каждый день, а это значит, что время истечения срока действия ключа нужно установить на 0 часов послезавтра. Ниже приведен полный код, реализованный с помощью Golang+Redis:
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
"strconv"
"time"
)
var (
RedisClient *redis.Client
ctx = context.Background()
)
const continuesCheckKey = "uid_%d" //存储到redis的key
func InitRedis() {
rdb := redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
})
RedisClient = rdb
}
func main() {
InitRedis()
//通过一些业务逻辑获取uid,这里为了方便演示,直接写死
uid := 5201314
Checkin(ctx, uid)
}
// Checkin 连续签到天数
func Checkin(ctx context.Context, uid int) {
key := fmt.Sprintf(continuesCheckKey, uid)
//用户在某一天内不能重复签到
if exists, _ := RedisClient.Exists(ctx, key).Result(); exists == 1 {
if ttl := RedisClient.TTL(ctx, key).Val(); ttl >= time.Duration(24)*time.Hour {
fmt.Printf("用户[%d]今天已经签到过了\n", uid)
return
}
}
// 1. 连续签到数+1
err := RedisClient.Incr(ctx, key).Err()
if err != nil {
fmt.Printf("用户[%d]连续签到失败", uid)
return
} else {
expAt := beginningOfDay().Add(48 * time.Hour)
// 2. 设置签到记录在后天的0点到期
if err := RedisClient.ExpireAt(ctx, key, expAt).Err(); err != nil {
panic(err)
} else {
// 3. 打印用户续签后的连续签到天数
day, err := getUserCheckInDays(ctx, uid)
if err != nil {
panic(err)
}
fmt.Printf("用户[%d]连续签到:%d(天), 过期时间:%s", uid, day, expAt.Format("2006-01-02 15:04:05"))
}
}
}
// getUserCheckInDays 获取用户连续签到天数
func getUserCheckInDays(ctx context.Context, userID int) (int, error) {
key := fmt.Sprintf(continuesCheckKey, userID)
days, err := RedisClient.Get(ctx, key).Result()
if err != nil {
return 0, err
} else {
return strconv.Atoi(days)
}
}
// beginningOfDay 获取今天0点时间
func beginningOfDay() time.Time {
now := time.Now()
y, m, d := now.Date()
return time.Date(y, m, d, 0, 0, 0, 0, time.Local)
}
Объяснение и анализ:
- Импортный пакет:
context
: Предоставляет контекст для обработки сроков обработки запросов, сигналов отмены и т. д.fmt
: используется для форматированного вывода.strconv
: используется для преобразования между строками и базовыми типами данных.time
: Используется для операций, связанных со временем.github.com/redis/go-redis/v9
: это клиентская библиотека Redis на языке Go.
- Глобальные переменные и константы:
RedisClient
: Клиент, используемый для взаимодействия с базой данных Redis.ctx
: глобальная контекстная переменная.continuesCheckKey
: шаблон постоянной строки, используемый для создания имени ключа данных регистрации пользователей, хранящихся в Redis.
init()
функция:- Инициализируйте клиентское соединение Redis и подключитесь к локальному серверу Redis.
main()
функция:- Для демонстрации напрямую прописывается идентификатор пользователя (5201314), а затем
Checkin()
вызывается функция.
- Для демонстрации напрямую прописывается идентификатор пользователя (5201314), а затем
Checkin()
функция:- Принимает контекст и идентификатор пользователя в качестве параметров.
- Создайте имя ключа для входа пользователя
key
. - Проверьте, вошел ли пользователь в систему сегодня. Если пользователь вошел в систему, определите, прошло ли более 24 часов с момента последнего входа в систему. Если да, это означает, что пользователь вошел в систему сегодня и не будет обрабатывать его снова .
- Если пользователь не выполнил вход, срок действия записи входа рассчитывается
expAt
как 48 часов после полуночи сегодняшнего дня. ИспользуйтеIncr()
команду, чтобы увеличить последовательный номер регистрации пользователя и установить срок действияexpAt
. - Вызовите
getUserCheckInDays()
функцию, чтобы получить количество последовательных дней регистрации пользователя и отформатировать выходные данные.
getUserCheckInDays()
функция:- Создайте имя ключа данных для входа на основе идентификатора пользователя
key
. - Используйте
Get()
команду, чтобы получить количество последовательных дней регистрации пользователя (хранится в строковой форме). - Используйте
strconv.Atoi()
для преобразования полученной строки в целое число и возврата ее.
- Создайте имя ключа данных для входа на основе идентификатора пользователя
beginningOfDay()
функция:- Возвращает нулевое время текущей даты.