1、降低redis内存占用的优点

  1、有助于减少创建快照和加载快照所用的时间

  2、提升载入AOF文件和重写AOF文件时的效率

  3、缩短从服务器进行同步所需的时间

  4、无需添加额外的硬件就可以让redis存贮更多的数据

2、短结构

  Redis为列表、集合、散列、有序集合提供了一组配置选项,这些选项可以让redis以更节约的方式存储较短的结构。

  2.1、ziplist压缩列表(列表、散列、有续集和)

  通常情况下使用的存储方式

降低Redis内存占用

  当列表、散列、有序集合的长度较短或者体积较小的时候,redis将会采用一种名为ziplist的紧凑存储方式来存储这些结构。

  ziplist是列表、散列、有序集合这三种不同类型的对象的一种非结构化表示,它会以序列化的方式存储数据,这些序列化的数据每次被读取的时候都需要进行解码,每次写入的时候也要进行编码。

    双向列表与压缩列表的区别:

  为了了解压缩列表比其他数据结构更加节约内存,我们以列表结构为例进行深入研究。

  典型的双向列表

    在典型双向列表里面,每个值都都会有一个节点表示。每个节点都会带有指向链表前一个节点和后一个节点的指针,以及一个指向节点包含的字符串值的指针。

    每个节点包含的字符串值都会分为三部分进行存储。包括字符串长度、字符串值中剩余可用字节数量、以空字符结尾的字符串本身。

  例子:

  假若一个某个节点存储了’abc’字符串,在32位的平台下保守估计需要21个字节的额外开销(三个指针+两个int+空字符即:3*4+2*4+1=21)

  由例子可知存储一个3字节字符串就需要付出至少21个字节的额外开销。

  ziplist

    压缩列表是由节点组成的序列,每个节点包含两个长度和一个字符串。第一个长度记录前一个节点的长度(用于对压缩列表从后向前遍历);第二个长度是记录本当前点的长度;被存储的字符串。

  例子:

  存储字符串’abc’,两个长度都可以用1字节来存储,因此所带来的额外开销为2字节(两个长度即1+1=2)

  结论:

  压缩列表是通过避免存储额外的指针和元数据,从而达到降低额外的开销。

  配置:

1 #list
2 list-max-ziplist-entries 512  #表示允许包含的最大元素数量
3 list-max-ziplist-value 64    #表示压缩节点允许存储的最大体积
4 #hash                  #当超过任一限制后,将不会使用ziplist方式进行存储
5 hash-max-ziplist-entries 512
6 hash-max-ziplist-value 64
7 #zset
8 zset-max-ziplist-entries 128
9 zset-max-ziplist-value 64

 测试list:

1、建立test.php文件

1 #test.php
2 <?php
3 $redis=new Redis();
4 $redis->connect('192.168.95.11','6379');
5 for ($i=0; $i<512  ; $i++) 
6 { 
7     $redis->lpush('test-list',$i.'-test-list');  #往test-list推入512条数据
8 }
9 ?>

 

降低Redis内存占用

  此时的test-list中含有512条数据,没有超除配置文件中的限制

2、往test-list中再推入一条数据

降低Redis内存占用

  此时test-list含有513条数据,大于配置文件中限制的512条,索引将放弃ziplist存储方式,采用其原来的linkedlist存储方式

  散列与有序集合同理。

  2.2、intset整数集合(集合)

  前提条件,集合中包含的所有member都可以被解析为十进制整数。

  以有序数组的方式存储集合不仅可以降低内存消耗,还可以提升集合操作的执行速度。

  配置:

1 set-max-intset-entries  512   #限制集合中member个数,超出则不采取intset存储

 

  测试:

  建立test.php文件

1 #test.php
2 <?php
3 $redis=new Redis();
4 $redis->connect('192.168.95.11','6379');
5 for ($i=0; $i<512  ; $i++) 
6 { 
7     $redis->sadd('test-set',$i);   #给集合test-set插入512个member
8 }
9 ?>

降低Redis内存占用

  2.3、性能问题

  不管列表、散列、有序集合、集合,当超出限制的条件后,就会转换为更为典型的底层结构类型。因为随着紧凑结构的体积不断变大,操作这些结构的速度将会变得越来越慢。

  测试:

#将采用list进行代表性测试

测试思路:

1、在默认配置下往test-list推入50000条数据,查看所需时间;接着在使用rpoplpush将test-list数据全部推入到新列表list-new中,查看所需时间

2、修改配置,list-max-ziplist-entries 100000,再执行上面的同样操作

3、对比时间,得出结论

  默认配置下测试:

  1、插入数据,查看时间

 1 #test1.php
 2 <?php
 3 header("content-type: text/html;charset=utf8;");
 4 $redis=new Redis();
 5 $redis->connect('192.168.95.11','6379');
 6 $start=time();
 7 for ($i=0; $i<50000  ; $i++) 
 8 { 
 9     $redis->lpush('test-list',$i.'-aaaassssssddddddkkk');
10 }
11 $end=time();
12 echo "插入耗时为:".($end-$start).'s';
13 ?>

   降低Redis内存占用降低Redis内存占用

结果耗时4秒

  2、执行相应命令,查看耗时

 1 #test2.php
 2 <?php
 3 header("content-type: text/html;charset=utf8;");
 4 $redis=new Redis();
 5 $redis->connect('192.168.95.11','6379');
 6 $start=time();
 7 $num=0;
 8 while($redis->rpoplpush('test-list','test-new'))
 9 {
10     $num+=1;
11 }
12 echo '执行次数为:'.$num."<br/>";
13 $end=time();
14 echo "耗时为:".($end-$start).'s';
15 ?>

降低Redis内存占用

  更改配置文件下测试  

  1、先修改配置文件

  list-max-ziplist-entries 100000  #将这个值修改大一点,可以更好的凸显对性能的影响

  list-max-ziplist-value 64    #此值可不做修改

  2、插入数据

  执行test1.php

  结果为:耗时12s

  降低Redis内存占用

  3、执行相应命令,查看耗时

  执行test2.php

  结果为:执行次数:50000,耗时12s

结论:

在本机中执行测试50000条数据就相差8s,若在高并发下,长压缩列表和大整数集合将起不到任何的优化,反而使得性能降低。

 

3、片结构

  分片的本质就是基于简单的规则将数据划分为更小的部分,然后根据数据所属的部分来决定将数据发送到哪个位置上。很多数据库使用这种技术来扩展存储空间,并提高自己所能处理的负载量。

  结合前面讲到的,我们不难发现分片结构对于redis的重要意义。因此我们需要在配置文件中关于ziplist以及intset的相关配置做出适当的调整。

  3.1、分片式散列

 

  #ShardHash.class.php

 1 <?php
 2 class ShardHash
 3 {
 4     private $redis='';  #存储redis对象
 5     /**
 6     * @desc 构造函数
 7     * 
 8     * @param $host string | redis主机
 9     * @param $port int    | 端口
10     */
11     public function __construct($host,$port=6379)
12     {
13         $this->redis=new Redis();
14         $this->redis->connect($host,$port);
15     } 
16 
17     /**
18     * @desc 计算某key的分片ID
19     *
20     * @param $base  string | 基础散列
21     * @param $key   string | 要存储到分片散列里的键名
22     * @param $total int    | 预计非数字分片总数
23     * 
24     * @return string | 返回分片键key
25     */
26     public function shardKey ($base,$key,$total)
27     {
28         if(is_numeric($key))
29         {
30             $shard_id=decbin(substr(bindec($key),0,5));  #取$key二进制高五位的十进制值
31         }
32         else
33         {
34             $shard_id=crc32($key)%$shards;  #求余取模
35         }
36         return $base.'_'.$shard_id;
37     }
38 
39     /**
40     * @desc 分片式散列hset操作
41     *
42     * @param $base  string | 基础散列
43     * @param $key   string | 要存储到分片散列里的键名
44     * @param $total int    | 预计元素总数
45     * @param $value string/int | 值
46     *
47     * @return bool | 是否hset成功
48     */
49     public function shardHset($base,$key,$total,$value)
50     {
51         $shardKey=$this->shardKey($base,$key,$total);
52         return $this->redis->hset($shardKey,$key,$value);
53     }
54 
55     /**
56     * @desc 分片式散列hget操作
57     *
58     * @param $base  string | 基础散列
59     * @param $key   string | 要存储到分片散列里的键名
60     * @param $total int    | 预计元素总数
61     *
62     * @return string/false | 成功返回value
63     */
64     public function shardHget($base,$key,$total)
65     {
66         $shardKey=$this->shardKey($base,$key,$total);
67         return $this->redis->hget($shardKey,$key);
68     }
69 
70 } 
71 
72 $obj=new ShardHash('192.168.95.11');
73 echo $obj->shardHget('hash-','key',500);
74 ?>
View Code

相关文章:

  • 2021-11-13
  • 2022-12-23
  • 2022-12-23
  • 2021-12-26
  • 2021-04-16
  • 2022-12-23
  • 2021-12-01
  • 2022-02-28
猜你喜欢
  • 2022-01-09
  • 2022-01-07
  • 2022-12-23
  • 2021-11-14
  • 2022-03-06
相关资源
相似解决方案