该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-09-28
发了帖子就没来看了,这才发现被加了良好了,真是不敢当.其实仅仅只是封装,同时找到了一些性能可以改进的点.
回robbin大哥:当时初学的时候得却看到两个,一个说是异步写的很不错,但是当时仅仅只是使用,前面这个时间比较早,觉得会成熟一些。其实后来在和作者交流过程中,他也在不断的优化,同时在我看来,对于nio的异步操作在whalin里面也有用(后来的版本)。 其实对于网络方面socket来说,个人觉得如果是短连接,释放比较快,那么就是一个连接池的维护,长连接说会要去共享信道之类的工作提高效率。同时在过去nio出来的时候,主要能够将服务端效率提高,因为服务端在接受请求以后后续还有很多处理,将接受请求和处理分开,那么就可以最大限度的去建立连接和提高处理效率。对于客户端来说,要么自己的socket用完了,否则我的想法异步或者共享没有什么作用,发送数据现在也不会发超过1m的,因为memcache的value最大限度就是1m。所以后来也就自己搞搞了,不过有空去测试比较一下,也可能就是比那个差。 回sdh5724同学:其实我也很赞同你的意见,我以前和别人说过,cache就是不稳定的,干什么要搞这样,但是在效率和可靠性需求上,不得不做出选择,就说我那个场景,大部分一次读入多次读取的数据,例如服务访问者的信息以及一些安全策略,如果不命中就去数据库取,我要搞垮这个网站十分容易,数据库资源会很容易被消耗,我们之前也考虑过内存数据库之类的,一来成熟产品比较贵,二来开源的东西效率和稳定性值得考虑,所以就自己封装了一下,其实也就是一个备份而已,我觉得有一点是肯定的,做任何事情简单就好,我们这边也是简单化,那就多放几份,丢了就部分粘过去。这里对于系统来说没有说增加太大的复杂度,仅仅就是double了一下服务器。 回movingboy同学:在使用Memcache之前我使用过Jboss Tree Cache还有其他的分布式的Cache,但是JGroup的master node对于管理slave node的问题一直困扰着很多人,其实组播本身就不一定可靠,所以我坚持认为还是暂时放弃分布式的Cache,在我看来现在的分布式无非就三种方式:一种就是类似于Memcache的伪分布式,靠客户端来分数据,同时自己在搞一个集群封装,来互相备份。要么就是用刚才说的基于组播的方式。还有就是现在分布式文件系统或者分布式计算中的master,slave模式,由Master来保证slave的选择和数据迁移,但是master的单点怎么解决呢,就又要拉开来了。说多了,赫赫。 其实Memcache出彩的地方在于它的内存分配算法,当然用java也可以去实现,不过既然有成熟的轮子,那就先用这把,把力气用在更需要去琢磨的有商业价值的技术研究上。还是很感谢robin大哥和各位同学(阿里习惯叫开发的朋友同学),因为自己有一个blog,很多东西也懒惰的贴来贴去,所以也就只关注javaeye,而一直潜水。 |
|
返回顶楼 | |
发表时间:2008-09-28
请教一个小问题: 如果某个slab已经被分配满了,当新的对象被set进来的时候,memcached是会挑选已经过期的对象覆盖掉,还是挑选LRU的对象覆盖掉呢?
|
|
返回顶楼 | |
发表时间:2008-09-29
robbin 写道 请教一个小问题: 如果某个slab已经被分配满了,当新的对象被set进来的时候,memcached是会挑选已经过期的对象覆盖掉,还是挑选LRU的对象覆盖掉呢?
首先,在memcache分配的时候,初始化回去分配一系列的slab,例如初始的slab为80k,然后factor为1.2,那么你会发现开始的时候就会有:80,96,116,....一直到1M大小的slab各一个,假如你的对象集中在其中某一个区间,那么很快那个slab就会分配满,此时如果内存还有,那么就会新建一个同样大小的slab作为链挂在第一个同等大小的slab上,如果说内存也满了,slab也满了,那么就开始LRU算法了。 但是从上面我描述的来看,其实Memcached的LRU算法是针对slab的,而非全局的,因此如果数据集中在一个slab上,那么初始化的时候其他几个slab肯定就浪费了,同时,如果slab的大小和你对象的大小有比较大的size差异,那么浪费的将会更加巨大。所以在你评估使用memcache初始大小和factor的时候需要注意这些,选择适合的初始化size和factor,减少slab分配的浪费。 |
|
返回顶楼 | |
发表时间:2008-09-29
多谢robbin和cenwenchu的指点,让我对MemCached又多了一些认识
|
|
返回顶楼 | |
发表时间:2008-09-29
我很喜欢MEMCACHED。 MEMCACHED非常的稳定, 我有一群机器, MEMCACHED进程已经运行运行了大约1年半了。 表现的算是比较稳定了。
cenwenchu 你说的情况, 我很明白, 就是利用一个不存在KEY去查询数据库, 很容易导致数据库搞跨。 我也在试图解决这个问题。 在理论上, 有很多技术能消除这个问题。 目前, 最流行的技术就 BloomFilter. 这东西能解决不存在的key造成性能的损耗的问题。 不过, 目前, 好像我们的应用没有遭受这样的攻击。 这个实现不是很紧急。 由于,我们这儿使用了很多种不同的CACHE技术。 为了整个系统有一致的cache接口, 方便不同技术的相互切换。 我封装了一个统一的JAVA API对 cache进行操作,通过引用不同CacheProvider实现。 另外,我同时让API代码更容易适合在spring bean 容器下的配置。 自我感觉这是个很好的主意, 因为我们有的团队发生过采用了不适当的cache导致要大规模修改代码的事情。 这也是值得规模使用cache的团队采用的方法。 现在我只需要稍微修改下配置就能简单切换不同的cache产品。 目前我封装了5种cache。 这实际上也很方便做代码测试, 我可以简单的使用Mock的机制做我的代码测试。 |
|
返回顶楼 | |
发表时间:2008-09-29
cenwenchu 写道 robbin 写道 请教一个小问题: 如果某个slab已经被分配满了,当新的对象被set进来的时候,memcached是会挑选已经过期的对象覆盖掉,还是挑选LRU的对象覆盖掉呢?
首先,在memcache分配的时候,初始化回去分配一系列的slab,例如初始的slab为80k,然后factor为1.2,那么你会发现开始的时候就会有:80,96,116,....一直到1M大小的slab各一个,假如你的对象集中在其中某一个区间,那么很快那个slab就会分配满,此时如果内存还有,那么就会新建一个同样大小的slab作为链挂在第一个同等大小的slab上,如果说内存也满了,slab也满了,那么就开始LRU算法了。 但是从上面我描述的来看,其实Memcached的LRU算法是针对slab的,而非全局的,因此如果数据集中在一个slab上,那么初始化的时候其他几个slab肯定就浪费了,同时,如果slab的大小和你对象的大小有比较大的size差异,那么浪费的将会更加巨大。所以在你评估使用memcache初始大小和factor的时候需要注意这些,选择适合的初始化size和factor,减少slab分配的浪费。 这个你有经验么, 我好久没有去维护这些东西了, 现在我的每个CACHE 进程大约使用了4-5G内存。 我没有设置特别的参数。 看来我要好好改善下了。 |
|
返回顶楼 | |
发表时间:2008-09-29
sdh5724 写道 我很喜欢MEMCACHED。 MEMCACHED非常的稳定, 我有一群机器, MEMCACHED进程已经运行运行了大约1年半了。 表现的算是比较稳定了。
cenwenchu 你说的情况, 我很明白, 就是利用一个不存在KEY去查询数据库, 很容易导致数据库搞跨。 我也在试图解决这个问题。 在理论上, 有很多技术能消除这个问题。 目前, 最流行的技术就 BloomFilter. 这东西能解决不存在的key造成性能的损耗的问题。 不过, 目前, 好像我们的应用没有遭受这样的攻击。 这个实现不是很紧急。 由于,我们这儿使用了很多种不同的CACHE技术。 为了整个系统有一致的cache接口, 方便不同技术的相互切换。 我封装了一个统一的JAVA API对 cache进行操作,通过引用不同CacheProvider实现。 另外,我同时让API代码更容易适合在spring bean 容器下的配置。 自我感觉这是个很好的主意, 因为我们有的团队发生过采用了不适当的cache导致要大规模修改代码的事情。 这也是值得规模使用cache的团队采用的方法。 现在我只需要稍微修改下配置就能简单切换不同的cache产品。 目前我封装了5种cache。 这实际上也很方便做代码测试, 我可以简单的使用Mock的机制做我的代码测试。 是的,这也是我封装它第一个目的,接口化,后端实现随时动态替换,只需要在自己实现的jar里面配置一个文件即可。因为我现在的产品比较特殊,是集成第三方服务的平台,自由开发者只需要注册一个开发应用即可使用淘宝,支付宝等API,所以不仅仅是自身安全问题,同时一旦被攻击,后端的服务也将会不能使用,因此才需要这样的考虑,第三方的我没有太多地去找,因为还是觉得有些东西简单化即可,搞太多的依赖反而维护成本会增加。 |
|
返回顶楼 | |
发表时间:2008-09-29
sdh5724 写道 cenwenchu 写道 robbin 写道 请教一个小问题: 如果某个slab已经被分配满了,当新的对象被set进来的时候,memcached是会挑选已经过期的对象覆盖掉,还是挑选LRU的对象覆盖掉呢?
首先,在memcache分配的时候,初始化回去分配一系列的slab,例如初始的slab为80k,然后factor为1.2,那么你会发现开始的时候就会有:80,96,116,....一直到1M大小的slab各一个,假如你的对象集中在其中某一个区间,那么很快那个slab就会分配满,此时如果内存还有,那么就会新建一个同样大小的slab作为链挂在第一个同等大小的slab上,如果说内存也满了,slab也满了,那么就开始LRU算法了。 但是从上面我描述的来看,其实Memcached的LRU算法是针对slab的,而非全局的,因此如果数据集中在一个slab上,那么初始化的时候其他几个slab肯定就浪费了,同时,如果slab的大小和你对象的大小有比较大的size差异,那么浪费的将会更加巨大。所以在你评估使用memcache初始大小和factor的时候需要注意这些,选择适合的初始化size和factor,减少slab分配的浪费。 这个你有经验么, 我好久没有去维护这些东西了, 现在我的每个CACHE 进程大约使用了4-5G内存。 我没有设置特别的参数。 看来我要好好改善下了。 嗬嗬,这个绝对不是我看官方文档YY得,实际测试过的,同时slab的链过长也会影响查询速度。你可以自己测试看看。 |
|
返回顶楼 | |
发表时间:2008-09-29
cenwenchu你好,请教几个问题:
cenwenchu 写道 在使用KeySet的时候有一个参数,类型是Boolean,这个字段的存在是因为,在Memcached中数据的删除并不是直接删除,而是标注一下,这样会导致实现keySet的时候取出可能已经删除的数据
我测试了一下,set一个对象以后,再delete它,然后stats items, stats cachedump itemid 0,发现memcached里面已经查询不到这个对象了。按照你的说法,应该可以遍历到这个对象的key,但实际上我遍历不到。 cenwenchu 写道 从上面我描述的来看,其实Memcached的LRU算法是针对slab的,而非全局的,因此如果数据集中在一个slab上,那么初始化的时候其他几个slab肯定就浪费了
我观察到的现象不是这样的,例如我分配了1.4GB的内存,那么初始化的时候,memcached会按照默认的1.2的factor一直分配到slabs class 38,如下: linux console:~> memcached -m 1400 -vv slab class 1: chunk size 104 perslab 10082 slab class 2: chunk size 136 perslab 7710 slab class 3: chunk size 176 perslab 5957 slab class 4: chunk size 224 perslab 4681 slab class 5: chunk size 280 perslab 3744 slab class 6: chunk size 352 perslab 2978 slab class 7: chunk size 440 perslab 2383 slab class 8: chunk size 552 perslab 1899 slab class 9: chunk size 696 perslab 1506 slab class 10: chunk size 872 perslab 1202 slab class 11: chunk size 1096 perslab 956 slab class 12: chunk size 1376 perslab 762 slab class 13: chunk size 1720 perslab 609 slab class 14: chunk size 2152 perslab 487 slab class 15: chunk size 2696 perslab 388 slab class 16: chunk size 3376 perslab 310 slab class 17: chunk size 4224 perslab 248 slab class 18: chunk size 5280 perslab 198 slab class 19: chunk size 6600 perslab 158 slab class 20: chunk size 8256 perslab 127 slab class 21: chunk size 10320 perslab 101 slab class 22: chunk size 12904 perslab 81 slab class 23: chunk size 16136 perslab 64 slab class 24: chunk size 20176 perslab 51 slab class 25: chunk size 25224 perslab 41 slab class 26: chunk size 31536 perslab 33 slab class 27: chunk size 39424 perslab 26 slab class 28: chunk size 49280 perslab 21 slab class 29: chunk size 61600 perslab 17 slab class 30: chunk size 77000 perslab 13 slab class 31: chunk size 96256 perslab 10 slab class 32: chunk size 120320 perslab 8 slab class 33: chunk size 150400 perslab 6 slab class 34: chunk size 188000 perslab 5 slab class 35: chunk size 235000 perslab 4 slab class 36: chunk size 293752 perslab 3 slab class 37: chunk size 367192 perslab 2 slab class 38: chunk size 458992 perslab 2 slab class 38的chunk size是448KB。假设我的应用程序不会put这么大的对象进去的话,按照你的说法,slab class 38是肯定被浪费掉了,因为预分配了2个,总共浪费2MB内存。 但实际上我观察下来,并非如此。这些预分配的超大slab如果一直空闲,迟早会被memcached回收,比方说JavaEye的memcached现在是这个样子的: linux console:~> memcached-tool localhost:11211 # Item_Size Max_age 1MB_pages Count Full? 1 104 B 101444 s 1 4882 no 2 136 B 101373 s 1 7005 no 3 176 B 100223 s 3 17871 yes 4 224 B 44825 s 12 56172 yes 5 280 B 33624 s 9 33696 yes 6 352 B 45249 s 56 166768 yes 7 440 B 40679 s 12 28596 yes 8 552 B 44904 s 12 22788 yes 9 696 B 42437 s 67 100902 yes 10 872 B 53838 s 37 44474 yes 11 1.1 kB 41718 s 22 21032 yes 12 1.3 kB 49149 s 36 27432 yes 13 1.7 kB 55130 s 35 21315 yes 14 2.1 kB 37793 s 34 16558 yes 15 2.6 kB 51071 s 27 10476 yes 16 3.3 kB 41532 s 31 9610 yes 17 4.1 kB 44724 s 33 8184 yes 18 5.2 kB 45328 s 38 7524 yes 19 6.4 kB 38455 s 43 6794 yes 20 8.1 kB 42549 s 49 6223 yes 21 10.1 kB 45387 s 60 6060 yes 22 12.6 kB 42531 s 70 5670 yes 23 15.8 kB 42652 s 92 5888 yes 24 19.7 kB 42559 s 140 7140 yes 25 24.6 kB 36928 s 70 2870 yes 26 30.8 kB 41898 s 67 2211 yes 27 38.5 kB 44852 s 72 1872 yes 28 48.1 kB 45952 s 65 1365 yes 29 60.2 kB 46564 s 71 1207 yes 30 75.2 kB 43544 s 151 1963 yes slab class 31到slab 38全部都被回收了,并没有被浪费。 |
|
返回顶楼 | |
发表时间:2008-09-29
sdh5724 写道 这个你有经验么, 我好久没有去维护这些东西了, 现在我的每个CACHE 进程大约使用了4-5G内存。 我没有设置特别的参数。 看来我要好好改善下了。 一个memcached使用4-5G内存,还不如启动4-5个进程,每个进程1GB这样更能够有效利用内存。 |
|
返回顶楼 | |