非一致性内存访问模型与内存分配器

标签: 计算机与 Internet | 发表时间:2011-10-22 01:11 | 作者:snnn119 cong
出处:http://snnn.sinaapp.com

CPU主频涨不上去了,一直停留在2-3G。前端总线的时钟频率也涨不上去了,我现在用的这个小黑,Intel Core2 P8600,前端总线的时钟频率只有266MHz。于是,虽然内存越来越便宜了,但是没有那么大的高速带宽来连接CPU和内存啊。

于是NUMA出现了。CPU组成node,每个node各自管理几十G内存,然后node和node之间通过Point-to-Point的方式建立高速直连。于是系统总线就没了,出现一个新名词,QPI,指那个快速访问通道,它不光连接内存和CPU,还连接其它外设如显卡。但是有个重要的结果是:CPU到每根内存条的“距离”是不相等的。有的是直连,所以速度很快,而有的需要绕到另一个node去拿,这样不仅速度慢,而且很容易把node之间的那个互连通道堵死。想想看,如果你工作在天津,但是偏偏要住在北京,每天上班下班是不是很痛苦?为什么呢?为什么会这样?为什么我想访问的这个内存不在我身边?那它在哪?

从C语言的malloc说起。首先强调一点,malloc分配的是“地址空间”,而不是内存!同理,free释放的也只是地址空间,而不是内存。当你访问某个内存地址,而这个地址没有映射到任何物理页的时候,就会发生缺页中断,然后此时,操作系统才分配内存。简单点说,”内存的分配发生在第一次访问的时候!“。

总的来说,内存分配器此时有三种策略:
1、糊里糊涂。什么都不知道,随便分。
2、就近,找离当前CPU最近的node分配。
3、round-robin。把你要的东西尽可能的平均分到每个node上。

我不清楚你用的C Runtime到底是哪一种实现,反正以上三种都有可能。喜欢C的人大多都是追求高效,那么自然喜欢第二种咯?于是就有人提出,服务器的启动过程应该做成并行化的,比如IO的buffer就让IO线程去初始化,各自做各自的。这样听起来很有道理,但是!亲爱的,如果这个线程被调度到另一个CPU上怎么办?所以我们不光得控制内存怎么分配的,还得控制线程调度策略,把这个线程绑在固定的CPU组上。更复杂的是,执行任务的是一个线程池怎么办?请问,我是在写Application,还是Operating System? 无论如何,“谁要用谁分配”依然是一个有效的优化策略。

那么说Java吧,它比较清晰。Java有4种垃圾回收策略 串行化、并行、CMS(并发)、G1。如果选择了并行化的垃圾回收策略(Server版的jvm默认如此),它的内存池分为三类:新生代、老生代、永生代。
并行化的垃圾回收器有一个开关,-XX:+UseNUMA,这个影响到新生代的Eden Space这个内存池的分配器的策略。先说Eden Space是干什么的:大部分new出来的对象都是首先在Eden Space上创建,这里面的对象都是临时创建而又立马被销毁的对象,否则会很快(小于1秒)就被挪到老生代里面去。如果打开了-XX:+UseNUMA,那么Eden Space会尽量就近找node分配,从而获得最经济、快捷的内存访问。可是另外,其它几个内存池呢?他们要么是采用的糊里糊涂的方式,要么就是采用的方式3,做round-robin。所以说,前面所说的为了内存访问局部化而把启动过程做成并行的对JAVA来说完全不适用。

那么,现在重新思考NUMA的问题:访问速度、带宽。
访问速度:的确,访问远处的内存会慢些,但是会慢多少呢?30%?50%?200%?你测过吗?我没有。据说,即便再慢,也比Nehalem之前的任何CPU快,因为改进了系统架构去掉北桥做了QPI等等。而且,根据我看到的各种数据来看,速度差距在50%以内。NUMA真是个很有意思的话题。我初次接触到这个概念是在《Solaris内核结构》那本书上,那本书是06年出版的。那个时代的硬件和现在差别很大的,那时候做NUMA可真是死了心的做,差2倍、差20倍它也觉得没问题,因为它和SMP相比增加了带宽嘛。于是OS就得被迫为这样巨大的差异做各种优化。可是现在呢?你看JVM,为什么仅仅对Eden Space做了就近分配?网上有很多关于NUMA的文章,以及如何在NUMA架构上写出更高效的程序。但是,很多观点是陈旧的。

带宽:你确实把CPU间的QPI跑满了吗?近年产的CPU,每条QPI的单向带宽是每秒12GB(理论最大值),如今看来,只有大型的数据库Server或者Cache Server才有可能把它跑满。否则,你不需要考虑带宽的问题。

所以现在有一种新的策略:SUMA,或者叫page interleaving,这个可以做到硬件层面去。把物理地址空间以均匀交替的方式分给每个node。例如0×0000-0x0FFF分给node 1,0×1000-0x1FFF分给node 2,以此类推。然后所有软件完全不在乎NUMA这件事情。做page interleaving的目的是尽可能平均的使用每个QPI通道。我觉得一般来说,这就足够了。Intel NUMA的x86 CPU在3年前才开始陆续面世,先让OS、compiler、jvm这些去适应它,等他们都折腾够了,最后才是我们这些普通的software developer。

相关 [一致性 内存 访问] 推荐:

非一致性内存访问模型与内存分配器

- est - snnn的blog
CPU主频涨不上去了,一直停留在2-3G. 前端总线的时钟频率也涨不上去了,我现在用的这个小黑,Intel Core2 P8600,前端总线的时钟频率只有266MHz. 于是,虽然内存越来越便宜了,但是没有那么大的高速带宽来连接CPU和内存啊. CPU组成node,每个node各自管理几十G内存,然后node和node之间通过Point-to-Point的方式建立高速直连.

一个速度快内存占用小的一致性哈希算法

- - 鸟窝
这篇论文中提出在动态变化的Cache环境中,哈希算法应该满足的4个适应条件::Balance(均衡)、Monotonicity(单调性)、Spread(分散性)、Load(负载). 在分布式缓存系统中使用一致性哈希算法时,某个节点的添加和移除不会重新分配全部的缓存,而只会影响小部分的缓存系统,如果均衡性做的好的话,当添加一个节点时,会均匀地从其它节点移一部分缓存到新的节点上;当删除一个节点的时候,这个节点上的缓存会均匀地分配到其它活着的节点上.

Nginx使用Linux内存加速静态文件访问

- - IT技术博客大学习
标签:   Nginx. Nginx是一个非常出色的静态资源web服务器. 如果你嫌它还不够快,可以把放在磁盘中的文件,映射到内存中,减少高并发下的磁盘IO. nginx.conf中所配置站点的路径是/home/wwwroot/res,站点所对应文件原始存储路径:/opt/web/res. shell脚本非常简单,思路就是拷贝资源文件到内存中,然后在把网站的静态文件链接指向到内存中即可.

一致性hash

- - 互联网 - ITeye博客
一致性hash算法 - consistent hashing. 分类:  算法艺术2010-02-02 09:19 69836人阅读  评论(97)  收藏  举报. 算法 cache object 服务器 存储 c. 一致性 hash 算法( consistent hashing ).

Redis BGSAVE因为内存不足 fork 失败导致目标 Redis 无法访问的问题 - piperck - 博客园

- -
中秋的时候正在外面愉快的在外卖喝着咖啡玩电脑. 突发 redis 报警从 sentry 应用端曝出的错误. 于是又开始愉快的处理问题了,看上去像是执行 rdb 快照持久化的时候出现的问题,上到 redis 机器查看日志定位详细问题. 可以很明显的发现应该是尝试 fork 的时候内存不够,并没有被 linux 内核放行.

大数据的一致性

- - 阳振坤的博客
看到了一篇关于数据一致性的文章:下一代NoSQL:最终一致性的末日. (  http://www.csdn.net/article/2013-11-07/2817420 ),其中说到: 相比关系型数据库,NoSQL解决方案提供了shared-nothing、容错和可扩展的分布式架构等特性,同时也放弃了关系型数据库的强数据一致性和隔离性,美其名曰:“最终一致性”.

COMMIT和数据一致性

- - Oracle - 数据库 - ITeye博客
[align=justify; direction: ltr; unicode-bidi: embed; vertical-align: baseline;]2.在执行一条update语句后一直未提交,数据会写到数据文件中吗. 一致性查询及一致性读原理. 如果8点钟可以查询出两条记录,假设一下,如果此查询很慢,从8点开.

一致性HASH算法

- - 企业架构 - ITeye博客
一致性 hash 算法( consistent hashing ). consistent hashing 算法早在 1997 年就在论文 . Consistent hashing and random trees 中被提出,目前在cache 系统中应用越来越广泛;. 比如你有 N 个 cache 服务器(后面简称 cache ),那么如何将一个对象 object 映射到 N 个 cache 上呢,你很可能会采用类似下面的通用方法计算 object 的 hash 值,然后均匀的映射到到 N 个 cache ;.