随着互联网飞速发展,数据访问量和存储量高速扩大,传统的架构APP访问DAL层,DAL层在查询直接通过关系数据库(比如MySQL数据库)获取数据返回给用户已然出现了性能问题。为了解决这一问题,需要对数据库和数据表水平拆分和垂直拆分。
数据库拆分之后就会出现多个数据库,多个数据库又分别部署在不同的服务器,这时就需要对数据库进行集群,为了保证多台机器的缓存一致、可用性和分区容错性,分布式缓存(redis)的诞生正好解决了这个痛点。
分布式缓存为多个web服务器提供一个共享的高性能缓存服务。
REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统。
Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存亦可持久化的日志型、 Key-Value 数据库,并提供多种语言的 API。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型
Memcached:多核的缓存服务,更加适合于多用户并发访问次数(访问次数较少的应用场景)
Redis:单核缓存服务,在单节点的情况下,更加适合少量用户,多次访问的应用场景。
扩展
redi出现问题的两种现象:
#1.缓存雪崩:Redis缓存层由于某种原因宕机后,所有的请求会涌向数据库存储层,短时间内的高并发请求可能会导致存储层挂机,称之为“Redis雪崩”。
规避方案:1.服务器启动时,提前写入
2.规范key的命名,通过中间件拦截
3.对某些高频访问的key,设置合理的TTL或永不过期
#2.缓存击穿:在Redis获取某一key时, 由于key不存在, 而必须向数据库发起一次请求的行为, 称为“Redis击穿”。
规避方案:1.使用redis集群
2.限流
#1.解压
[root@docker ~]# wget https://download.redis.io/releases/redis-6.0.9.tar.gz
[root@docker ~]# tar -xf redis-6.0.9.tar.gz -C /usr/local
[root@docker ~]# cd /usr/local/redis-6.0.9/
#2.编译
在linux中编译软件需要安装gcc gcc-c++ make 等如软件。
[root@docker redis-6.0.9]# yum -y install centos-release-scl
[root@docker redis-6.0.9]# yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
[root@docker redis-6.0.9]# scl enable devtoolset-9 bash
[root@docker redis-6.0.9]# make -j #多核编译
#3.安装
[root@docker redis-6.0.9]# make PREFIX=/usr/local/redis install #指定目录安装
#4.将配置文件移动到指定目录
[root@docker redis]# mkdir conf
[root@docker redis]# mv ../redis-6.0.9/redis.conf conf/
[root@docker redis]# ll
总用量 0
drwxr-xr-x 2 root root 134 4月 30 20:35 bin
drwxr-xr-x 2 root root 24 4月 30 20:38 conf
[root@docker redis]# ll conf/
总用量 84
-rw-rw-r-- 1 root root 84841 10月 27 2020 redis.conf
#5.启动
[root@docker redis]# ./bin/redis-server ./conf/redis.conf #指定配置文件启动、
#6.验证启动
[root@docker ~]# cd /usr/local/redis
[root@docker redis]# ./bin/redis-cli
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
kind: Deployment
apiVersion: apps/v1
metadata:
name: redis-deployment
spec:
selector:
matchLabels:
app: redis
deploy: redis
template:
metadata:
labels:
app: redis
deploy: redis
spec:
containers:
- name: redis
image: redis:6.0.9
---
kind: Service
apiVersion: v1
metadata:
name: redis-deployment-svc
spec:
ports:
- port: 6379
targetPort: 6379
name: redis
protocol: TCP
selector:
app: redis
deploy: redis
type: NodePort
#1.注册服务
cat > /usr/lib/systemd/system/redis.service << EOF
[Unit]
Description=Redis
After=network.target
[Service]
Type=forking
PIDFile=/var/run/redis_6379.pid
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
#2.修改配置文件
[root@docker conf]# vim /usr/local/redis/conf/redis.conf
daemonize yes #将no改为yes
#3.使用systemctl启动redis
[root@docker conf]# systemctl start redis
#1.修改配置文件内容
[root@docker conf]# vim /etc/profile
在最后添加内容
export REDIS_HOME=/usr/local/redis
PATH=$PATH:$REDIS_HOME/bin
[root@docker conf]# source /etc/profile #重新加载环境变量
#2.测试
[root@docker ~]# redis-cli
127.0.0.1:6379>
#1.修改配置文件
[root@docker conf]# vim /usr/local/redis/conf/redis.conf
requirepass 123
#2.重启
[root@docker ~]# systemctl restart redis.service
#进入以后提示无权限 需要密码
[root@docker ~]# redis-cli
127.0.0.1:6379> set a b
(error) NOAUTH Authentication required.
#1.使用密码进入
[root@docker ~]# redis-cli -a 123
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379>
#2.进入后使用密码
[root@docker ~]# redis-cli
127.0.0.1:6379> AUTH 123
OK
[root@docker ~]# redis-cli
127.0.0.1:6379> set name 一夜暴富
OK
127.0.0.1:6379> get name
"\xe4\xb8\x80\xe5\xa4\x9c\xe6\x9a\xb4\xe5\xaf\x8c" #获取乱码
[root@docker ~]# redis-cli --raw
127.0.0.1:6379> auth 123
OK
127.0.0.1:6379> get name
一夜暴富
#1.添加
127.0.0.1:6379> set name 一夜暴富
OK
#2.获取
127.0.0.1:6379> get name
一夜暴富
#3.修改
127.0.0.1:6379> set name yeyeyeyeye
OK
127.0.0.1:6379> get name
yeyeyeyeye
#4.删除
127.0.0.1:6379> del name
1
127.0.0.1:6379> get name
#5.判断一个key是否存在
127.0.0.1:6379> exists name
0
127.0.0.1:6379> set name lll
OK
127.0.0.1:6379> exists name
1
#6.过期时间
127.0.0.1:6379> TTL name #查看过期时间
-1 #永不过期
127.0.0.1:6379> TTL name
-2 # 已经过期了
127.0.0.1:6379> TTL name
5 # 剩下5秒钟就过期了
#7.设置一个以毫秒为单位的过期时间
127.0.0.1:6379> set name lll px 1000
OK
#8.设置一个以秒为单位的过期时间
127.0.0.1:6379> set name lll ex 10
OK
#9.合并set和ex
127.0.0.1:6379> SETEX name 10 abc #key+秒数+value
#10.合并set和px
127.0.0.1:6379> PSETEX name 10000 dbc #key+秒数+value
#11.判断一个key不存在则创建,存在则忽略
(NX:当key不存在时创建,已存在则忽略)
127.0.0.1:6379> set name lll nx
OK
127.0.0.1:6379> get name
lll
127.0.0.1:6379> set name qqq nx #存在则忽略
127.0.0.1:6379> get name
lll
#12.合并set和nx
127.0.0.1:6379> SETNX name yangge
0
127.0.0.1:6379> get name
yangge
127.0.0.1:6379> SETNX name chenyang
0
127.0.0.1:6379> get name
yangge
#13.判断一个key存在则更新,不存在则忽略
(XX:当key存在则更新,不存在则忽略)
127.0.0.1:6379> get name
lll
127.0.0.1:6379> set name qqq xx
OK
127.0.0.1:6379> get name
qqq
#14.设置多个值
127.0.0.1:6379> MSET b c d e f g
OK
127.0.0.1:6379> KEYS *
f
b
a
d
name
127.0.0.1:6379> get b
c
127.0.0.1:6379> get d
e
127.0.0.1:6379> get f
g
127.0.0.1:6379>
#15.删除多个值
127.0.0.1:6379> KEYS *
1) "a"
2) "name"
3) "d"
127.0.0.1:6379> del a d
(integer) 2
127.0.0.1:6379> KEYS *
1) "name"
#16.GETSET
(相当于get+set:先执行get命令,返回get结果,然后将key更新为新的value,下次再get的时候查到的就是新得value)
127.0.0.1:6379> GETSET name lalala
"qqq"
127.0.0.1:6379> get name
"lalala"
#17.按照下标去更新
127.0.0.1:6379> SETRANGE name 2 ,,,
(integer) 6
127.0.0.1:6379> GET name #在第二位数后添加指定内容
"la,,,a"
#18.获取多个key值
127.0.0.1:6379> MGET get name
1) (nil)
2) "la,,,a"
#19.截取
127.0.0.1:6379> get name #截取name值的2-4位
"la,,,a"
127.0.0.1:6379> getrange name 2 4
",,,"
#20.计数
(Redis当中的计数器是具有原子性的)
127.0.0.1:6379> INCR num # 递增
1
127.0.0.1:6379> DECR num # 递减
0
#21.指定长度递增
127.0.0.1:6379> INCRby num 21
236
#22.指定长度递减
127.0.0.1:6379> decrby num 21
26
#23.追加
127.0.0.1:6379> get name
"la,,,a"
127.0.0.1:6379> append name --
(integer) 8
127.0.0.1:6379> get name
"la,,,a--"
#怎样用一个key存一个人的信息呢?
#1.写入数据
127.0.0.1:6379> hset people name yiyebaofu sex man add tianjin
(integer) 3
#2.获取数据
127.0.0.1:6379> hget people name
"yiyebaofu"
127.0.0.1:6379> hget people add
"tianjin"
#4.修改数据
127.0.0.1:6379> hset people name lalala
(integer) 0
127.0.0.1:6379> hget people name
"lalala"
#5.删除数据
127.0.0.1:6379> hdel people name
(integer) 1
127.0.0.1:6379> hget people name
(nil)
#6.删除所有数据
127.0.0.1:6379> del people
(integer) 1
127.0.0.1:6379> hget people name
(nil)
127.0.0.1:6379> hget people add
(nil)
#7.获取多个值
127.0.0.1:6379> hset peopel name yeyeye sex man add tianjian
(integer) 3
127.0.0.1:6379> hmget peopel name add sex
1) "yeyeye"
2) "tianjian"
3) "man"
#8.获取所有的key和value
127.0.0.1:6379> hgetall peopel
1) "name"
2) "yeyeye"
3) "sex"
4) "man"
5) "add"
6) "tianjian"
#9.获取所有的key
127.0.0.1:6379> hkeys peopel
1) "name"
2) "sex"
3) "add"
#10.获取所有的value
127.0.0.1:6379> hvals peopel
1) "yeyeye"
2) "man"
3) "tianjian"
#11.计数(增加)
127.0.0.1:6379> hincrby peopel id 1
(integer) 1
127.0.0.1:6379> hincrby peopel id 1
(integer) 2
127.0.0.1:6379> hincrby peopel id 1
(integer) 3
127.0.0.1:6379> hget peopel id
"3"
#12.计数(递减)
127.0.0.1:6379> hget peopel id
"3"
127.0.0.1:6379> hincrby peopel id -1
(integer) 2
127.0.0.1:6379> hincrby peopel id -1
(integer) 1
127.0.0.1:6379> hget peopel id
"1"
#13.计数(小数点)
127.0.0.1:6379> HINCRBYFLOAT peopel num 1.1
"1.1"
127.0.0.1:6379> HINCRBYFLOAT peopel num 1.1
"2.2"
127.0.0.1:6379> HINCRBYFLOAT peopel num 1.1
"3.3"
127.0.0.1:6379> HINCRBYFLOAT peopel num 1.1
"4.4"
===========================================
127.0.0.1:6379> HINCRBYFLOAT people num 10.9
134.09
127.0.0.1:6379> HINCRBYFLOAT people num 10.9
144.98999999999999999 # 精度不够
#14.获取长度
127.0.0.1:6379> hlen peopel
(integer) 5
#15.获取某个字段的长度
127.0.0.1:6379> hstrlen peopel num
(integer) 3
#16.设置过期时间
127.0.0.1:6379> expire peopel 111
(integer) 1