Back-end технология в основном должна иметь дело с кешем.Недавно я столкнулся с потребностью в этом методе на работе.Я использовал этот пакет golang в оцепенении.Теперь я планирую написать эту статью.
Прежде всего, давайте немного перейдем к следующей теме, что такое кеш?
кеш (cache), первоначальное значение означает, что скорость доступа выше среднейоперативная память(ОЗУ) Быстрый тип высокоскоростной памяти, который обычно не используется в качестве основной памяти системы.DRAMтехнология, при этом используется дорогая, но более быстраяSRAMТехнологии. Настройка кэша является одним из важных факторов высокой производительности всех современных компьютерных систем.
Если использовать неуместную аналогию, когда вы хотите приготовить, вам нужно получить сырье, обработать его и съесть.
Если доставать его из холодильника каждый раз, когда режешь овощ, ходить туда-сюда — пустая трата времени, да и сам устанешь. В это время вы можете взять корзину и положить ингредиенты (овощи), которые вы хотите использовать, в холодильник за один раз, а затем поставить ее рядом с разделочной доской для последующего использования.
Приведенный выше пример:Холодильник: База данных Овощи: Корзина данных: Кэш-контейнер
Далее, давайте представим go-cache, основной пакет, используемый сегодня.
go-cache — это высокоскоростной инструмент кэширования в памяти, который хранит файлы в формате k-v. Он подходит для приложений, работающих на одной машине, может хранить значения любого типа данных и может безопасно использоваться несколькими горутинами. Хотя go-cache не предназначен для использования в качестве постоянного хранилища данных, можно сохранить все кэшированные данные в файл (или любой io.Reader/Writer) и быстро загрузить из указанного источника данных, быстро восстановив состояние.
основной код go-cache
type cache struct {
defaultExpiration time.Duration //默认的通用key实效时长
items map[string]Item //底层的map存储
mu sync.RWMutex //由于map是非线程安全的,增加的全局锁
onEvicted func(string, interface{})//失效key时,回触发,我自己命名为回收函数
janitor *janitor //监视器,Goroutine,定时轮询用于失效key
}
demo
import (
"fmt"
"github.com/patrickmn/go-cache"
"time"
)
func main() {
// 默认过期时间为5min,每10min清理一次过期缓存
c := cache.New(5*time.Minute, 10*time.Minute)
// 设置key-value,并设置为默认过期时间
c.Set("foo", "bar", cache.DefaultExpiration)
// 设置一个不会过期的key,该key不会自动删除,重新更新key或者使用c.Delete("baz")
c.Set("baz", 42, cache.NoExpiration)
// 从缓存获取对应key的值
foo, found := c.Get("foo")
if found {
fmt.Println(foo)
}
// Since Go is statically typed, and cache values can be anything, type
// assertion is needed when values are being passed to functions that don't
// take arbitrary types, (i.e. interface{}). The simplest way to do this for
// values which will only be used once--e.g. for passing to another
// function--is:
foo, found := c.Get("foo")
if found {
MyFunction(foo.(string))
}
// This gets tedious if the value is used several times in the same function.
// You might do either of the following instead:
if x, found := c.Get("foo"); found {
foo := x.(string)
// ...
}
// or
var foo string
if x, found := c.Get("foo"); found {
foo = x.(string)
}
// ...
// foo can then be passed around freely as a string
// Want performance? Store pointers!
c.Set("foo", &MyStruct, cache.DefaultExpiration)
if x, found := c.Get("foo"); found {
foo := x.(*MyStruct)
// ...
}
}
Предыдущий пример соответствует программе, которая представляет собой небольшую проблему, с которой я столкнулся на этот раз.
Мне нужно экспортировать отчет на веб-страницу, и каждая ячейка в каждой строке должна брать соответствующие данные из соответствующей модели, но поскольку эти данные не могут существовать только в одной модели, мне нужно проверить связанную таблицу. Если вы заходите в библиотеку, чтобы проверять соответствующие данные каждый раз, когда вы используете какую-либо модель, скорость будет очень низкой (первоначальный человек написал это так, поэтому нам нужно его оптимизировать)
В первую очередь нам нужно вынести данные из базы, здесь я использую mongodb, то есть вынуть все данные в коллекцию (коллекцию можно понимать как таблицу в mysql)
for _, collection := range collections {
switch collection {
case "product":
products, err := gql.FindProduct(ctx, mongoplus.M{})
if err != nil {
logrus.Warn(err)
}
for _, product := range products {
temp := product
err := coll.Set("product_"+product.ID, &temp)
if err != nil {
logrus.Warn(err)
}
}
case "user":
users, err := gql.FindUser(ctx, mongoplus.M{})
if err != nil {
logrus.Warn(err)
}
for _, user := range users {
temp := user
err := coll.Set("user_"+user.ID, &temp)
if err != nil {
logrus.Warn(err)
}
}
case "company":
companys, err := gql.FindCompanyCache(ctx, mongoplus.M{})
if err != nil {
logrus.Warn(err)
}
for _, com := range companys {
temp := com
err := coll.Set("com_"+com.ID, &temp)
if err != nil {
logrus.Warn(err)
}
}
case "region":
Regions, err := gql.FindRegion(ctx, mongoplus.M{})
if err != nil {
logrus.Warn(err)
}
for _, Region := range Regions {
temp := Region
err := coll.Set("region_"+Region.ID, &temp)
if err != nil {
logrus.Warn(err)
}
}
case "industry":
industrys, err := gql.FindIndustry(ctx, mongoplus.M{})
if err != nil {
logrus.Warn(err)
}
for _, industry := range industrys {
temp := industry
err := coll.Set("industry_"+industry.ID, &temp)
if err != nil {
logrus.Warn(err)
}
}
}
}
return coll
}
В приведенном выше коде я помещаю все данные, которые я вывел, в контейнер.coll.Set("product_"+product.ID, &temp)
Я использую форму поля id_+model
Затем считывайте данные непосредственно из базы данных, когда вы хотите использовать их для оптимизации часть времени.
Суммировать:
gocache относительно прост. Для хранения использует map[string]Item. Ограничения на размер нет. Пока позволяет память, его можно хранить все время. Верхнего предела нет. На это нужно обратить внимание. к реальному производству.
Gocache очень простой, но есть еще много нерешенных задач.Просто перечислите несколько собственных идей, которые можно вместе оптимизировать:
1. Нет верхнего предела количества кешей, что по-прежнему чревато проблемами при использовании онлайн.
2. При вызове get для получения объекта, если объект не существует, метод get сразу вернет nil.На самом деле тут можно оптимизировать.Если хита нет, то можно загрузить из базы данных.
3. Некоторые обращения невозможно отследить.
Вывод:
На самом деле есть и другие места, которые можно анализировать на go-cache, такие как гранулярность его блокировок, совмещенная с системой сборка мусора и т.д., но так как я давно не изучал язык golang, то это было бы неловко писать во многих местах, не освоив его. Я обновлю знания, связанные с go-cache, после систематического изучения многопоточности go и других алгоритмов в будущем. Давай в будущем!