高并发之config

对于config的读取,再熟悉不过了,通常的写法如下:

//1. read from cache
string configvalue = GetFromCache(configKey);
if(!configValue.IsNullOrEmpty()){
    return configValue;
}

//2. read from db
configValue = GetFromDb(configKey);
if(configValue.IsNullOrEmpty()){
    // set to cache 30s
    retrun config;
}

 

这种写法在普通的场景下,完全是可行的 先从cache中读,再从db中读取,设置30s缓存时间

但当遇到高并发的场景下: 即如果瞬时有10000个或更多的请求,来读取这个config,恰巧碰到,30s过期的临界值。此时全部的请求压力就会转向db,缓存就会miss。

这里有个概念:

滑动过期 :即config 从本地内存中读取,同时开启一个定时器,定时从cache中同步config到本地内存中

public class ConfigFacade
    {
        private const int FRESHEN_INTERVAL = 30 * 1000;
        private static readonly ConcurrentDictionary<string, string> localCache = new ConcurrentDictionary<string, string>();
        private static Timer _timer;
        static ConfigFacade()
        {
            Console.WriteLine("timer start ...");
            _timer = new Timer(state => LoadConfig(), null, FRESHEN_INTERVAL, FRESHEN_INTERVAL);
        }

        private static void LoadConfig()
        {
            //sync configvalue to localcache
            foreach (var key in localCache.Keys)
            {
                var configValue = GetConfigFromClient(key);
                var tryUpdateValue = localCache.TryUpdate(key, configValue, localCache[key]);
                Console.WriteLine("now : {0}", DateTime.Now);
                Console.WriteLine("update key :{0} , {1}", key, tryUpdateValue);
            }
        }

        public static string GetConfig(string key)
        {
            string value;
            if (localCache != null && localCache.Count > 0 && localCache.ContainsKey(key))
            {
                var tryGetValue = localCache.TryGetValue(key, out value);
                if (tryGetValue)
                {
                    return value;
                }
            }

            value = GetConfigFromClient(key);
            localCache.TryAdd(key, value);
            return value;
        }

        private static string GetConfigFromClient(string key)
        {
            // 1. from redis 
            // 2. from db 
            Console.WriteLine("key => {0} ,get value form client", key);
            return string.Format("{0}_value", key);
        }
    }

 

优点

  1. 每次并发的读取都能保证是读取本地内存,定时器会定时的去同步缓存到本地内存
  2. 这种处理问题的思路 类似于将config 放到一个池子里,永远保证这个池子里有值
posted @ 2018-04-07 11:17  六度僧人  阅读(182)  评论(0编辑  收藏  举报