《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!
PONG
127.0.0.1:6379> exit
另一种:
cd /usr/local/redis/bin
./redis-cli -h 192.168.0.100 -p 6379
192.168.0.100:6379> ping
PONG
四、Redis五种常用数据结构
===============
KEY | VALUE |
string | |
list | |
set | |
hash | |
zset |
Redis中的数据,总体上是键值对,不同数据类型指的是键值对中值的类型。
Redis中最基本的类型,它是key对应的一个单一值。二进制安全,不必担心由于编码等问题导致二进制数据变化。所以redis的string可以包含任何数据,比如jpg图片或者序列化的对象。Redis中一个字符串值的最大容量是512M。
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。说明它的底层是基于链表实现的,所以它操作时头尾效率高,中间效率低。
2.set类型
Redis的set是string类型的无序集合。它是基于哈希表实现的。
本身就是一个键值对集合。可以当做Java中的Map<String,Object>对待。
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。
========================================================================
①切换数据库
``` html
Redis默认有16个数据库。
115 # Set the number of databases. The default database is DB 0, you can select
116 # a different one on a per-connection basis using SELECT where
117 # dbid is a number between 0 and ‘databases’-1
118 databases 16
使用select进行切换,数据库索引从0开始
127.0.0.1:6379> select 2
OK
127.0.0.1:6379[2]> select 0
OK
127.0.0.1:6379>
```
②查看数据库长度
``` html
127.0.0.1:6379> dbsize
(integer) 3
```
2.KEY操作
``` html
●KEYS PATTERN
●TYPE KEY
返回KEY对应的值的类型
●MOVE KEY DB
把一组键值对数据移动到另一个数据库中
●DEL KEY [KEY …]
根据KEY进行删除,至少要指定一个KEY
●EXISTS KEY
检查指定的KEY是否存在。指定一个KEY时,存在返回1,不存在返回0。可以指定多个,返回存在的KEY的数量。
●RANDOMKEY
在现有的KEY中随机返回一个
●RENAME KEY NEWKEY
重命名一个KEY,NEWKEY不管是否是已经存在的都会执行,如果NEWKEY已经存在则会被覆盖。
●RENAMENX KEY NEWKEY
只有在NEWKEY不存在时能够执行成功,否则失败
●TIME
返回当前UNIX时间戳
●TTL KEY
以秒为单位查看KEY还能存在多长时间
●PTTL KEY
以毫秒为单位查看KEY还能存在多长时间
●EXPIRE KEY SECONDS
给一个KEY设置在SECONDS秒后过期,过期会被Redis移除。
●EXPIREAT KEY TIMESTAMP
设置一个KEY在TIMESTAMP指定的时间过期
●PEXPIRE KEY MILLISECONDS
以毫秒为单位指定过期时间
●PEXPIREAT KEY MILLISECONDS-TIMESTAMP
以毫秒为单位指定过期的时间戳
●PERSIST KEY
移除过期时间,变成永久key
```
2.string操作
``` html
●SET KEY VALUE [EX SECONDS] [PX MILLISECONDS] [NX|XX]
给KEY设置一个string类型的值。
EX参数用于设置存活的秒数。
PX参数用于设置存活的毫秒数。
NX参数表示当前命令中指定的KEY不存在才行。
XX参数表示当前命令中指定的KEY存在才行。
●GET KEY
根据key得到值,只能用于string类型。
●APPEND KEY VALUE
把指定的value追加到KEY对应的原来的值后面,返回值是追加后字符串长度
●STRLEN KEY
直接返回字符串长度
●INCR KEY
自增1
●DECR KEY
自减1
●INCRBY KEY INCREMENT
原值+INCREMENT
●DECRBY KEY DECREMENT
原值-DECREMENT
●GETRANGE KEY START END
从字符串中取指定的一段
●SETRANGE KEY OFFSET VALUE
从offset开始使用VALUE进行替换
●SETEX KEY SECONDS VALUE
设置KEY,VALUE时指定存在秒数
●SETNX KEY VALUE
新建字符串类型的键值对
●MSET KEY VALUE [KEY VALUE …]
一次性设置一组多个键值对
●MGET KEY [KEY …]
一次性指定多个KEY,返回它们对应的值,没有值的KEY返回值是(nil)
●MSETNX KEY VALUE [KEY VALUE …]
一次性新建多个值
●GETSET KEY VALUE
设置新值,同时能够将旧值返回
```
3.list操作
``` html
●LPUSH key value [value …]
●RPUSH key value [value …]
●LRANGE key start stop
根据list集合的索引打印元素数据
正着数:0,1,2,3,…
倒着数:-1,-2,-3,…
●LLEN key
●LPOP key
从左边弹出一个元素。
弹出=返回+删除。
●RPOP key
从右边弹出一个元素。
●RPOPLPUSH source destination
从source中RPOP一个元素,LPUSH到destination中
●LINDEX key index
根据索引从集合中取值
●LINSERT key BEFORE|AFTER pivot value
在pivot指定的值前面或后面插入value
●LPUSHX key value
只能针对存在的list执行LPUSH
●LREM key count value
根据count指定的数量从key对应的list中删除value
●LSET key index value
把指定索引位置的元素替换为另一个值
●LTRIM key start stop
仅保留指定区间的数据,两边的数据被删除
```
4.set操作
``` html
●SADD key member [member …]
●SMEMBERS key
●SCARD key
返回集合中元素的数量
●SISMEMBER key member
检查当前指定member是否是集合中的元素
●SREM key member [member …]
从集合中删除元素
●SINTER key [key …]
将指定的集合进行“交集”操作
集合A:a,b,c
集合B:b,c,d
交集:b,c
●SINTERSTORE destination key [key …]
取交集后存入destination
●SDIFF key [key …]
将指定的集合执行“差集”操作
集合A:a,b,c
集合B:b,c,d
A对B执行diff:a
相当于:A-交集部分
●SDIFFSTORE destination key [key …]
●SUNION key [key …]
将指定的集合执行“并集”操作
集合A:a,b,c
集合B:b,c,d
并集:a,b,c,d
●SUNIONSTORE destination key [key …]
●SMOVE source destination member
把member从source移动到destination
●SPOP key [count]
从集合中随机弹出count个数量的元素,count不指定就弹出1个
●SRANDMEMBER key [count]
从集合中随机返回count个数量的元素,count不指定就返回1个
●SSCAN key cursor [MATCH pattern] [COUNT count]
基于游标的遍历
```
5.hash操作
``` html
●HSET key field value
●HGETALL key
●HGET key field
●HLEN key
●HKEYS key
●HVALS key
●HEXISTS key field
●HDEL key field [field …]
●HINCRBY key field increment
●HMGET key field [field …]
●HMSET key field value [field value …]
●HSETNX key field value
●HSCAN key cursor [MATCH pattern] [COUNT count]
```
6.zset操作
``` html
●ZADD key [NX|XX] [CH] [INCR] score member [score member …]
●ZRANGE key start stop [WITHSCORES]
●ZCARD key
●ZCOUNT key min max
根据分数在min,max之间查找元素
●ZSCORE key member
●ZINCRBY key increment member
●ZLEXCOUNT key min max
●ZRANGEBYLEX key min max [LIMIT offset count]
按照字母顺序在区间内返回member
min和max使用“[a”表示闭区间,使用“(a”表示开区间
-表示负无穷
+表示正无穷
●ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
在分数的指定区间内返回数据
●ZRANK key member
先对分数进行升序排序,返回member的排名
●ZREM key member [member …]
●ZREMRANGEBYLEX key min max
●ZREMRANGEBYRANK key start stop
●ZREMRANGEBYSCORE key min max
●ZREVRANGE key start stop [WITHSCORES]
●ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
●ZREVRANK key member
●ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]
●ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
把指定集合的member取交集,分数会相加
●ZSCAN key cursor [MATCH pattern] [COUNT count]
```
六、Redis持久化机制
============
Redis工作时数据都存储在内存中,万一服务器断电,则所有数据都会丢失。针对这种情况,Redis采用持久化机制来增强数据安全性。
①机制描述
每隔一定的时间把内存中的数据作为一个快照保存到硬盘上的文件中。Redis默认开启RDB机制。
②触发时机
``` properties
save 900 1
save 300 10
save 60 10000
```
含义
| 配置 | 含义 |
| — | — |
| save 900 1 | 900秒内至少有一次修改则触发保存操作 |
| save 300 10 | 300秒内至少有10次修改则触发保存操作 |
| save 60 10000 | 60秒内至少有1万次修改则触发保存操作 |
save或bgsave
这个命令也会产生dump.rdb文件,但里面是空的,没有意义
如果执行SHUTDOWN命令让Redis正常退出,那么此前Redis就会执行一次持久化保存。
③相关配置
| 配置项 | 取值 | 作用 |
| — | — | — |
| save | “” | 禁用RDB机制 |
| dbfilename | 文件名,例如:dump.rdb | 设置RDB机制下,数据存储文件的文件名 |
| dir | Redis工作目录路径 | 指定存放持久化文件的目录的路径。注意:这里指定的必须是目录不能是文件名 |
④思考
RDB机制能够保证数据的绝对安全吗?
①机制描述
根据配置文件中指定的策略,把生成数据的命令保存到硬盘上的文件中。一个AOF文件的内容可以参照下面的例子:
``` properties
*2
$6
SELECT
$1
0
*3
$3
set
$3
num
$2
10
*2
$4
incr
$3
num
*2
$4
incr
$3
num
*2
$4
incr
$3
num
```
生成上面文件内容的Redis命令是:
``` html
set num 10
incr num
incr num
incr num
```
②AOF基本配置
| 配置项 | 取值 | 作用 |
| — | — | — |
| appendonly | yes | 启用AOF持久化机制 |
| | no | 禁用AOF持久化机制[默认值] |
| appendfilename | “文件名” | AOF持久化文件名 |
| dir | Redis工作目录路径 | 指定存放持久化文件的目录的路径。注意:这里指定的必须是目录不能是文件名 |
| appendfsync | always | 每一次数据修改后都将执行文件写入操作,缓慢但是最安全。 |
| | everysec | 每秒执行一次写入操作。折中。 |
| | no | 由操作系统在适当的时候执行写入操作,最快。 |
③AOF重写
对比下面两组命令:
| AOF重写前 | AOF重写后 |
| — | — |
| set count 1
incr count
incr count
incr count | set count 4 |
两组命令执行后对于count来说最终的值是一致的,但是进行AOF重写后省略了中间过程,可以让AOF文件体积更小。而Redis会根据AOF文件的体积来决定是否进行AOF重写。参考的配置项如下:
| 配置项 | 含义 |
| — | — |
| auto-aof-rewrite-percentage 100 | 文件体积增大100%时执行AOF重写 |
| auto-aof-rewrite-min-size 64mb | 文件体积增长到64mb时执行AOF重写 |
实际工作中不要进行频繁的AOF重写,因为CPU资源和硬盘资源二者之间肯定是CPU资源更加宝贵,所以不应该过多耗费CPU性能去节省硬盘空间。
Redis服务器启动时如果读取了损坏的持久化文件会导致启动失败,此时为了让Redis服务器能够正常启动,需要对损坏的持久化文件进行修复。这里以AOF文件为例介绍修复操作的步骤。
-
第一步:备份要修复的appendonly.aof文件
-
第二步:执行修复程序
/usr/local/redis/bin/redis-check-aof --fix /usr/local/redis/appendonly.aof
- 第三步:重启Redis
注意:所谓修复持久化文件仅仅是把损坏的部分去掉,而没法把受损的数据找回。
①RDB
适合大规模的数据恢复,速度较快
会丢失最后一次快照后的所有修改,不能绝对保证数据的高度一致性和完整性。Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑,但上述成立有条件,Linux也有优化手段
②AOF
选择appendfsync always方式运行时理论上能够做到数据完整一致,但此时性能又不好。文件内容具备一定可读性,能够用来分析Redis工作情况。
持久化相同的数据,文件体积比RDB大,恢复速度比RDB慢。效率在同步写入时低于RDB,不同步写入时与RDB相同。
③RDB和AOF并存
Redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整
RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份)、快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。
④使用建议
如果Redis仅仅作为缓存可以不使用任何持久化方式。
其他应用方式综合考虑性能和完整性、一致性要求。
RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。如果不开启AOF,仅靠Master-Slave Replication 实现高可用性能也不错。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构。
=======================================================================
| 命令名 | 作用 |
| — | — |
| MULTI | 表示开始收集命令,后面所有命令都不是马上执行,而是加入到一个队列中。 |
| EXEC | 执行MULTI后面命令队列中的所有命令。 |
| DISCARD | 放弃执行队列中的命令。 |
| WATCH | “观察“、”监控“一个KEY,在当前队列外的其他命令操作这个KEY时,放弃执行自己队列的命令 |
| UNWATCH | 放弃监控一个KEY |
①加入队列时失败
``` html
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 20
QUEUED
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> incr age www
(error) ERR wrong number of arguments for ‘incr’ command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
```
遇到了入队时即可检测到的错误,整个队列都不会执行。
②执行队列时失败
``` html
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 30
QUEUED
127.0.0.1:6379> incrby age 5
QUEUED
127.0.0.1:6379> incrby age 5
QUEUED
127.0.0.1:6379> incrby age ww
QUEUED
127.0.0.1:6379> incrby age 5
QUEUED
127.0.0.1:6379> EXEC
-
OK
-
(integer) 35
-
(integer) 40
-
(error) ERR value is not an integer or out of range
-
(integer) 45
127.0.0.1:6379> get age
“45”
```
错误在入队时检测不出来,整个队列执行时有错的命令执行失败,但是其他命令并没有回滚。
③Redis为什么不支持回滚
官方解释如下:
如果你有使用关系式数据库的经验, 那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。以下是这种做法的优点: 1.Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。 2.因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。 有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。
在使用WATCH命令监控一个KEY后,当前队列中的命令会由于外部命令的执行而放弃,这是乐观锁的体现。
- 悲观锁
认为当前环境非常容易发生碰撞,所以执行操作前需要把数据锁定,操作完成后释放锁,其他操作才可以继续操作。
- 乐观锁
认为当前环境不容易发生碰撞,所以执行操作前不锁定数据,万一碰撞真的发生了,那么放弃自己的操作。
=========================================================================
1.读写分离的好处:
-
性能优化:主服务器专注于写操作,可以用更适合写入数据的模式工作;同样,从服务器专注于读操作,可以用更适合读取数据的模式工作。
-
强化数据安全,避免单点故障:由于数据同步机制的存在,各个服务器之间数据保持一致,所以其中某个服务器宕机不会导致数据丢失或无法访问。从这个角度说参与主从复制的Redis服务器构成了一个集群。
①思路
Redis集群在运行时使用的是同一个可执行文件,只是对应的配置文件不同。
每个配置文件中相同的参数是:
``` html
dir /usr/local/cluster-redis
```
不同的参数有:
| 配置项名称 | 作用 | 取值 |
| — | — | — |
| port | Redis服务器启动后监听的端口号 | 6000
7000
8000 |
| dbfilename | RDB文件存储位置 | dump6000.rdb
dump7000.rdb
dump8000.rdb |
| logfile | 日志文件位置 | /var/logs/redis6000.log
/var/logs/redis7000.log
/var/logs/redis8000.log |
| pidfile | pid文件位置 | /var/run/redis6000.pid
/var/run/redis7000.pid
/var/run/redis8000.pid |
②步骤
-
第一步:创建/usr/local/cluster-redis目录
-
第二步:把原始未经修改的redis.conf复制到/usr/local/cluster-redis目录
-
第三步:把/usr/local/cluster-redis目录下的redis.conf复制为redis6000.conf
-
第四步:按照既定计划修改redis6000.conf中的相关配置项
-
dir
-
port
-
dbfilename
-
logfile
-
pidfile
-
第五步:复制redis6000.conf为redis7000.conf
-
第六步:修改redis7000.conf中的相关配置项
-
port
-
dbfilename
-
logfile
-
pidfile
-
第七步:复制redis6000.conf为redis8000.conf
-
第八步:修改redis8000.conf中的相关配置项
-
port
-
dbfilename
-
logfile
-
pidfile
③启动Redis主从复制集群
```html
/usr/local/redis/bin/redis-server /usr/local/cluster-redis/redis6000.conf
/usr/local/redis/bin/redis-server /usr/local/cluster-redis/redis7000.conf
/usr/local/redis/bin/redis-server /usr/local/cluster-redis/redis8000.conf
```
使用redis-cli停止指定服务器的命令格式如下:
/usr/local/bin/redis-cli -h IP地址 -p 端口号 shutdown
①查看主从关系
``` html
127.0.0.1:6000> info replication
# Replication
role:master
connected_slaves:0
```
刚刚启动的集群服务器中每一个节点服务器都认为自己是主服务器。需要建立主从关系。
②设定主从关系
在从机上指定主机位置即可
``` html
SLAVEOF 127.0.0.1 6000
```
③取消主从关系
在从机上执行命令
总结:心得体会
既然选择这个行业,选择了做一个程序员,也就明白只有不断学习,积累实战经验才有资格往上走,拿高薪,为自己,为父母,为以后的家能有一定的经济保障。
学习时间都是自己挤出来的,短时间或许很难看到效果,一旦坚持下来了,必然会有所改变。不如好好想想自己为什么想进入这个行业,给自己内心一个答案。
面试大厂,最重要的就是夯实的基础,不然面试官随便一问你就凉了;其次会问一些技术原理,还会看你对知识掌握的广度,最重要的还是你的思路,这是面试官比较看重的。
最后,上面这些大厂面试真题都是非常好的学习资料,通过这些面试真题能够看看自己对技术知识掌握的大概情况,从而能够给自己定一个学习方向。包括上面分享到的学习指南,你都可以从学习指南里理顺学习路线,避免低效学习。
大厂Java架构核心笔记(适合中高级程序员阅读):
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!
③启动Redis主从复制集群
```html
/usr/local/redis/bin/redis-server /usr/local/cluster-redis/redis6000.conf
/usr/local/redis/bin/redis-server /usr/local/cluster-redis/redis7000.conf
/usr/local/redis/bin/redis-server /usr/local/cluster-redis/redis8000.conf
```
使用redis-cli停止指定服务器的命令格式如下:
/usr/local/bin/redis-cli -h IP地址 -p 端口号 shutdown
①查看主从关系
``` html
127.0.0.1:6000> info replication
# Replication
role:master
connected_slaves:0
```
刚刚启动的集群服务器中每一个节点服务器都认为自己是主服务器。需要建立主从关系。
②设定主从关系
在从机上指定主机位置即可
``` html
SLAVEOF 127.0.0.1 6000
```
③取消主从关系
在从机上执行命令
总结:心得体会
既然选择这个行业,选择了做一个程序员,也就明白只有不断学习,积累实战经验才有资格往上走,拿高薪,为自己,为父母,为以后的家能有一定的经济保障。
学习时间都是自己挤出来的,短时间或许很难看到效果,一旦坚持下来了,必然会有所改变。不如好好想想自己为什么想进入这个行业,给自己内心一个答案。
面试大厂,最重要的就是夯实的基础,不然面试官随便一问你就凉了;其次会问一些技术原理,还会看你对知识掌握的广度,最重要的还是你的思路,这是面试官比较看重的。
最后,上面这些大厂面试真题都是非常好的学习资料,通过这些面试真题能够看看自己对技术知识掌握的大概情况,从而能够给自己定一个学习方向。包括上面分享到的学习指南,你都可以从学习指南里理顺学习路线,避免低效学习。
大厂Java架构核心笔记(适合中高级程序员阅读):
[外链图片转存中…(img-g7c0nYXL-1714741725215)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门,即可获取!