一
使用redis的原因:
1.使用磁盘存数据,访问太慢;
2.使用数据库索引,还是较慢;
因此使用redis内存数据库,存放热数据。
缓存穿透:
要访问的数据不在redis中,穿透到了数据库去找。
解决方案:
为防止黑客多次使用无效字段访问而导致多次缓存穿透,可使用过滤器,来存放有效字段;
然而过滤器的数据也是放在内存,如果数据太多会造成内存紧张,效果适得其反;
因此过滤器采用了布隆算法。
布隆算法:
将有效字段通过hash函数求得的二进制数组的方式来代表有效字段。
二进制数组占内存非常少。
通过错误率换取空间:
因为不同数进行hash计算后可能得到相同值,所以,可能会把某个无效字段判为有效字段,但反之不可能,因此影响不大。
降低错误率:增加数组长度;增加散列函数。
但也不可太多个散列,极端情况下会出现全为1,导致误判严重
假设过滤器采用十位的数组:
如下图,假设 S 集合中有n个元素,利用 k 个哈希函数,将S中的每个元素映射到一个长度为 10 的位(bit)数组中不同的位置上,这些位置均置为1。
如果待检测的元素经过这k个哈希函数的映射后,发现其k个位置上的二进制数不全是1,那这个元素一定不在S中,反之,该元素可能是S中的某一个元素。
缓存击穿:
存放在redis的某条数据,超时后仍然为热数据,导致数据库被频繁访问。缓存穿透的一种。
解决方案:
对中小型的服务器一般不需要解决,只是单条数据而已。
大型:分布式锁。(zookeeper)
(普通的synchronized只能用于同一个服务器内)
当某个服务器获得锁取得数据,就会放在redis中,这样其它服务器也可以直接去redis拿了。如果不用锁的话,还是会导致在把数据放到redis的过程中MySQL依然要承受短暂压力。
举例: (注:现实中几乎不用这种方式)
对数据库加锁(value),当服务器们想要访问数据库某条热数据时,必须先抢到锁(insert value)。
为了避免服务器在获得锁之后宕机,又使用了另一个jvm来监测。但如果设置锁超时时间过长,可能会导致效率低下;过短又可能会导致几个服务器同时获得锁。
缓存雪崩:
redis的多条热数据同时失效,导致数据库被频繁访问。
原因:
- 有效期一样。
解决方案: 给每条数据设置随机有效期。 - redis挂了。
解决方案: 使用redis集群。
redis集群: 把redis放在多个服务器。
数据量少时,使用 主从复制。
数据量大时,使用 切片。
常用方法:一致性hash算法。
一致性hash算法:
举例:使用 2^32个节点的hash环。
把热数据通过hash (key) 再求余2^32;
把服务器进行hash (ip+端口)再求余2^32,
分别对应环上的某个节点。
把环上的热数据都放在顺时针前一个的redis里。
这样,不管有多少台服务器redis,动态扩展时,都只要对其中的两个redis进行复制。
一般的,在一致性哈希算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据;如果增加一台服务器,则受影响的数据仅仅是新服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据。
性质:1、平衡性:哈希结果尽可能分布到所有缓冲中去;
2、单调性:有新的缓冲区加入到系统中,那么哈希的结果应能够保证原有已分配的内容可以被映射到
新的缓冲区中去,而不会被映射到旧的缓冲集合中的其他缓冲区。
3、分散性:由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相
同的内容被不同的终端映射到不同的缓冲区中;(要尽量降低分散性)
4、负载:对于一个特定的缓冲区而言,也可能被不同的用户映射为不同的内容;(要降低
5、平滑性:缓存服务器的数目平滑改变和缓存对象的平滑改变是一致的。
若出现数据倾斜,可以使用虚拟节点机制,对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。可以知道,虚拟节点越多,数据就能分布更均匀。
实现方式:可以在服务器ip 端口后面加上编号。
二
1、Linux中的redis安装
直接解压后到文件夹内进行make即可,过程中报错大概率是因为gcc版本太低 ,可以临时提高:
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
再重新make即可 。
打开文件夹下的src文件夹中,存在redis-server,即安装成功。
2 、启动redis
(1)直接进入文件夹下的src文件夹执行 ./redis-server,出现图标 ,表示服务已启动;
此时可以用另一终端执行同目录下的 ./redis-cli,即可使用服务 。
但这种启动方式是前台的。
此时若要关闭服务,写入exit即可。
(2)修改安装文件夹下的配置文件 redis-conf,把下方这一行的no 改为yes
daemonize no
再重新启动服务 ,出现以下:
即已在后台运行 。
此时若要关闭服务 ,要使用 netstat或 ps 命令去kill进程 。
(3)将redis设为开机启动项。
在/etc下新建redis文件夹
把刚刚提到的 redis.conf文件复制一份过去
将与redis.conf 在同一目录下的 utils目录下的redis_init_script 复制一份到 /etc/init.d/redisd 下
进入 /etc/init.d 目录,执行 chkconfig redisd on,设为开机自启动
然后就可以使用 service redisd start / service redisd stop 来启动 /关闭服务了