Кеширование результатов выполнения запросов

GolangBeginner
Практиковаться сейчас

Введение

В этом проекте вы научитесь реализовывать библиотеку кеширования, которая поддерживает время истечения срока действия на основе пакета singleflight в Go. Эта библиотека кеширования может быть использована в распределенных системах для кеширования результатов выполнения запросов, улучшая производительность вашего приложения.

👀 Предварительный просмотр

$ /usr/local/go/bin/go test --race
PASS
ok      cacheflight     1.263s

🎯 Задачи

В этом проекте вы научитесь:

  • Как инициализировать модуль Go и установить необходимые пакеты
  • Как реализовать библиотеку кеширования с использованием пакета singleflight
  • Как протестировать библиотеку кеширования, чтобы убедиться, что она работает как ожидается

🏆 Достижения

После завершения этого проекта вы сможете:

  • Разобраться в основных концепциях кеширования и пакете singleflight в Go
  • Реализовать библиотеку кеширования, которая поддерживает время истечения срока действия
  • Интегрировать библиотеку кеширования в вашу распределенную систему, чтобы улучшить производительность вашего приложения

Инициализация модуля и установка необходимых пакетов

В этом шаге вы научитесь инициализировать модуль и устанавливать необходимые пакеты для проекта.

  1. Откройте терминал в директории /home/labex/project.

  2. Инициализируйте модуль с использованием следующей команды:

    /usr/local/go/bin/go mod init cacheflight
    
  3. Установите необходимые пакеты с использованием следующих команд:

    /usr/local/go/bin/go get github.com/golang/groupcache/singleflight
    /usr/local/go/bin/go get github.com/stretchr/testify/assert
    

Реализация библиотеки кеширования

В этом шаге вы реализуете библиотеку кеширования на основе пакета singleflight.

  1. Откройте файл cacheflight.go в директории /home/labex/project.

  2. Добавьте необходимое содержимое в import.

    import (
        "sync"
        "time"
    
        "github.com/golang/groupcache/singleflight"
    )
    
  3. Добавьте необходимое содержимое в type Group и type cacheResult.

    // cacheResult представляет результат кеширования
    type cacheResult struct {
        data      interface{} // данные кеша
        ctime     time.Time   // время создания кеша
        isRunning chan bool   // выполняется ли функция
    }
    
    // Group - это核心структура
    type Group struct {
        cacheExpiration time.Duration          // время истечения срока действия кеша
        sfg             *singleflight.Group    // группа singleflight
        cache           map[string]cacheResult // результаты кеширования
        mu              sync.Mutex             // мьютекс
    }
    
  4. Реализуйте функцию NewGroup, которая возвращает новую группу кеширования с указанным временем истечения срока действия кеша.

    func NewGroup(cacheExpiration time.Duration) (group *Group) {
        group = &Group{
            sfg:             &singleflight.Group{},
            cache:           make(map[string]cacheResult),
            cacheExpiration: cacheExpiration,
        }
        return
    }
    
  5. Реализуйте функцию do, которая обрабатывает логику кеширования.

    func (g *Group) do(key string, fn func() (interface{}, error)) (ret interface{}, err error) {
        return g.sfg.Do(key, func() (interface{}, error) {
            g.mu.Lock()
            result, ok := g.cache[key]
            if result.isRunning!= nil {
                g.mu.Unlock()
                // ждем завершения fn
                <-result.isRunning
                return g.do(key, fn)
            } else if!ok || result.ctime.Add(g.cacheExpiration).Before(time.Now()) {
                // если кеш не существует или истек
                var run = make(chan bool)
                result.isRunning = run
                g.cache[key] = result
                // когда fn завершится и закроет канал run, позволит другим горутинам получить кеш
                defer close(run)
            } else {
                // если кеш существует и не истек
                g.mu.Unlock()
                return result.data, nil
            }
    
            g.mu.Unlock()
    
            // разные ключи могут выполняться одновременно
            ret, err = fn()
            if err!= nil {
                return ret, nil
            }
    
            result = cacheResult{
                data:  ret,
                ctime: time.Now(),
            }
            g.mu.Lock()
            g.cache[key] = result
            g.mu.Unlock()
    
            return ret, nil
        })
    }
    
  6. Реализуйте функцию Do, которая является оберткой вокруг функции do.

    func (g *Group) Do(key string, fn func() (interface{}, error)) (ret interface{}, err error) {
        return g.do(key, fn)
    }
    

Тестирование библиотеки кеширования

В этом шаге вы протестируете библиотеку кеширования, чтобы убедиться, что она работает как ожидается.

  1. Откройте терминал в директории /home/labex/project.

  2. Запустите следующую команду для выполнения тестов:

    cd /home/labex/project
    /usr/local/go/bin/go test --race
    
  3. Если функция кеширования была реализована правильно, вы увидите следующий вывод:

    PASS
    ok      cacheflight     1.263s
    
  4. Если вы столкнулись с ошибкой по таймауту, выполните следующие команды в терминале, а затем нажмите кнопку "Проверить снова", чтобы пройти проверку:

    cd /home/labex/project
    /usr/local/go/bin/go test --race
    

Поздравляем! Вы успешно реализовали библиотеку кеширования на основе пакета singleflight. Теперь вы можете использовать эту библиотеку в своей распределенной системе для кеширования результатов выполнения запросов и улучшения производительности вашего приложения.

Резюме

Поздравляем! Вы завершили этот проект. Вы можете практиковаться в более многих лабораторных работах в LabEx, чтобы улучшить свои навыки.

✨ Проверить решение и практиковаться✨ Проверить решение и практиковаться✨ Проверить решение и практиковаться