浅学一下Redis

NoSQL概述

NoSQL特点

1、方便拓展(数据之间没有关系)

2、大数据量高性能(Redis一秒可以读11万次,写8万次)

3、数据类型多样性(不需要事先设计数据库,随取随用)

NoSQL四大分类

Key:Value

Redis

memecache

文档

MongoDB:MongoDB是关系型数据库和非关系型数据库的中间产品,MongoDB是非关系型数据库中功能最丰富,最像关系型数据库的

ConthDB

列存储数据库

HBase

图关系型数据库

不是存储图片的数据库,存储的是关系

Neo4j,InfoGrid

Redis入门

概述

Remote Dictionary Server远程数据字典

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库缓存消息中间件

Redis的作用

1、内存存储(断电即失),持久化(RDB、AOF)

2、效率高,可用于高缓存

3、发布订阅系统

4、地图信息分析

5、计时器、计数器

特性

1、数据多样性

2、持久化

3、集群

4、事务

Linux安装

官网:http://www.redis.io/

中文网站:http://www.redis.cn/

1、在网站中下载压缩包

2、将压缩包上传至服务器并解压

tar -zxvf xxx

3、省略。。。

使用测试:

redis-cli -p 6379

keys * 查看所有的key

查看Redis的进程是否启动

ps -ef|grep redis

关闭Redis的服务

在Redis中使用shutdown

测试性能

redis-benchmark是一个压力测试工具

redis-benchmark 参数

序号选项描述默认值
1-h指定服务器主机名127.0.0.1
2-p指定服务器端口6379
3-s指定服务器 socket
4-c指定并发连接数50
5-n指定请求数10000
6-d以字节的形式指定 SET/GET 值的数据大小2
7-k1=keep alive 0=reconnect1
8-rSET/GET/INCR 使用随机 key, SADD 使用随机值
9-P通过管道传输 请求1
10-q强制退出 redis。仅显示 query/sec 值
11–csv以 CSV 格式输出
12-l\(L 的小写字母)生成循环,永久执行测试
13-t仅运行以逗号分隔的测试命令列表。
14-I\(i 的大写字母)Idle 模式。仅打开 N 个 idle 连接并等待。

基础知识

Redis有16个数据库,默认使用第0个

select 3 #切换数据库

DBSIZE #查看数据库大小

flushdb #清空当前数据库

flushall #清空所有数据库

Redis为什么是单线程的:Redis的瓶颈不在于CUP,在于内存和网络带宽,既然单线程可以实现,那么就使用单线程,而且单线程可以节省掉切换线程所带来的开销

Redis为什么单线程还这么快:Redis的数据全部放在内存中,单线程的效率是最高的

其他命令

exists key #查看key是否存在

move name 1 #移除1号数据库中key为name的数据

expire name 10 #将name的过期时间设置为10秒

ttl name #查看name剩余的过期时间

setex key 10 value #设置key并且设置过期时间

setnx key value #如果不存在key则设置,如果存在,则不设置

mset k1 v1 k2 v2 #批量设置多个值

mget k1 k2 #批量获取多个值

msetnx #批量如果不存在设置(原子性,要么全部成功,要么全部失败)

五大数据类型

String

append name “hello” #向key为name的值后面追加字符串“hello”

strlen name #显示key为name的值的长度

incr num #自增

decr num #自减

incrby num 10 #增加10

getrange name 0 3 #截取前4个字符

getrange name 0 -1 #获取key为name的全部值

getset key value #先get再set

List

所有List相关的命令都是以L开头的

List底层数据结构为链表

lpush list one two three #将一个或多个值存入链表

​ rpush #从右边开始插入数据

lrange list 0 -1 #获取链接的所有值,倒序排列

lpop list 2#移除左边2个值

rpop #移除右边第一个值

lindex list 0#根据下标获取数据

llen list #获取链表长度

lrem list 2 three #移除list列表中最后两个three

ltrim list 0 2 #保留前三个数据,其他数据删除

rpoplpush oldlist newlist #将oldlist中最右边的数据移到newlist最左边

lset list 0 newitem #将llist中下标为0的数据更新为newitem

linsert list before three six #在list列表中,在three左边插入一个six

​ after # 在右边插入

Set

sadd set set1 set2 set3 set2 set4 #向set中批量添加数据

smembers set #查看set中的全部数据

sismember set set3 #查看set中是否存在set3这个值

scard set #获取set的尺寸

srem set set2 set3 #移除set中set2和set3这两个数据

srandmember set 2 #从set中随机获取2个数据

spop set 2 #随机移除2个数据,默认移除一个

smove set set2 set6 # 将set6这个数据从set集合移动到set2这个集合中

sdiff set1 set2 #查看差集,以set1为核心,查看set1在set2中没有的数据

sinter set1 set2 #查看交集

sunion set1 set2 #查看并集

ZSet

有序集合

zadd set 1 value #添加数据,score为1

zrange 0 -1 #显示所有

ZRANGEBYSCORE salary -inf +inf #排序,从负无穷到正无穷根据score进行排序

​ withscore #显示的结果带上score

zrem salary a #移除zset中的某个值

Hash

key-map

hset map f1 v1 f2 v2 #设置一个hash类型的数据

hget map f1 #取出key为map,filed为f1的值

hgetall map #获取map的所有键值对

hdel map f1 #删除map中key为f1的数据

hlen map #获取map的字段数量

hkeys map #获取所有的key

hvals map #获取所有的value

hincrby、hsetnx

三种特殊数据类型

geospatial

地理位置

底层为zset,可以用一些zset的命令如删除

GEOADD #添加城市信息,一般通过java程序直接导入
GEODIST #获取两点之间的距离

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。

GEOHASH #将经纬度转为字符串输出
GEOPOS #获取指定的城市经纬度信息
GEORADIUS #查找给定经纬度与距离为半经内所有的值,查找附近的人,可以指定数量
GEORADIUSBYMEMBER #类似于georadius,区别于它个命令是由给定的位置而不是给定的经纬度

zrem #删除某个地理位置

hyperloglog

基数统计

使用场景:当一个用户多次访问同一个网站时,只算作一次访问

实现原理:每次用户访问都使用pfadd加入,最后统计的时候只会统计到一次

0.81%的错误率,如果允许容错,可以使用这个方法

redis> PFADD hll1 foo bar zap a #添加数据
(integer) 1
redis> PFADD hll2 a b c foo
(integer) 1
redis> PFMERGE hll3 hll1 hll2 #合并数据
OK
redis> PFCOUNT hll3 #统计数据
(integer) 6

bitmaps

使用场景:统计用户登录状态,是否活跃,打卡等只有两个状态的场景

使用的是位图数据结构,都是使用二进制来存储

setbit bit 0 1 #设置值

getbit bit 0 #获取值

bitcount bit 0 2 #统计,可以指定范围,默认全部

事务

Redis单条命令可以保证原子性,事务不保证原子性

Redis事务没有隔离级别的概念

所有命令在事务中的时候,并没有被执行,只有在事务开始执行的时候才会执行事务中的命令

**Redis事务的本质:**一组命令的集合, 一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行

一次性,顺序性,排他性

Redis事务:开始事务(multi),命令入队(…),执行事务(exec)

discard #取消事务

当执行事务报错场景:

编译型错误(事务中某个命令错误):在执行事务的时候会报错,所有命令都不会执行

运行时异常(给某个不存在的值自增时):错误命令抛出异常,其他命令正常执行


监控 Watch

悲观锁:很悲观,总是考虑最坏的情况,无论什么情况都会加锁

乐观锁:比较乐观,总考虑最好的情况,不会上锁,在更新数据的时候会根据数据的version去判断在此期间是否有人变更过这个数据

Redis的监视测试

#线程一
127.0.0.1:6379> mset money 10
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCR money
QUEUED
127.0.0.1:6379(TX)> INCR money
QUEUED
127.0.0.1:6379(TX)> EXEC
(nil)
127.0.0.1:6379> 
#线程二
127.0.0.1:6379> set money 300
OK

在线程一对money进行监视,开启事务,对money进行操作并不执行,此时线程二对money进行变更,线程一在执行的时候会执行失败

unwatch money #先取消监视,再重新监视,然后开始事务

Jedis

导入Jedis的依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.2.3</version>
</dependency>
// 在代码中使用Jedis,和在命令行中使用一样
// 远程调用Redis的时候需要先开启对应端口,其次要修改配置文件的保护功能
private static final String host = "120.27.129.201";

private static final int port = 6379;

public static void main(String[] args) {
    Jedis jedis = new Jedis(host,port);
    System.out.println(jedis.ping());
    jedis.set("name","ralph");
    System.out.println(jedis.get("name"));
}

整合SpringBoot

在SpringBoot2.X以后,原来使用的Jedis被替换成了lettuce

Jedis和lettuce的区别

**Jedis:**采用的是直连,在多线程调用的情况下不安全,需要使用Jedis pool连接池

**lettuce:**采用的是netty,实例可以在多个线程中共享,不存在线程不安全的情况

整合测试

1、导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、添加配置

spring:
  redis:
    host: 120.27.129.201

3、启动测试

4、编写Utils工具类

配置文件

网络

bind 127.0.0.1 #允许访问的ip
protected-mode yes #受保护的
port 6379 #端口号

通用

daemonize yes #以守护进程的方式运行(后台运行),默认为no
pidfile /var/run/redis_6379.pid #如果以守护进程方式运行,需要指定它的pid文件存储位置
loglevel notice #日志级别
logfile #日志文件
database 16 #数据库数量,默认16
alwayss show-logo yes #是否显示logo

快照

save 900 1 #900秒内如果有一个以上的key进行了修改,则进行持久化
save 300 10 #300秒内有10个以上的key进行了修改,则进行持久化
save 60 10000 #60秒内有10000个以上的key进行了修改,则进行持久化

stop-writes-on-bgsave-error yes #持久化的时候出错是否继续工作
rdbcompression yes #是否压缩rdb文件,需要消耗一些CPU资源
rdbchecksum yes #保存rdb文件的时候是否校验、检查
dir /www/server/redis/ #rdb文件保存目录

复制


安全

Redis默认没有密码,可以设置密码

127.0.0.1:6379> config get requirepass
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass 916828
OK
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "916828"
127.0.0.1:6379> ping
PONG

客户端限制

maxclients 10000 #最大客户端连接数
maxmemory <bytes> #Redis最大内存容量
maxmemory-policy noeviction #内存达到上限后的处理策略(6种拒绝策略)

APPEND ONLY MODE aof配置

appendonly no #默认不开启,使用rdb方式
appendfilename "appendonly.aof" #持久化文件
appendfsync everysec #aof执行策略(三种执行策略)

持久化

Redis默认使用RDB进行持久化操作

RDB

是指redis隔一段时间将内存中的数据集快照写入硬盘

实际操作过程:fork一个子进程,先将数据集写入一个临时文件,替换掉之前的文件,使用二进制进行压缩存储,文件名:dump.rdb

存储过程中子进程与父进程同步进行,子进程负责备份,父进程负责继续服务

RDB优点

  1. 整个redis数据库只会存一份文件,如果系统出现灾难性故障,可以很容易恢复
  2. 性能最大化,持久化的时候,只需要fork一个子进行,可以避免主进程执行IO操作
  3. 相对于AOF,如果数据集很大,RDB启动效率会更高

RDB缺点

  1. 如果在系统定时持久化的中间系统发生的问题,那么从上一将持久化到发生问题之间的数据会丢失
  2. 如果数据集较大,子进程在持久化的时候,可能会导致整个服务器停止服务几百毫秒甚至1秒钟
AOF

当redis执行改变数据的命令时,会将这个命令加到AOF文件中,记录所有操作日志

AOF同步策略:1、每秒同步,即每秒同步一次,不过如果系统在这一秒内发生宕机,那么这一秒的变更会丢失;2、每修改同步,即每次修改都会同步,这样效率会很差;3、不同步,不同步修改数据

AOF优点

  1. AOF数据安全性更高,有三种同步策略
  2. AOF对日志文件的写入采用的是append模式,所以即使在写入过程中发生了宕机,也不会破坏日志文件中已存在的内容
  3. 如果日志文件过大,可以使用rewrite机制,即Redis以append模式不断的将修改数据写入到老的磁盘文件中

AOF缺点

  1. 对于相同的数据集,AOF文件通常要大于RDB文件,RDB在恢复大数据集的效率要比AOF更好
  2. 根据同步策略的不同,AOF的效率要慢于RDB,采用不同步策略的时候,效率和RDB一样

发布订阅

序号命令及描述
1[PSUBSCRIBE pattern pattern …] 订阅一个或多个符合给定模式的频道。
2[PUBSUB subcommand argument [argument …]] 查看订阅与发布系统状态。
3PUBLISH channel message 将信息发送到指定的频道。
4[PUNSUBSCRIBE pattern [pattern …]] 退订所有给定模式的频道。
5[SUBSCRIBE channel channel …] 订阅给定的一个或多个频道的信息。
6[UNSUBSCRIBE channel [channel …]] 指退订给定的频道。
#连接一
SUBSCRIBE ralph #订阅渠道
#实时接收消息
1) "message"
2) "ralph"
3) "hello"

#连接二
PUBLISH ralph hello #在渠道中发送消息

主从复制

主从复制,就是将一个Redis服务器中的数据,复制到其他Redis服务器中,前者称为主节点,后者称为从节点

数据的复制都是单向的,只能由主节点复制到从节点,主节点以写为主,从节点以读为主

默认情况下每个Redis服务器都是主节点,可以配置它的主节点,且一个从节点只能有一个主节点

为什么需要主从同步

在使用redis服务的时候如果时单机服务,一旦单机服务宕机了,那么可能导致我们整个系统处于不可用状态,或者当系统的访问量大了以后单机的redis服务成功了整个系统的瓶颈,这时候就到了主从复制展示伸手的时候了.主从复制可以帮我们完成以下功能.

1.数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

2.故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。

3.负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。

4.高可用基石:主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

一般来说,要将Reids应用在工程项目中,只使用一台服务器是不行的(服务器可能会发生宕机)

  1. 从结构上,单个Redis服务器可能会发生单点故障,并且一台服务器处理所有的请求负载,压力过大
  2. 从容量上,单个Redis服务器的内容容量有限,单台Redis服务器的容量不应该超过20G

一般情况下,读的情况远远大于写的情况,所以可以使用一主三从模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ygU2vtpi-1666075447394)(…/Image/image-20220629191456212.png)]

环境配置

info replication #查看服务器配置信息

role:master #表示这是一个主节点

connected_slaves:0 #表示没有从节点

修改配置文件:

1、端口

2、pid名字

3、log文件名字

4、rdb文件名字

在从机上配置主机(命令或者修改配置文件)使用命令行配置的话,重启会失效

slaveof 127.0.0.1 6379

复制原理

中有主机可以写操作,从机不能写,在主机中写入数据后从机中可以查到

当从机第一次连接到主机时,会发送一个sync命令,主机收到命令后会对从机进行一次全量复制,当从机与主机连接成功后,主机的数据的变更会增量同步到从机称为增量复制

链表模式

链表模式为三个服务器之间依次依赖,呈链表状,如第三个是第二个的从机,第二个是第一个的从机,这样当第一个主机宕机时,可以使用slaveof no one命令来使得第二个服务器变为主机。

当第一个服务器重新启动后,不能重新回到主机的地位,只能加入到第二个服务器下面,成为一个从机

哨兵模式

当主机宕机时,需要手动输入命令去切换主机,需要人工干预,而且可能会导致一段时间服务不可用,Redis从2.8开始提供了sentinel(哨兵)架构来解决这个问题

哨兵模式能够在后台自动监控主机是否出现问题,如果出现了问题,根据投票数自动将从库转为主库

测试

1、配置哨兵配置文件sentinel.conf

# sentinel monitor 被监控的名称 host port 1
# 1代表如果主机挂了,那么进行投票选举新的主机
sentinel monitor myredis 127.0.0.1 6379 1

2、启动哨兵

redis-sentinel sentinel.conf

如果主机宕机了,哨兵会随机(随机算法)在从机中选取一个作为主机,如果原来的主机重启成功,那么会自动成为新主机的从机

缓存穿透、击穿、雪崩

缓存穿透

描述:一个数据请求,缓存与数据库中都不存在该数据,但是依然高频调用,会导致数据库压力增加

解决方案:可将该key的value设置为null,时间设置短一点以免导致正常时间无法使用

缓存击穿

描述:缓存中有数据,请求次数非常多,数据库中有,如缓存到期,此时并发访问会导致数据库压力增加

解决方案:

  1. 加互斥锁
  2. 设置数据不过期
缓存雪崩

描述:缓存数据大量同时到期,同时访问数据库导致数据库大力增加

解决方案:多条数据缓存时间设置不一致,避免多条数据同时到期


👍 欢迎前往博客主页查看更多内容

👍 如果觉得不错,期待您的点赞、收藏、评论、关注

👍 ​ 如有错误欢迎指正!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值