Golang 实现缓存系统

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Golang 实现缓存系统

缓存

缓存(Cache)在计算机硬件中普遍存在。比如在 CPU 中就有一级缓存,二级缓存,甚至三级缓存。缓存的工作原理一般是 CPU 需要读取数据时,会首先从缓存中查找需要的数据,如果找到了就直接进行处理,如果没有找到则从内存中读取数据。由于 CPU 中的缓存工作速度比内存还要快,所以缓存的使用能加快 CPU 处理速度。缓存不仅仅存在于硬件中,在各种软件系统中也处处可见。比如在 Web 系统中,缓存存在于服务器端,客户端或者代理服务器中。广泛使用的 CDN 网络,也可以看作一个巨大的缓存系统。缓存在 Web 系统中的使用有很多好处,不仅可以减少网络流量,降低客户访问延迟,还可以减轻服务器负载。

目前已经存在很多高性能的缓存系统,比如 Memcache,Redis 等,尤其是 Redis,现已经广泛用于各种 Web 服务中。既然有了这些功能完善的缓存系统,那为什么我们还需要自己实现一个缓存系统呢?这么做主要有两个原因,第一,通过动手实现我们可以了解缓存系统的工作原理,这也是老掉牙的理由了。第二,Redis 之类的缓存系统都是独立存在的,如果只是开发一个简单的应用还需要单独使用 Redis 服务器,难免会过于复杂。这时候如果有一个功能完善的软件包实现了这些功能,只需要引入这个软件包就能实现缓存功能,而不需要单独使用 Redis 服务器,就最好不过了。

缓存系统的设计

缓存系统中,缓存的数据一般都存储在内存中,所以我们设计的缓存系统要以某一种方式管理内存中的数据。既然缓存数据是存储在内存中的,那如果系统停机,那数据岂不就丢失了吗?其实一般情况下,缓存系统还支持将内存中的数据写入到文件中,在系统再次启动时,再将文件中的数据加载到内存中,这样一来就算系统停机,缓存数据也不会丢失。

同时缓存系统还提供过期数据清理机制,也就是说缓存的数据项是有生存时间的,如果数据项过期,则数据项会从内存中被删除,这样一来热数据会一直存在,而冷数据则会被删除,也没有必要进行缓存。

缓存系统还需要对外提供操作的接口,这样系统的其他组件才能使用缓存。一般情况下,缓存系统需要支持 CRUD 操作,也就算创建(添加),读取,更新和删除操作。

通过以上分析,可以总结出缓存系统需要有以下功能:

  1. 缓存数据的存储
  2. 过期数据项管理
  3. 内存数据导出,导入
  4. 提供 CRUD 接口

代码实现

package examples
import (
  "sync"
  "testing"
  "time"
)
type ICache interface {
  //size support: 1KB,100KB,1MB,2MB,1GB
  SetMaxMemory(size string) bool
  //key expire after expire time
  Set(key string, val interface{}, expire time.Duration)
  //get one key
  Get(key string) (interface{}, bool)
  //delete one key
  Del(key string) bool
  //exists one key
  Exists(key string) bool
  //delete all key
  Flush() bool
  //get all key
  Keys() []string
  //garbage collection every second
  GcLoop()
  //delete expired key
  DeleteExpired()
}
type Item struct {
  Object     interface{}
  Expiration int64
}
type cache struct {
  size     string
  items    map[string]Item
  mu       sync.RWMutex
  interval time.Duration
}
func (c *cache) SetMaxMemory(size string) bool {
  c.mu.RLock()
  defer c.mu.RUnlock()
  c.size = size
  return true
}
func (c *cache) Set(k string, x interface{}, d time.Duration) {
  c.mu.Lock()
  defer c.mu.Unlock()
  e := time.Now().Add(d * time.Second).Unix()
  c.items[k] = Item{
    Object:     x,
    Expiration: e,
  }
}
func (c *cache) Get(k string) (interface{}, bool) {
  c.mu.RLock()
  defer c.mu.RUnlock()
  item, found := c.items[k]
  if !found {
    return nil, false
  }
  if time.Now().Unix() > item.Expiration {
    return nil, false
  }
  return item.Object, true
}
func (c *cache) Del(k string) bool {
  c.mu.Lock()
  defer c.mu.Unlock()
  if _, found := c.items[k]; found {
    delete(c.items, k)
    return true
  }
  return false
}
func (c *cache) Exists(k string) bool {
  c.mu.RLock()
  defer c.mu.RUnlock()
  if _, found := c.items[k]; found {
    return true
  }
  return false
}
func (c *cache) Flush() bool {
  c.mu.Lock()
  defer c.mu.Unlock()
  c.items = map[string]Item{}
  return true
}
func (c *cache) Keys() []string {
  c.mu.RLock()
  defer c.mu.RUnlock()
  var keys []string
  for k := range c.items {
    keys = append(keys, k)
  }
  return keys
}
func (c *cache) GcLoop() {
  ticker := time.NewTicker(c.interval)
  for {
    select {
    case <-ticker.C:
      c.DeleteExpired()
    }
  }
}
func (c *cache) DeleteExpired() {
  now := time.Now().Unix()
  for k, v := range c.items {
    if now > v.Expiration {
      c.Del(k)
    }
  }
}
func NewCache() ICache {
  c := &cache{
    size:     "1024",
    items:    map[string]Item{},
    interval: time.Second,
  }
  go c.GcLoop()
  return c
}
func TestCacheExample(t *testing.T) {
  c := NewCache()
  c.Set("foo", "bar", 5)
  time.Sleep(10 * time.Second)
  r, b := c.Get("foo")
  t.Log(r, b)
  t.Log("test cache finished.")
}
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
21天前
|
缓存 NoSQL Linux
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
|
3天前
|
缓存 运维 NoSQL
二级缓存架构极致提升系统性能
本文详细阐述了如何通过二级缓存架构设计提升高并发下的系统性能。
|
1月前
|
缓存 应用服务中间件 nginx
[nginx]proxy_cache缓存系统
[nginx]proxy_cache缓存系统
|
14天前
|
Go 开发者
|
19天前
|
缓存 架构师 数据库
缓存系统稳定性 - 架构师峰会演讲实录
缓存系统稳定性 - 架构师峰会演讲实录
|
2月前
|
消息中间件 缓存 算法
基于Netty的自研流系统缓存实现挑战: 内存碎片与OOM困境
基于Netty的自研流系统缓存实现挑战: 内存碎片与OOM困境
37 1
基于Netty的自研流系统缓存实现挑战: 内存碎片与OOM困境
|
2月前
|
自然语言处理 Go 数据处理
云计算自旋锁问题之引入Golang插件系统后iLogtail的输入输出通道和处理能力如何解决
云计算自旋锁问题之引入Golang插件系统后iLogtail的输入输出通道和处理能力如何解决
31 1
|
2月前
|
存储 缓存 NoSQL
深入理解分布式缓存在后端系统中的应用与实践
【7月更文挑战第20天】 本文将探讨分布式缓存技术在后端系统设计中的关键角色,并揭示其如何优化性能和扩展性。文章不仅剖析了分布式缓存的基本原理和工作机制,而且提供了实际案例分析,展示了其在处理大规模数据时的优势。我们将深入了解几种流行的分布式缓存解决方案,并讨论它们在不同场景下的适用性。最后,文章将指导读者如何在真实世界的应用中实施分布式缓存,包括架构设计、性能调优以及故障排除的最佳实践。
|
2月前
|
存储 缓存 NoSQL
深入理解分布式缓存在现代后端系统中的应用与挑战
随着互联网技术的飞速发展,分布式缓存已成为提升后端系统性能的关键技术之一。本文将从数据导向和科学严谨的角度出发,探讨分布式缓存技术的原理、应用场景以及面临的主要挑战。通过对具体案例的分析和数据统计,我们旨在为读者提供一个全面而深入的理解框架,帮助开发者更好地设计和优化后端系统。 【7月更文挑战第20天】
57 0
|
3月前
|
缓存 监控 负载均衡
Java一分钟之-Ehcache:分布式缓存系统
【6月更文挑战第17天】**Ehcache是Java的开源缓存库,支持本地和分布式缓存,提供负载均衡、数据复制和容错能力。常见问题包括网络分区导致的数据不一致、缓存雪崩和配置不当引起的性能瓶颈。解决策略涉及选择强一致性策略、设置合理缓存过期时间和监控调整配置。使用Ehcache需添加相关依赖,并配置分布式缓存,如示例所示,通过CacheManager创建和管理缓存。实践中,持续监控和优化配置至关重要。**
75 1