MST

星途 面试题库

面试题:Go接口类型查询在分布式缓存系统中的高级应用

假设要开发一个分布式缓存系统,使用Go语言实现。在这个系统中,不同的缓存策略(如LRU、LFU等)通过接口来定义,如何利用接口类型查询实现根据不同的配置动态选择合适的缓存策略,并且要考虑并发安全问题,详细阐述设计思路并给出核心代码。
15.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 定义缓存策略接口:定义一个统一的缓存策略接口,包含如 GetPut 等操作方法,这样不同的缓存策略(LRU、LFU)都可以实现这个接口。
  2. 配置管理:通过配置文件或命令行参数等方式获取缓存策略的配置信息,例如配置为 lrulfu
  3. 工厂模式:使用工厂模式根据配置动态创建对应的缓存策略实例。
  4. 并发安全:为了保证并发安全,可以使用 sync.RWMutex 对缓存操作进行加锁保护。

核心代码

package main

import (
    "fmt"
    "sync"
)

// 缓存策略接口
type CacheStrategy interface {
    Get(key string) (interface{}, bool)
    Put(key string, value interface{})
}

// LRU缓存策略实现
type LRUCache struct {
    capacity int
    cache    map[string]interface{}
    keys     []string
    mutex    sync.RWMutex
}

func NewLRUCache(capacity int) *LRUCache {
    return &LRUCache{
        capacity: capacity,
        cache:    make(map[string]interface{}),
        keys:     make([]string, 0),
    }
}

func (lru *LRUCache) Get(key string) (interface{}, bool) {
    lru.mutex.RLock()
    defer lru.mutex.RUnlock()
    value, exists := lru.cache[key]
    if exists {
        // 移动到链表头部(这里简单模拟,实际可使用双向链表优化)
        for i, k := range lru.keys {
            if k == key {
                lru.keys = append(lru.keys[:i], lru.keys[i+1:]...)
                lru.keys = append([]string{key}, lru.keys...)
                break
            }
        }
    }
    return value, exists
}

func (lru *LRUCache) Put(key string, value interface{}) {
    lru.mutex.Lock()
    defer lru.mutex.Unlock()
    if _, exists := lru.cache[key]; exists {
        // 移动到链表头部
        for i, k := range lru.keys {
            if k == key {
                lru.keys = append(lru.keys[:i], lru.keys[i+1:]...)
                lru.keys = append([]string{key}, lru.keys...)
                break
            }
        }
    } else {
        if len(lru.keys) >= lru.capacity {
            // 删除最久未使用的
            delete(lru.cache, lru.keys[len(lru.keys)-1])
            lru.keys = lru.keys[:len(lru.keys)-1]
        }
        lru.keys = append([]string{key}, lru.keys...)
    }
    lru.cache[key] = value
}

// LFU缓存策略实现
type LFUCache struct {
    capacity int
    cache    map[string]struct {
        value      interface{}
        frequency  int
    }
    frequencyMap map[int][]string
    mutex        sync.RWMutex
}

func NewLFUCache(capacity int) *LFUCache {
    return &LFUCache{
        capacity:       capacity,
        cache:          make(map[string]struct {
            value      interface{}
            frequency  int
        }),
        frequencyMap: make(map[int][]string),
    }
}

func (lfu *LFUCache) Get(key string) (interface{}, bool) {
    lfu.mutex.RLock()
    defer lfu.mutex.RUnlock()
    item, exists := lfu.cache[key]
    if exists {
        // 增加频率
        lfu.increaseFrequency(key, item.frequency)
        return item.value, true
    }
    return nil, false
}

func (lfu *LFUCache) Put(key string, value interface{}) {
    lfu.mutex.Lock()
    defer lfu.mutex.Unlock()
    if _, exists := lfu.cache[key]; exists {
        // 更新值并增加频率
        lfu.cache[key].value = value
        lfu.increaseFrequency(key, lfu.cache[key].frequency)
    } else {
        if len(lfu.cache) >= lfu.capacity {
            // 删除最不经常使用的
            lfu.removeLeastFrequent()
        }
        lfu.cache[key] = struct {
            value      interface{}
            frequency  int
        }{value, 1}
        lfu.frequencyMap[1] = append(lfu.frequencyMap[1], key)
    }
}

func (lfu *LFUCache) increaseFrequency(key string, oldFreq int) {
    // 从旧频率列表中移除
    for i, k := range lfu.frequencyMap[oldFreq] {
        if k == key {
            lfu.frequencyMap[oldFreq] = append(lfu.frequencyMap[oldFreq][:i], lfu.frequencyMap[oldFreq][i+1:]...)
            break
        }
    }
    newFreq := oldFreq + 1
    lfu.cache[key].frequency = newFreq
    lfu.frequencyMap[newFreq] = append(lfu.frequencyMap[newFreq], key)
}

func (lfu *LFUCache) removeLeastFrequent() {
    for freq := 1; ; freq++ {
        if keys, exists := lfu.frequencyMap[freq]; exists && len(keys) > 0 {
            key := keys[0]
            lfu.frequencyMap[freq] = keys[1:]
            delete(lfu.cache, key)
            break
        }
    }
}

// 缓存策略工厂
type CacheStrategyFactory struct{}

func (f *CacheStrategyFactory) CreateCacheStrategy(strategy string, capacity int) CacheStrategy {
    switch strategy {
    case "lru":
        return NewLRUCache(capacity)
    case "lfu":
        return NewLFUCache(capacity)
    default:
        return nil
    }
}

你可以这样使用:

func main() {
    factory := &CacheStrategyFactory{}
    // 从配置中获取策略,这里假设为 "lru"
    strategy := "lru"
    capacity := 10
    cache := factory.CreateCacheStrategy(strategy, capacity)
    cache.Put("key1", "value1")
    value, exists := cache.Get("key1")
    fmt.Printf("Get key1: value=%v, exists=%v\n", value, exists)
}