在这个cache everywhere的时代,在这我的人都会说分布式缓存的时代,Memcached几乎已成为网站开发中的标配。html
做为一名普通的coder,咱们在编写缓存代码的时候,不少状况下可能都只是了解其基本原理,知道如何调用API,知道大概怎么work around,而后测试经过上线,一般这样作还真不会出事。git
然而看到这几天评论猛烈的雄文由于所谓的代码性能不高而被离职的程序员及其回帖,以及以前公司内部培训发现居然有不少人不知道framework的缓存是天生的Thread Safe,实在忍不住,抛开非技术话题,也不讨论代码可读性,就说说Memcached缓存的使用,用好用对其实并不容易,并且说不定就会有隐藏问题,真的太有总结的必要了。程序员
缓存的key有长度限制,key的组成有特定字符的限制。github
缓存的value必须能够序列化,且缓存的单一value容量有大小限制,对于可序列化的value,应该千方百计尽可能规避某些特定数据结构,好比Hashtable,DataTable这些内部其实很是很是之复杂的数据结构。对于读频繁的操做来讲,每次序列化和反序列化复杂数据结构的开销可想而知。web
若是连分布式缓存的key和value(尤为是value)的通常限制都搞错了,那么使用缓存的后果极可能只是白白增长了网络IO及序列化、反序列化的开销,对系统性能提高固然是巨大的副作用。数据库
这一点隐藏的也比较深,下面以应用普遍的EnyimMemcached为例来简单说明。缓存
一般咱们使用的客户端每次实例化MemcachedClient对象内部都会初始化一个客户端对象池(TCP链接池,客户端命名为ServerPool)。所谓TCP链接池就是将建立好的TCP链接(链接数一般按照配置来,生产环境的配置不会小于两位数)初始化放在容器内,客户端调用的时候能够直接拿出已经存在的TCP链接来用,这样能够省去实时打开TCP链接的开销。安全
由于有人喜欢using一下(固然包括楼主本身了),一看到MemcachedClient是继承自IDisposable的,必须用using啊,而后就要new一个MemcachedClient对象,这样客户端内部也就不得再也不初始化一个TCP链接池。若是某个使用缓存的服务方法调用频繁,很快你就会发现系统CPU飙升,页面打开速度奇慢,直至不能正常访问。服务器
咱们知道,分布式缓存系统都有一个TCP链接上限的设置,不管如何,超过这个上限都有可能引起连环反应,这种反应毫无疑问是不良反作用。网络
因此若是咱们误用MemcachedClient,每次都new一个对象,那么高并发状况下效果就很是惨了,一方面web服务器由于TCP链接过多没法正常访问,另外一方面Memcached服务器也由于链接太多负载太重而性能变得极差,依赖Memcached的服务极可能短期内只接收到超时响应。
解决方案无比简单,配置合适的TCP链接数,MemcachedClient对象单例便可。
最后还要重申选择使用缓存的业务场景的重要性。这一点真的没法说透,可是根据一些已有经验,能够提炼出两条比较通用的缓存准则:
一、写频繁的数据不适合缓存;
二、读频繁而写不频繁的数据适合缓存。
果真正确的话都是废话,上面两条等于没说。
怕大家说无聊,仍是要奉献两条本身使用缓存的主要准则,固然只是本身一家之言经验之谈,不可全信,切记,不然被总监劝退老子概不负责:
一、适合缓存的数据一般应该对外公开供(全部)人调用,私有的数据缓存多数状况下是没有意义的;
二、对准确性、实时性、安全性等要求极高的业务数据,你的数据可能不适合缓存。
顺带再提一下web开发中的性能问题。听说若是一个网站有性能问题,那么它必定会出现性能问题。数据库、缓存、消息队列、各类框架、com组件等等等等,这些web开发中的标配,有哪一个使用不当不会引起系统的性能问题呢?甚至你们习觉得常的拼接字符串在特定条件下都会形成系统崩溃。咱们也知道生产环境就像国际政治同样错综复杂波谲云诡,测试环境、UAT环境经过并不能保证系统诸事无虞,应该时刻认识到coding无小事,不然一个疏忽就有可能形成生产环境发生悲剧乃至惨剧。