mysql启动命令save_redis的基本命令、持久化和事务

redis是一种非关系型、缓存数据库,相比于Mysql、Oracle等关系型数据库,它主要存储一些频繁访问的热点数据,由于redis将数据存放在内存中,所以它的访问速度非常块。

由操作系统中的局部性原理:当某一条指令被执行后,在短时间内,该指令很有可能再执行;当某一块内存单元被访问,它附近的内存单元很可能被访问。所以在redis中,当用户请求一份数据时,先向业务服务器发送这个请求,该服务器会先请求内存,如果内存中没有想要的数据,服务器会向硬盘中数据库请求数据,将请求到数据向用户返回一份,再写到内存中一份。如果下次再请求这份数据时,直接在内存中取出返回给用户。大大提高访问效率。

1、redis的使用场景

1)取最新的N条数据

比如在个人博客中,最新的N篇文章会放在redis的list中,其他的文章会存放在数据库中。

2)排行榜

比如游戏中的排行榜、微博热搜,在短时间内会频繁变化,如果把得分或者名次存放在硬盘中数据库,存取效率会非常慢。mysql中读8000次/秒、写4000次/秒。redis读写速度平均可达10万次/秒。

3)需要设定精准定过期时间

比如朋友圈动态三天可见、美团券

2、redis客户端与服务器的关系

redis-server来管理内存,redis-cli想要请求数据,先连接redis服务器。把请求的命令交给redis-server,redis-server再去操作内存。例如,当redis-cli想要存key-value时,redis-server会对内存进行malloc操作,由于一次malloc开销比较大,redis-server会malloc一片内存空间。

3、redis常用的数据结构和命令

1)string类型

set命令,设置key对应的值为string类型的value。

get命令,获取对应的value

set name kitty

get name

setnx命令,设置key对应的值为string类型的value。如果value存在,值不变,返回0

127.0.0.1:6379>set name kitty

OK127.0.0.1:6379>get name"kitty"

127.0.0.1:6379>setnx name liming

(integer)0

127.0.0.1:6379>get name"kitty"

setex命令,设置key对应的值为string类型的value,并设置有效期。单位为秒。psetex命令设置有效期单位为毫秒。

例如:微信投票,每个用户四小时内只能投一次,过了这个时间,又可以投票了。

127.0.0.1:6379> SETEX age 10five

OK127.0.0.1:6379>get age"five"

127.0.0.1:6379>get age

(nil)

setrange命令,设置key的value的子字符串

127.0.0.1:6379> set email kitty@123.com

OK127.0.0.1:6379>get email"kitty@123.com"

127.0.0.1:6379> SETRANGE email 6aaa

(integer)13

127.0.0.1:6379>get email"kitty@aaa.com"

mset命令,一次设置多个key-value

27.0.0.1:6379>MSET str1 liming str2 zhangsan

OK127.0.0.1:6379>mget str1 str21) "liming"

2) "zhangsan"

自增命令:INCR key

incrby mykey  increment

incrbyfloat mykey increment

127.0.0.1:6379> set key1 10OK127.0.0.1:6379>get key1"10"

127.0.0.1:6379>incr key1

(integer)11

127.0.0.1:6379> incrby key1 10(integer)21

127.0.0.1:6379> INCRBYFLOAT key1 1.5

"22.5"

自减命令:DECR key

如果value值为整数类型,执行减1操作

append命令,追加字符串,返回字符串长度。如果apped后面的key不存在,就新建一个。

127.0.0.1:6379>get name"kitty"

127.0.0.1:6379>APPEND name mi

(integer)7

127.0.0.1:6379>get name"kittymi"

2)hash

ca137330ca457327340a2f851a9ddb74.png

创建一个hash类型:HSET key field value

127.0.0.1:6379>hset user name zhangsan

(integer)1

127.0.0.1:6379> hset user age 18(integer)1

127.0.0.1:6379>hset user gender male

(integer)1

获取hash类型的值:HGET key field

127.0.0.1:6379>hget user name"zhangsan"

127.0.0.1:6379>hget user age"18"

127.0.0.1:6379>hget user gender"male"

批量添加hash的值:HMSET key field value [field value ...]

127.0.0.1:6379> hmset user name lisi age 20gender male

OK

批量取值:HMGET key field [field ...]

127.0.0.1:6379>hmget user name age gender1) "lisi"

2) "20"

3) "male"

取hash中所有的内容:HGETALL key,如果里面的字段过多,不适合用hgetall把他们全部拿出来,影响效率。

127.0.0.1:6379>hgetall user1) "name"

2) "lisi"

3) "age"

4) "20"

5) "gender"

6) "male"

获取哈希表中字段的数量

127.0.0.1:6379> HLEN 1002(integer)3

获取哈希表中是否存在某个字段

127.0.0.1:6379> HEXISTS 1002name

(integer)1

127.0.0.1:6379> HEXISTS 1002salary

(integer)0

获取哈希表中指定key的字段和字段值

hkeys key   获取字段

hvals key    获取字段值

127.0.0.1:6379> HKEYS 1002

1) "name"

2) "age"

3) "gender"

127.0.0.1:6379> HVALS 1002

1) "liming"

2) "18"

3) "male"

增加某个字段值,hincrby key field increment

127.0.0.1:6379> HINCRBY 1002 age 1(integer)19

hash的使用场景——购物车

用户id就是hash中的key,购物车中的商品名对应hash中的字段,商品数量对应hash中的字段值,通过hset来设置字段值,hincrby来增加字段值。购物车里商品总量可以用hlen实现,删除某个商品相当于删除某个字段,hdel后跟字段名。

3)list

在redis中list类型可以当做栈使用也可以当做队列使用。

从左边向list中添加内容:LPUSHX key value

lpush mykey 1 2 3 4 5 6 7 8

key值: mykey

value值:1 2 3 4 5 6 7 8

在list的头部插入元素

从右边向list中添加内容:RPUSHX key value

在list的尾部插入元素

查看list中的内容:LRANGE key start stop

元素下标从0开始

-1表示列表的最后一个元素

-2表示倒数第二个,以此类推

整个区间:0 -1

从左边取元素:LPOP key

从右边取元素:RPOP key

list的长度: LLEN key

127.0.0.1:6379> LPUSH key 1 2 3(integer)3

127.0.0.1:6379> LRANGE key 0 -1

1) "3"

2) "2"

3) "1"

127.0.0.1:6379> RPUSH key 4 5 6(integer)6

127.0.0.1:6379> LRANGE key 0 -1

1) "3"

2) "2"

3) "1"

4) "4"

5) "5"

6) "6"

127.0.0.1:6379>LPOP key"3"

127.0.0.1:6379>RPOP key"6"

4)set类型

集合类型,集合元素是没有顺序的,但是元素是唯一的

向集合中添加元素:SADD key member [member ...],重复的元素会被过滤

127.0.0.1:6379> sadd set1 2 3 1 2 3(integer)3

列出集合中所有元素:SMEMBERS key

127.0.0.1:6379>SMEMBERS set11) "1"

2) "2"

3) "3"

从集合中删除元素:SREM key member [member ...]

127.0.0.1:6379> srem set1 3(integer)1

127.0.0.1:6379>smembers set11) "1"

2) "2"

集合的差集:SDIFF key [key ...]

127.0.0.1:6379>SMEMBERS set21) "2"

2) "3"

3) "4"

127.0.0.1:6379>SMEMBERS set11) "1"

2) "2"

127.0.0.1:6379> SDIFF set1 set2 //set1-set2,把相同部分减去

1) "1"

集合的交集:SINTER key [key ...]

//set1: 1 2//set2: 2 3 4

127.0.0.1:6379>SINTER set1 set21) "2"

集合的并集: SUNION key [key ...]

127.0.0.1:6379>SUNION set1 set21) "1"

2) "2"

3) "3"

4) "4"

5)SortSet类型,集合中每个元素都有一个分数,Sortedset会根据分数进行排序。

排序集合中添加数据:ZADD key score member,先写分数,然后才是元素的名称,根据分数进行升序排列

127.0.0.1:6379> zadd str 1 a 2 b 3c

(integer)3

查看zset中的元素,默认升序:ZRANGE key start stop [WITHSCORES]

127.0.0.1:6379> ZRANGE str 0 -1

1) "a"

2) "b"

3) "c"

//显示分数

127.0.0.1:6379> ZRANGE str 0 -1withscores1) "a"

2) "1"

3) "b"

4) "2"

5) "c"

6) "3"

//设置降序

127.0.0.1:6379> zrevrange str 0 -1

1) "c"

2) "b"

3) "a"

4、持久化

利用永久性存储介质对数据进行保存,在特定的时间再对数据进行恢复。防止数据丢失。

持久化过程保存什么?

1)快照形式,对当前数据进行保存,关注点在数据结果;RDB

2)日志形式,对操作过程进行保存,关注点在操作数据的过程;

第一个方案:RDB

使用save命令,它的相关配置如下:

dbfilename dump.rdb

#说明:设置本地数据库文件名,默认值为 dump.rdb ,通常设置为dump-端口号.rdbdir#说明:设置存储.rdb文件的路径

rdbcompression yes

#说明:设置存储至本地数据库时是否压缩数据,默认为 yes,采用 LZF 压缩 ,通常默认为开启状态。

实现过程如下:

d48748d254ca9a0e26f21549e3414761.png

如图所示,即使关闭了服务器,当再打开的时候,数据并没有消失,因为数据都保存在了dump.rdb文件中。但是并不建议使用save命令来持久化,因为redis是单线程处理任务,一个一个的命令排着队等待处理,当有一个save命令时,如果save执行时间多长,就会长时间阻塞整个任务队列,影响效率。

bgsave命令是save的改进,save命令是立即执行,而bgsave是D启动后台保存操作,并不是立即执行。

127.0.0.1:6379>set brand huawei

OK127.0.0.1:6379>bgsave

Background saving started

当我们发出bgsave这个指令时,redis会调用fork函数生成一个子进程来创建一个.rdb文件,创建成功后返回消息“backgrand saving sarted”

除了save、bgsave命令还有一种方式——自动执行,满足限定时间范围内key的变化数量达到指定数量即进行持久化,通过修改配置文件达到目的。

save 900 1#900秒之内有1个keys发生变化时,就会执行bgsave

save300 10 #300秒之内有1个keys发生变化时,就会执行bgsave

save配置要根据实际业务情况进行设置,频度过高或过低都会出现性能问题。 save配置启动后执行的是bgsave操作 。

RDB方式的缺点:每次读写都是全部数据,当数据量过大,效率低;

调用fork创建额外的进程,消耗系统资源;

宕机后有可能发生数据丢失

第二个方法:AOF

存储的是命令,目前是Redis持久化的主流方式 。当用户向服务器发送命令时,redis并没有马上记录,而是把命令放在一个临时缓冲区,当有下一个命令发送过来时,还是把命令放在缓冲区。缓冲区里的命令就是生成.aof文件时要用到的原材料。等到一个契机,redis会将命令同步到aof文件中。那么问题来了,一次性写过去多少条?多久写一次?

AOF写数据的三种策略:

always(每次) 每次写入操作均同步到AOF文件中,数据零误差,性能较低 ;

everysec(每秒) 每秒将缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高 ,在系统突然宕机的情况下丢失1秒内的数据 ;

no(系统控制) 由操作系统控制每次同步到AOF文件的周期,整体过程不可控;

修改配置文件,修改完成后,再启动redis,会发现指定目录下有一个appendonly.aof文件。

appendonly yes

#表示是否开启AOF持久化,默认不开启。

appendfilename"appendonly.aof"#设置aof文件的名字

appendfsync everysec

#指定AOF策略,设置对 appendonly.aof 文件进行同步的频率

01fe1a21dae03b18422c24d8eeeddf6f.png

随着写入的命令越多,aof文件的体积也越来越庞大,为此redis引入AOF重写机制。

首先写入以下命令。然后查看aof文件大小

127.0.0.1:6379>set name zhangsan

OK127.0.0.1:6379>set name lisi

OK127.0.0.1:6379>set name kitty

OK

d1d875a636dae8701358e7c6ac0114dc.png

查看aof文件内容

31c6cc298b1363770a25d1c38fc9190a.png

其实只有最后一条命令起作用,但是aof文件把所有的命令都保存了,这就出现了数据冗余,浪费系统资源。AOF重写机制就可以很好避免这个问题,以下是手动重写:

127.0.0.1:6379> BGREWRITEAOF

这时,我再查看aof文件,只剩下最后一条有效的命令。

fb6789c40e23e9093b1b692f1b1c9116.png

RDB与AOF的比较

持久化方式

RDB

AOF

占用空间

存储速度

恢复速度

安全性

会丢失数据

依策略而定

资源消耗

启动优先级

5、事务

redis事务就是一个命令执行的队列,将一系列预定义命令包装成一个整体(一个队列)。当执行时,一次性按照添加顺序依次执行,中间不会被打断或者干扰。

事务的基本操作:multi表示开启事务,后续命令依次加入队列,exec表示执行任务,与multi成对出现。discard表示取消事务。

当服务器在接受到普通命令时,服务器会执行该命令,做出回复。当服务器接收到multi命令时,会创建一个队列,之后再接受到普通命令时,并不是马上执行而是加入队列中,当接收到exec命令时,才依次从队列中取出命令依次执行。当服务接受到discard命令时,会销毁创建好的任务队列。

redis事务不支持回滚,即在队列中执行到错误的指令,会跳过错误指令执行其他指令。

877442052d434c5076bd6b3113a762d2.png

锁——基于特定条件的事务执行

场景:多个客户端有可能同时操作同一组数据,并且该数据一旦被操作修改后,将不适用于继续操作。

解决办法:在操作之前锁定要操作的数据,一旦发生变化,终止当前操作。在redis中,对 key 添加监视锁,在执行exec前如果key发生了变化,终止事务执行。如下图所示,首先使用watch命令对name监控,然后multi创建任务队列,另一个客户端修改了name的值,在原来客户端中再执行exec会不执行。----取消监控unwatch

33d04c167840387a3d483e0d7dfa32fb.png

分布式锁

问题:虽然redis是单线程的,但是多个客户端对同一数据同时进行操作时,如何避免不被同时修改?这里要用到分布式锁。使用"setnx lock-key 1"命令可以给一个key上锁,上锁成功可以拥有控制权,如果此时另一个客户端对此key进行上锁会返回失败,但是如果不去拿锁而是直接操作key也是允许的,因此redis中的分布式锁是一把“建议锁”。操作完成可以通过del命令释放锁。

a04d7a9c6150cd0127a18a07ee6df816.png

补充:可以使用命令“expire lock-key second ”对锁增加时间限制,到时不释放,放弃锁 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值