博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Redis 面试全攻略 3W字大集合
阅读量:2389 次
发布时间:2019-05-10

本文共 12250 字,大约阅读时间需要 40 分钟。

文章目录

NoSQL数据库简介

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Redis简介安装

redis安装和配置

1.安装

  • 下载安装包

    课前资料提供的安装包,或者:
    建议上传到我们的home下:/usr/local/leyou

  • 解压

tar -xvf redis-4.0.9.tar.gz
  • 编译安装
mv redis-4.0.9 redis cd redis make && make install

2.配置

修改安装目录下的redis.conf文件

vim redis.conf

修改以下配置:

#bind 127.0.0.1 # 将这行代码注释,监听所有的ip地址,外网可以访问protected-mode no # 把yes改成no,允许外网访问daemonize yes # 把no改成yes,后台运行

3.启动或停止

redis提供了服务端命令和客户端命令:

  • redis-server 服务端命令,可以包含以下参数:
    start 启动
    stop 停止
  • redis-cli 客户端控制台,包含参数:
    -h xxx 指定服务端地址,缺省值是127.0.0.1
    -p xxx 指定服务端端口,缺省值是6379

4.设置开机启动

  1. 输入命令,新建文件
vim /etc/init.d/redis

输入下面内容:

#!/bin/sh# chkconfig:   2345 90 10# description:  Redis is a persistent key-value databasePATH=/usr/local/bin:/sbin:/usr/bin:/binREDISPORT=6379EXEC=/usr/local/bin/redis-serverREDIS_CLI=/usr/local/bin/redis-cliPIDFILE=/var/run/redis.pidCONF="/usr/local/leyou/redis/redis.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          if [ "$?"="0" ]           then                echo "Redis is running..."          fi          ;;      stop)          if [ ! -f $PIDFILE ]          then                  echo "$PIDFILE does not exist, process is not running"          else                  PID=$(cat $PIDFILE)                  echo "Stopping ..."                  $REDIS_CLI -p $REDISPORT SHUTDOWN                  while [ -x ${PIDFILE} ]                 do                      echo "Waiting for Redis to shutdown ..."                      sleep 1                  done                  echo "Redis stopped"          fi          ;;     restart|force-reload)          ${0} stop          ${0} start          ;;    *)      echo "Usage: /etc/init.d/redis {start|stop|restart|force-reload}" >&2          exit 1  esac

然后保存退出

注意:以下信息需要根据安装目录进行调整:

EXEC=/usr/local/bin/redis-server # 执行脚本的地址

REDIS_CLI=/usr/local/bin/redis-cli # 客户端执行脚本的地址

PIDFILE=/var/run/redis.pid # 进程id文件地址

CONF="/usr/local/src/redis-3.0.2/redis.conf" #配置文件地址

2)设置权限

chmod 755 /etc/init.d/redis

3)启动测试

/etc/init.d/redis start

启动成功会提示如下信息:

Starting Redis server...Redis is running...

4)设置开机自启动

chkconfig --add /etc/init.d/redischkconfig redis on

Redis的启动

  1. 默认前台方式启动
     直接执行redis-server 即可.启动后不能操作当前命令窗口
  2. 推荐后台方式启动
     拷贝一份redis.conf配置文件到其他目录,例如根目录下的myredis目录 /myredis
     修改redis.conf文件中的一项配置 daemonize 将no 改为yes,代表后台启动
     执行配置文件进行启动 执行 redis-server /myredis/redis.conf

在这里插入图片描述

redis-server /opt/myredis/redis.confredis-cli

Redis的单线程+多路IO复用技术

  1. 多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)。
  2. Memcached 是 多线程 + 锁.
    Redis 是 单线程 + 多路IO复用.

Redis五大数据类型

都只能是字符串

key

keys * 查看当前库的所有键

exists < key> 判断某个键是否存在
type < key> 查看键的类型
del < key> 删除某个键
expire < key> < seconds> 为键值设置过期时间,单位秒
ttl < key> 查看还有多久过期,-1表示永不过期,-2表示已过期
dbsize 查看当前数据库中key的数量
flushdb 清空当前库
Flushall 通杀全部库

String

String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。

String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M

常用操作

get 查询对应键值

set 添加键值对
append 将给定的追加到原值的末尾
strlen 获取值的长度
senx 只有在key 不存在时设置key的值
incr 将key中存储的数字值增1
只能对数字值操作,如果为空,新增值为1
decr 将key中存储的数字值减1
只能对数字之操作,如果为空,新增值为-1
incrby /decrby 步长 将key中存储的数字值增减,自定义步长

incr key 操作的原子性

 所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。

 在单线程中, 能够在单条指令中完成的操作都可以认为是" 原子操作",因为中断只能发生于指令之间。
 在多线程中,不能被其它进程(线程)打断的操作就叫原子操作。
Redis单命令的原子性主要得益于Redis的单线程
 思考:java中i++是否是原子操作

list

它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差

常用操作

lpush/rpush < key> < value1> < value2> 从左边/右边插入一个或多个值。

lpop/rpop < key> 从左边/右边吐出一个值。
值在键在,值光键亡。
rpoplpush < key1> < key2> 从< key1>列表右边吐出一个值,插到< key2>列表左边
lrange < key> < start> < stop> 按照索引下标获得元素(从左到右)
lindex < key> < index> 按照索引下标获得元素(从左到右)
llen < key> 获得列表长度
linsert < key> before < value> < newvalue> 在< value>的后面插入< newvalue> 插入值
lrem < key> < value> 从左边删除n个value(从左到右)

hash

  1. Redis hash 是一个键值对集合
  2. Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
  3. 类似Java里面的Map<String,Object>
  4. 分析一个问题: 现有一个JavaBean对象,在Redis中如何存?
    通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题
    在这里插入图片描述
    hset 给集合中的 键赋值
    hget 从集合 取出 value
    hmset … 批量设置hash的值
    hexists key 查看哈希表 key 中,给定域 field 是否存在。
    hkeys 列出该hash集合的所有field
    hvals 列出该hash集合的所有value
    hincrby 为哈希表 key 中的域 field 的值加上增量 increment
    hsetnx 将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在

set-不是java的set

  1. Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的
  2. Redis的Set是string类型的无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。

常用操作

sadd … 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。

smembers 取出该集合的所有值。
sismember 判断集合是否为含有该值,有返回1,没有返回0
scard 返回该集合的元素个数。
srem … 删除集合中的某个元素。
spop 随机从该集合中吐出一个值。
srandmember 随机从该集合中取出n个值。
不会从集合中删除
sinter 返回两个集合的交集元素。
sunion 返回两个集合的并集元素。
sdiff 返回两个集合的差集元素。

zset(sorted set)

以元素为键(key),以分数为值

  1. Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分(score) ,这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。
  2. 因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。

如何利用zset实现一个文章访问量的排行榜

在这里插入图片描述

Redis相关配置

  1. 计量单位说明,大小写不敏感
  2. include
    类似jsp中的include,多实例的情况可以把公用的配置文件提取出来
  3. ip地址的绑定 bind
     默认情况bind=127.0.0.1只能接受本机的访问请求
     不写的情况下,无限制接受任何ip地址的访问
     生产环境肯定要写你应用服务器的地址
     如果开启了protected-mode,那么在没有设定bind ip且没有设密码的情况下,Redis只允许接受本机的相应
  4. tcp-backlog
     可以理解是一个请求到达后至到接受进程处理前的队列.
     backlog队列总和=未完成三次握手队列 + 已经完成三次握手队列
     高并发环境tcp-backlog 设置值跟超时时限内的Redis吞吐量决定
  5. timeout
    一个空闲的客户端维持多少秒会关闭,0为永不关闭。
  6. tcp keepalive
    对访问客户端的一种心跳检测,每个n秒检测一次,官方推荐设置为60秒
  7. daemonize
    是否为后台进程
  8. pidfile
    存放pid文件的位置,每个实例会产生一个不同的pid文件
  9. log level
    四个级别根据使用阶段来选择,生产环境选择notice 或者warning
  10. log level
    日志文件名称
  11. syslog
    是否将Redis日志输送到linux系统日志服务中
  12. syslog-ident
    日志的标志
  13. syslog-facility
    输出日志的设备
  14. database
    设定库的数量 默认16
  15. security
    在命令行中设置密码
    在这里插入图片描述
  16. maxclient
    最大客户端连接数
  17. maxmemory
    设置Redis可以使用的内存量。一旦到达内存使用上限,Redis将会试图移除内部数据,移除规则可以通过maxmemory-policy来指定。如果Redis无法根据移除规则来移除内存中的数据,或者设置了“不允许移除”,
    那么Redis则会针对那些需要申请内存的指令返回错误信息,比如SET、LPUSH等。
  18. Maxmemory-policy
     volatile-lru:使用LRU算法移除key,只对设置了过期时间的键
     allkeys-lru:使用LRU算法移除key
     volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键
     allkeys-random:移除随机的key
     volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key
     noeviction:不进行移除。针对写操作,只是返回错误信息
  19. Maxmemory-samples
    设置样本数量,LRU算法和最小TTL算法都并非是精确的算法,而是估算值,所以你可以设置样本的大小。
    一般设置3到7的数字,数值越小样本越不准确,但是性能消耗也越小。

Redis的java客户端Jedis.

docker run -p 6379:6379 -v /zzyyuse/myredis/data:/data -v /zzyyuse/myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf  -d redis:3.2 redis-server /usr/local/etc/redis/redis.conf --appendonly yes启动:docker run -p 6379:6379 -d redis:3.2 redis-server docker exec -it  CONTAINER_ID redis-cli
  1. Jedis所需要的jar包 ,可通过Maven的依赖引入
    Commons-pool-1.6.jar
    Jedis-2.1.0.jar
  2. 使用Windows环境下Eclipse连接虚拟机中的Redis注意事项
     禁用Linux的防火墙:Linux(CentOS7)里执行命令 : systemctl stop firewalld.service
     redis.conf中注释掉bind 127.0.0.1 ,然后 protect-mode no。
  3. Jedis测试连通性
public static void main(String[] args) {
//连接本地的 Redis 服务 Jedis jedis = new Jedis("127.0.0.1",6379); //查看服务是否运行,打出pong表示OK System.out.println("connection is OK=======>:"+jedis.ping()); }}
  1. 完成一个手机验证码功能
    要求:
    1、输入手机号,点击发送后随机生成6位数字码,2分钟有效
    2、输入验证码,点击验证,返回成功或失败
    3、每个手机号每天只能输入3次
    jedis.xxx();

Redis事务

不同于关系型数据库

Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
Redis事务的主要作用就是串联多个命令防止别的命令插队

multi开启 、exec执行、discard取消

事务中的错误处理

为什么要做成事务?

  1. 想想一个场景: 有很多人有你的账户,同时去参加双十一抢购
    在这里插入图片描述

秒杀案例

Redis事务的使用

关系型数据库都是悲观锁:加锁,一次事务结束开锁,下一个事务开始加锁

nosql都是乐观锁:比较版本

  • 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以**每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。**传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁

  • 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。

在这里插入图片描述

  1. WATCH xxx 监视事务
秒杀案例

秒杀并发模拟 ab工具

在这里插入图片描述 3) 遗留问题超卖问题

监视.watch(kckey)
transaction=j.multi()
t.exec();

  1. 请求超时问题
  • pool连接池
  1. 遗留问题
  • LUA脚本
    SecKill_redisByScript

Redis持久化

持久化:把数据存到磁盘上

Redis是把数据存在内存中
Redis提供了2个不同形式的持久化方式 RDB 和 AOF

RDB

快照:恢复数据

RDB:Redis 关系数据库存储的是数据
主要是更改配置
在这里插入图片描述
主要保存

rdb保存策略

1)触发机制

手动触发(一般不用)

  • 分别对应save同步命令和bgsave异步命令
    自动触发
    save 时间 次数

触发持久化:1.满足保存策略2.正常shutdown

一定要压缩文件太大
在这里插入图片描述

AOF

AOF:(append only file)存储的是指令

以日志的形式来记录每个写操作

  1. AOF默认不开启,需要手动在配置文件中配置
    在这里插入图片描述
    myRedis/appendonly.aof配置文件

AOF的优缺点

 优点:

备份机制更稳健,丢失数据概率更低。
可读的日志文本,通过操作AOF稳健,可以处理误操作。
 缺点:
比起RDB占用更多的磁盘空间
恢复备份速度要慢
每次读写都同步的话,有一定的性能压力。

RDB和AOF 用哪个好

 官方推荐两个都启用。

 如果对数据不敏感,可以选单独用RDB
 不建议单独用 AOF,因为可能会出现Bug。
 如果只是做纯内存缓存,可以都不用
… …
AOF和RDB同时开启,redis听AOF

Redis主从复制

主从复制,就是主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主。

目的

  1. 读写分离,性能扩展
  2. 容灾快速恢复

在这里插入图片描述

主从配置

  1. 原则: 配从不配主
  2. 步骤: 准备三个Redis实例,一主两从
  • redis6379.conf
    拷贝多个redis.conf文件include
    开启daemonize yes//自动
    Pid文件名字pidfile
    指定端口port
    Log文件名字
    Dump.rdb名字dbfilename
    • redis.conf
      Appendonly 关掉或者换名字

vim 替换:%s/6379/6380

  1. info replication 打印主从复制的相关信息
  2. slaveof 成为某个实例的从服务器
能	切入点问题?slave1、slave2是从头开始复制还是从切入点开始复制?比如从k4进来,那之前的123是否也可以复制只读	从机是否可以写?set可否?原地待命 都down	主机shutdown后情况如何?从机是上位还是原地待命能	主机又回来了后,主机新增记录,从机还能否顺利复制能	其中一台从机down后情况如何?依照原有它能跟上大部队吗?

上面的只是在命令行操作不是永久的,需要在配置文件:slaveof 配置

薪火相传

从二: slaveof ip port从一

在这里插入图片描述
2) 反客为主(小弟上位)
当一个master宕机后,后面的slave可以立刻升为master,其后面的slave不用做任何修改。
slaveof no one 将从机变为主机

  1. 哨兵模式 sentinel (推举大哥)
    反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库.
  • 配置哨兵
     调整为一主二从模式
     自定义的/myredis目录下新建sentinel.conf文件
     在配置文件中填写内容
    sentinel monitor mymaster 127.0.0.1 6379 1
    其中mymaster为监控对象起的服务器名称, 1 为 至少有多少个哨兵同意迁移的
    数量。
     启动哨兵
    执行redis-sentinel /myredis/sentinel.conf
    在这里插入图片描述
    值越小优先级越高

Redis集群

sentinel 哨兵 宿管大妈监视出入人员

阻塞 i/o 非阻塞
给女神发信息后等女神下楼 一直给女神发信息并等下楼

问题

  1. 容量不够,redis如何进行扩容?
  2. 并发写操作, redis如何分摊?

什么是集群

  1. Redis 集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。
  2. Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求
  1. Redis有了解吗
    redis相比memcached有哪些优势?
    redis都支持哪些数据类型?应用场景有哪些?
    redis的配置文件有了解吗?
  2. Redis是单线程的吗?为什么执行速度这么快?
  3. 使用redis可能出现的问题
  4. redis的持久化方式有哪些
  5. redis数据的过期回收策略与内存淘汰机制
  6. redis的主从复制机制
    7.redis对事务支持

整合redis作为缓存

* Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 * 	1、安装redis:使用docker;	docker run -d -p 6379:6379 --name myredis redis * 	2、引入redis的starter * 	3、配置redis spring.redis.host=192.168.100.246 * 	4、测试缓存 * 		原理:CacheManager===Cache 缓存组件来实际给缓存中存取数据 *		1)、引入redis的starter,容器中保存的是 RedisCacheManager; *		2)、RedisCacheManager 帮我们创建 RedisCache 来作为缓存组件;RedisCache通过操作redis缓存数据的 *		3)、默认保存数据 k-v 都是Object;利用序列化保存;如何保存为json *   			1、引入了redis的starter,cacheManager变为 RedisCacheManager; *   			2、默认创建的 RedisCacheManager 操作redis的时候使用的是 RedisTemplate
* 3、RedisTemplate
是 默认使用jdk的序列化机制 * 4)、自定义CacheManager; * 修改

@EnableCaching // 开启缓存

引入redis的starter,配置redis

spring.redis.host=192.168.100.246
org.springframework.boot
spring-boot-starter-redis

创建RedisConfig的配置类

// 1.项目启动时此方法先被注册成bean被spring管理,如果没有这个bean,则redis可视化工具中的中文内容(key或者value)都会以二进制存储,不易检查。     @Bean    public RedisTemplate
empRedisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate
template = new RedisTemplate
(); template.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer
ser = new Jackson2JsonRedisSerializer
(Department.class); template.setDefaultSerializer(ser); return template; } //CacheManagerCustomizers可以来定制缓存的一些规则 @Primary //将某个缓存管理器作为默认的 @Bean public RedisCacheManager employeeCacheManager(RedisTemplate
empRedisTemplate){ RedisCacheManager cacheManager = new RedisCacheManager(empRedisTemplate); //key多了一个前缀 //使用前缀,默认会将CacheName作为key的前缀 cacheManager.setUsePrefix(true); return cacheManager; }

Service中操作缓存

@Qualifier("employeeCacheManager")    @Autowired    RedisCacheManager employeeCacheManager;    //注解方式     @Cacheable(cacheNames = "dept",cacheManager = "employeeCacheManager")    public Department getDeptById(Integer id){
System.out.println("查询部门"+id); return departmentMapper.getDeptById(id); } ------------------------------------------- // 使用缓存管理器得到缓存,进行api调用 public Department getDeptById(Integer id){
System.out.println("查询部门"+id); Department department = departmentMapper.getDeptById(id); //获取某个缓存 Cache dept = employeeCacheManager.getCache("dept"); dept.put("dept:1",department); return department; }

参考

转载地址:http://yvxab.baihongyu.com/

你可能感兴趣的文章
编写不受魔术引号影响的php应用
查看>>
PHP开发安全设置
查看>>
Php Endangers - Remote Code Execution
查看>>
变量的变量,PHP和你
查看>>
PROC系列之四---/proc/loadavg
查看>>
某大型网站的内核TCP/ip优化脚本
查看>>
Defeating SSL using SSLStrip (Marlinspike Blackhat)
查看>>
大型网站数据库架构
查看>>
rdp 安全策略
查看>>
Threat Intelligence Quotient Test
查看>>
Cisco路由器上防止DDOS的一些建议
查看>>
系统安全防护之UNIX下入侵检测方法
查看>>
域控渗透技巧
查看>>
Minion security project and 分布式nmap
查看>>
防火墙相关
查看>>
网络性能测试工具Iperf上手指南
查看>>
opensecuritytraining video
查看>>
collective intelligence framework
查看>>
2015年关注的技术书籍
查看>>
windows 2003 server 记录远程桌面的连接登录日志和修改3389连接端口方法
查看>>