前言
许多web应用都将数据保存到RDBMS(Relational Database Management System 关系型数据库管理系统)中。应用服务器从中读取数据并显示在浏览器中,but 随着数据量增大、访问集中等情况,RDBMS的负载就会加重,会拖慢数据库响应(响应恶化),网站显示延迟等重大影响。(像搜索类的、提交的评论、等等由用户发起的一系列,需要经过数据库的请求等,都会很慢)
那怎么办呢?
这时候,一个 高性能 的 分布式 内存 缓存 服务器就出现了,比如非关系型数据库Memcache、Redis。
== 它通过缓存数据库的查询结果,减少数据库访问次数,来提高动态web等应用的响应速度,提高可扩展性。==
简介
缓存服务器的作用>>>>>>>>>>加快动态网站访问响应速度,缓解数据库压力。
NOSQL非关系型数据库
NOSQL==》not only sql :弥补关系型数据库的不足,以键值对 (key value)的方式存储数据,做缓存数据库
三种:redis、memcache、mongoDB
Memcache
memcache是一个分布式内存对象缓存系统,开源,用于动态web应用,减轻数据库负载。通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高网站访问速度。
它是一个存储键值对的HashMap,在内存中,对任意数据所使用的key-value存储。memcache的设计小而强大,促进了快速部署,易于开发并解决大规模数据缓存的很多难题。
memcache是这个项目的名称,memcached是可执行文件的名称。
支持平台很多,linux、freeBSD、Solaris、Mac OS X、Windows
特点
-
内置内存存储方式:重启操作系统会导致全部数据消失
-
简单key/value存储:只要是可序列化数据就行,不关心数据本身的意义和结构。存储项由四部分组成:
- 键
- 过期时间
- 可选标志
- 数据
- 不互相通信的分布式
尽管memcached是分布式的缓存服务器,但是memcached本身没有分布式的功能,每个memcached不会相互通信来共享信息。
那怎么进行分布式呢?这取决于客户端的实现。客户端程序库进行分布式算法,分发到每个memcached
原理
检查用户请求的数据在缓存中是否存在,如果有存在的话,只需要直接把请求的数据返回,无需查询数据库。
如果请求的数据在缓存中找不到,这时候再去查询数据库,返回请求数据的同时,把数据也在缓存中存一份。
要保持缓存的“新鲜性”,每当数据发生变化的时候(什么变化?数据被修改删除之类的),要同步更新缓存信息,确保用户不会在缓存里拿到旧数据,要新的。
Memcache安装部署
memcache的部署需要两个组件,一个是libevent,另一个才是memcache。
- libevent 它是memcache依赖的一个网络库,在安装memcache之前需要先安装这个网络库。
在libevent官网下载最新的安装包
我这里下载的是libevent-2.1.12-stable.tar.gz
tar xzf libevent-2.1.12-stable.tar.gz
cd libevent-2.1.12-stable
yum -y install gcc make zlib-devel pcre pcre-devel openssl-devel #安装编译环境,装过的就不用了。
./configure --prefix=/usr/local/libevent
make && make install
- memcached部署
在memcached官网下载最新版,我这里下载的是memcached-1.6.9.tar.gz
也可以wget http://www.memcached.org/files/memcached-1.6.9.tar.gz
tar xzvf memcached-1.6.9.tar.gz
cd memcached-1.6.9
./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent
make && make install
memcache测试
可以简单的看一下,memcached端口是11211
[root@bogon memcached-1.6.9]# netstat -antp | grep 11211
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 7798/memcached
tcp6 0 0 :::11211 :::* LISTEN 7798/memcached
使用telnet工具来登录
yum -y install telnet
[root@bogon memcached-1.6.9]# telnet localhost 11211
Trying ::1...
Connected to localhost.
Escape character is '^]'.
set name 0 900 4
tome
STORED #这个表示保持成功
get name #获取name(就是显示刚才保存的name)
VALUE name 0 4
tome
END
quit #quit退出
Connection closed by foreign host.
redis
开源的、C语言编写的、支持网络交互、 基于内存也可以持久化key-value数据库
它支持丰富的数据结构、支持持久化(可以长久保存)、支持事务(集群分布式,保证数据安全),支持主从
(什么是事务? 事务是指一个完整的动作,要么全部执行,要么什么也不做)
安装
从redis.io下载最新版redis-X.Y.Z.tar.gz后解压,然后进入redis-X.Y.Z文件夹后直接make即可。我下载的是redis-6.2.4.tar.gz
tar xvzf redis-6.2.4.tar.gz -C /usr/local/
cd /usr/local/
mv redis-6.2.4/ redis
cd redis/
make
mkdir /etc/redis
cp redis.conf /etc/redis/6379.conf
cp utils/redis_init_script /etc/init.d/redis
vim /etc/init.d/redis
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
chkconfig: 2345 10 90
description: Start and Stop redis
### BEGIN INIT INFO
# Provides: redis_6379
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Redis data structure server
# Description: Redis data structure server. See https://redis.io
### END INIT INFO
REDISPORT=6379
EXEC=/root/redis-6.2.4/src/redis-server
CLIEXEC=/root/redis-6.2.4/src/redis-cli
PIDFILE=/var/run/redis_${REDISPORT}.pid
CONF="/etc/redis/${REDISPORT}.conf"
case "$1" in
start)
if [ -f $PIDFILE ]
then
echo "$PIDFILE exists, process is already running or crashed"
else
echo "Starting Redis server..."
$EXEC $CONF
fi
;;
stop)
if [ ! -f $PIDFILE ]
then
echo "$PIDFILE does not exist, process is not running"
else
PID=$(cat $PIDFILE)
echo "Stopping ..."
$CLIEXEC -p $REDISPORT shutdown
while [ -x /proc/${PID} ]
do
echo "Waiting for Redis to shutdown ..."
sleep 1
done
echo "Redis stopped"
fi
;;
*)
echo "Please use start or stop as first argument"
;;
esac
chmod +x /etc/init.d/redis
给init.d下的redis文件执行权限
chkconfig --add redis
增加开机启动设置
chkconfig redis on
设置redis开机启动
systemctl daemon-reload
重新加载自启动信息
systemctl start redis
启动redis
测试
[root@bogon ~]# redis-6.2.4/src/redis-cli
127.0.0.1:6379> set name xuexi
OK
127.0.0.1:6379> get name
"xuexi"
127.0.0.1:6379> exit
redis持久化
什么是持久化?持久化是干什么的?
开启持久化后,重启redis,数据会自动通过持久化文件恢复
两种持久化的方式:RDB、AOF
- RDB(redis database)
rdb是在不同时间点上,将redis存储的数据生成快照并存储到磁盘等介质上
(1)具有周期性
(2)不会影响数据的写入:rdb会启动子进程,备份所有数据,当前进程继续提供数据的读写。当备份完成后,才替换掉备份文件
(3)具有高效:一次性还原所有数据
(4)完整性较差:故障点 到 上一次备份之间的数据没有办法恢复
- AOF (append only file)
AOF 相比于RDB,就是换了一个角度来实现持久化。它将redis执行过的所有的写指令都记录在日志中(每秒中),当下次redis重新启动时,只需要把这些写指令,从前到后再重复执行一遍,就可以实现数据恢复了。
- 具有实时性
- 完整性比RDB要好一些
- 但是它体积大,会记录数据的指令,删除数据的指令都会被记录下来。
那该如何选择持久化的方式呢?
如果只做缓存的话,不用开启任何持久化方式。
由于rdb数据的不实时性,两个一起开,当然,一起开的话,服务器只会去找AOF文件,所以,rdb文件当作万一的手段。
配置
- rdb默认开启。
查看开启状态
vim /redis-6.2.4/redis.conf #dbfilename:持久化数据存储在本地的文件
dbfilename dump.rdb #dir:持久化数据存储在本地的路径,如果是在/root/redis-6.2.4/src下启动的redis-cli,则数据会存储在当前src目录下
dir ./
##snapshot触发的时机,save <seconds> <changes>
##如下为900秒后,至少有一个变更操作,才会snapshot
##对于此值的设置,需要谨慎,评估系统的变更操作密集程度
##可以通过“save “””来关闭snapshot功能
#save时间,以下分别表示更改了1个key时间隔900s进行持久化存储;更改了10个key300s进行存储;更改10000个key60s进行存储。
save 900 1
save 300 10
save 60 10000
##当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,“错误”可能因为磁盘已满/磁盘故障/OS级别异常等
stop-writes-on-bgsave-error yes
##是否启用rdb文件压缩,默认为“yes”,压缩往往意味着“额外的cpu消耗”,同时也意味这较小的文件尺寸以及较短的网络传输时间
rdbcompression yes
- AOF默认关闭
修改配置文件redis.conf
##此选项为aof功能的开关,默认为“no”,可以通过“yes”来开启aof功能
##只有在“yes”下,aof重写/文件同步等特性才会生效
appendonly yes
##指定aof文件名称
appendfilename appendonly.aof
##指定aof操作中文件同步策略,有三个合法值:always everysec no,默认为everysec
##设置always时,会极大的消耗redis的性能,因为这种模式下,每次write后都会调用fsync(linux为调用fdatasync);
##如果设置成no,write后不会有fsync调用,由操作系统自动调度刷磁盘,性能是最好的;
## everysec是最多每秒调用一次fsync,这种模式性能不是很糟糕,一般也不会产生毛刺,
##主要是因为,redis引入了BIO线程,所有的fsync操作都异步的交给了BIO线程。
appendfsync everysec
##在aof-rewrite期间,appendfsync是否暂缓文件同步,"no"表示“不暂缓”,“yes”表示“暂缓”,默认为“no”
no-appendfsync-on-rewrite no
auto-aof-rewrite-min-size 64mb
##触发aof rewrite的最小文件尺寸
auto-aof-rewrite-percentage 100
##当Aof log增长超过指定比例时,重写log file,
##设置为0表示不自动重写Aof日志,重写是为了使aof体积保持最小,而确保保存最完整的数据。
redis主从
用法及原理
主从架构中,建议关闭主服务器的数据持久化功能(提高主服务器的处理性能),只让从服务器进行持久化。
redis跟MySQL一样,支持主从同步,也支持一主多从以及多级从结构。
主从结构,一方面时纯粹的冗余备份,另一方面也是为了提升读的性能,比如很消耗性能的SORT就可以由从服务器来承担。
redis的主从同步时异步进行的,也就是说,它的主从同步不会影响主逻辑,也不会降低redis的处理性能。
在主从架构中,从服务器通常被设置成只读的模式,以避免从服务器的数据被误修改,但是从服务器仍然可以接收config等指令,所以,不要把从服务器直接暴露在不安全的网络环境中,如果必须如此,那可以考虑给重要指令进行重命名,以避免命令被外人误执行。
原理(字多读两遍)
从服务器会向主服务器发出SYNC指令(一个数据同步的指令),当主服务器接到此命令后,就会调用BGSAVE指令来创建一个子进程专门进行数据持久化工作,也就是将主服务器的数据写入RDB文件中。在数据持久化期间,主服务器将执行的写指令都缓存在内存中。
在BGSAVE(后台备份程序)指令执行完成后,主服务器会将持久化好的RDB文件发送给从服务器,从服务器接到此文件后会将其存储到磁盘上,然后再将其读取到内存中。这个动作完成后,主服务器会将这段时间缓存的写指令再以redis协议的格式发送给从服务器。
另外,要说的一点是,即使有多个从服务器同时发来SYNC指令,主服务器也只会执行一次BGSAVE,然后把持久化好的RDB文件发给多个下游。在redis2.8版本之前,如果从服务器与主服务器因某些原因断开连接的话,都会进行一次主从之间的全量的数据同步;而在2.8版本之后,redis支持了效率更高的增量同步策略,这大大降低了连接断开的恢复成本。
主服务器会在内存中维护一个缓冲区,缓冲区中存储着将要发给从服务器的内容。从服务器在与主服务器出现网络瞬断之后,从服务器会尝试再次与主服务器连接,一旦连接成功,从服务器就会把“希望同步的主服务器ID”和“希望请求的数据的偏移位置(replication offset)”发送出去。主服务器接收到这样的同步请求后,首先会验证主服务器ID是否和自己的ID匹配,其次会检查“请求的偏移位置”是否存在于自己的缓冲区中,如果两者都满足的话,主服务器就会向从服务器发送增量内容。
增量同步功能,需要服务器端支持全新的PSYNC指令。这个指令,只有在redis-2.8之后才具有。
redis主从搭建
准备:三台服务器,保持通信畅通 ,关闭防火墙selinux ,改主机名,增加本地的域名解析master1、slave2、slave3,并安装redis
master1
vim /etc/redis/6379.conf
##监听本机所有IP
##关闭保护模式
bind 0.0.0.0
protected-mode no
systemctl restart redis
重启redis服务
slave1、2
vim /etc/redis/6379.conf
slaveof 10.9.30.108 6379 #masterIP地址和端口。slave仆从,谁的仆从,108的。
bind 0.0.0.0
protected-mode no
systemctl restart redis
重启redis服务
redis主从测试
两项:数据的一致性 和 服务的状态
- 数据一致性
/redis/src/redis-cli
>set abcd defg
>info replication
从库看/redis/src/redis-cli
>get abcd
>info replication
到此为止,保持数据的一致性体现出来了,但是冗余却没有体现出来,这个时候,哨兵模式就出现了
redis sentinel
Redis-Sentinel是Redis官方推荐的一个高可用(HA)的解决方案,实际上,这以为着,你可以使用Sentinel模式,创建一个可以不用认为干涉就能应对各种故障的redis部署。
它可以用作:
- Master状态检测
- 如果主服务器出现故障,就会进行主从切换
- 切换后,配置文件的内容会发函俄国改变,监控目标也会调换
工作方式
- 每个哨兵会以每1s一次的频率向它所知的Master、Slave以及其他的sentine实例,发送一个ping的命令
- 如果实例距离最后一次有效回复ping命令的时间超过了 down-after-miliseconds 选项指定的指,则这个实例会被标记为主观下线(宕掉了)
- 如果一个Master服务器被标记为主观下线,那么正在监视这个master服务器的所有sentinel会以每秒一次的频率来确认master是不是真的进入了主观下线状态。
- 当有足够数量的sentinel,在指定范围内,确认了master确实进入了主观下线状态,那么master就会被标记,然后重新选举master。(足够数量的sentinel和指定范围都是可以自己自定义的)
redis-sentinel的部署
准备:三台服务器,都安装好redis(配置啥的如上所示,把mester的RDB和AOF给关了),关闭防火墙和selinux
vim /root/redis-6.2.4/setinel.conf
sentinel monitor mymaster 10.9.30.108 6379 2 #设置主服务器ip和端口,并设置当有两台sentinel认为master死掉的时候,才真正认为master死掉
sentinel down-after-milliseconds mymaster 3000 #单位毫秒,在3s内,没有收到有效回复,就认为master死掉了
sentinel failover-timeout mymaster 10000 #10s内为完成故障转移操作,就认为失败
protected-mode no
cd redis-6.2.4
./src/redis-sentinel sentinel.conf
启动
redis-sentinel的测试
把master的redis服务关掉,看看另外两台的变化