PHP海量数据存储 php的数据是怎么样存在内存中的( 三 )


保持超过其机器本身内存大小的数据 。当然,机器本身的内存必须要能够保持所有的key,毕竟这些数据是不会进行swap操作的 。同时由于Redis将内存
中的数据swap到磁盘中的时候,提供服务的主线程和进行swap操作的子线程会共享这部分内存,所以如果更新需要swap的数据,Redis将阻塞这个
操作,直到子线程完成swap操作后才可以进行修改 。
使用Redis特有内存模型前后的情况对比:
VM off: 300k keys, 4096 bytes values: 1.3G used
VM on:300k keys, 4096 bytes values: 73M used
VM off: 1 million keys, 256 bytes values: 430.12M used
VM on:1 million keys, 256 bytes values: 160.09M used
VM on:1 million keys, values as large as you want, still: 160.09M used

从Redis中读取数据的时候 , 如果读取的key对应的value不在内存中,那么Redis就需要从swap文件中加载相应数据,然后再返回给请求方 。
这里就存在一个I/O线程池的问题 。在默认的情况下,Redis会出现阻塞,即完成所有的swap文件加载后才会相应 。这种策略在客户端的数量较小,进行
批量操作的时候比较合适 。但是如果将Redis应用在一个大型的网站应用程序中,这显然是无法满足大并发的情况的 。所以Redis运行我们设置I/O线程
池的大小 , 对需要从swap文件中加载相应数据的读取请求进行并发操作 , 减少阻塞的时间 。
如果希望在海量数据的环境中使用好Redis,我相信理解Redis的内存设计和阻塞的情况是不可缺少的 。
补充的知识点:
memcached和redis的比较
1 网络IO模型
Memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接,接受请求后,将连接描述
字pipe 传递给worker线程 , 进行读写IO, 网络层使用libevent封装的事件库,多线程模型可以发挥多核作用 , 但是引入了cache
coherency和锁的问题,比如,Memcached最常用的stats
命令 , 实际Memcached所有操作都要对这个全局变量加锁,进行计数等工作,带来了性能损耗 。
(Memcached网络IO模型)
Redis使用单线程的IO复用模型 , 自己封装了一个简单的AeEvent事件处理框架,主要实现了epoll、kqueue和select,
对于单纯只有IO操作来说,单线程可以将速度优势发挥到最大,但是Redis也提供了一些简单的计算功能 , 比如排序、聚合等,对于这些操作,单线程模型实
际会严重影响整体吞吐量,CPU计算过程中 , 整个IO调度都是被阻塞住的 。
2.内存管理方面
Memcached使用预分配的内存池的方式,使用slab和大小不同的chunk来管理内存,Item根据大小选择合适的chunk存储,内
存池的方式可以省去申请/释放内存的开销,并且能减小内存碎片产生,但这种方式也会带来一定程度上的空间浪费,并且在内存仍然有很大空间时 , 新的数据也可
能会被剔除,原因可以参考Timyang的文章:
Redis使用现场申请内存的方式来存储数据,并且很少使用free-list等方式来优化内存分配,会在一定程度上存在内存碎片,Redis
跟据存储命令参数 , 会把带过期时间的数据单独存放在一起 , 并把它们称为临时数据,非临时数据是永远不会被剔除的,即便物理内存不够 , 导致swap也不会剔
除任何非临时数据(但会尝试剔除部分临时数据),这点上Redis更适合作为存储而不是cache 。
3.数据一致性问题
Memcached提供了cas命令,可以保证多个并发访问操作同一份数据的一致性问题 。Redis没有提供cas 命令,并不能保证这点,不过Redis提供了事务的功能,可以保证一串 命令的原子性,中间不会被任何操作打断 。

推荐阅读