测试面试之Redis

什么是分布式锁?有什么作用?
分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在单机或者单进程环境下,多线程并发的情况下,使用锁来保证一个代码块在同一时间内只能由一个线程执行。比如 Java 的 Synchronized 关键字和 Reentrantlock 类。
分布式锁的作用是当多个进程不在同一个系统中,用分布式锁可以控制多个进程对资源的访问。
分布式锁可以通过什么来实现?
可以使用 Memcached 实现分布式锁:Memcached 提供了原子性操作命令 add,线程获取到锁。key 已存在的情况下,则 add 失败,获取锁也失败。
也可以使用 Redis 实现分布式锁:Redis 的 setnx 命令为原子性操作命令。只有在 key 不存在的情况下,才能 set 成功。和 Memcached 的 add 方法比较类似。
还可以使用 ZooKeeper 分布式锁:利用 ZooKeeper 的顺序临时节点,来实现分布式锁和等待队列。
还有 Chubby 实现分布式锁:Chubby 底层利用了 Paxos 一致性算法,实现粗粒度分布式锁服务。
介绍一下分布式锁实现需要注意的事项?
分布式锁实现需要保证以下几点:
互斥性:任意时刻,只有一个资源能够获取到锁;
容灾性:在未成功释放锁的的情况下,一定时限内能够恢复锁的正常功能;
统一性:加锁和解锁保证同一资源来进行操作。
如果有大量的 key 需要设置同一时间过期,一般需要注意什么?
如果大量的 key 过期时间设置的过于集中,到过期的那个时间点,redis 可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。
分布式 Redis 是前期做还是后期规模上来了再做好,为什么?
为防止以后扩容增加难度,最好的办法就是一开始就使用分布式。即便只有一台服务器,也可以一开始就让 Redis 以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。
刚开始操作时比较麻烦,但是当数据不断增长,需要更多的 Redis 服务器时,只需要将 Redis 实例从一台服务迁移到另外一台服务器即可,而不用考虑重新分区的问题。一旦添加了另一台服务器,只需要将一半的 Redis 实例从第一台机器迁移到第二台机器。
为什么要做 Redis 分区?
分区可以让 Redis 管理更大的内存,Redis 将可以使用所有机器的内存。如果没有分区,你最多只能使用一台机器的内存。
分区使 Redis 的计算能力通过简单地增加计算机得到成倍提升,Redis 的网络带宽也会随着计算机和网卡的增加而成倍增长。
什么是数据库缓存双写一致性?
当一个数据需要更新时,因为不可能做到同时更新数据库和缓存,那么此时读取数据的时候就一定会发生数据不一致问题,而数据不一致问题在金融交易领域的系统中是肯定不允许的。
解决办法:读的时候先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。更新的时候,先更新数据库,然后再删除缓存
怎么去发现 Redis 阻塞异常情况?
可以从以下两方面准备:

  1. 使用 Redis 自身监控系统
    使用 Redis 自身监控系统,可以对 CPU、内存、磁盘、命令耗时等阻塞问题进行监控,当监控系统发现各个监控指标存在异常的时候,发送报警。
  2. 使用应用服务监控
    当 Redis 存在阻塞时,应用响应时间就会延长,应用可以感知发现问题,并发送报警给管理人员。
    如何处理 Redis 集群中 big key 和 hot key?
    对于 big key 先分析业务存在大键值是否合理,如果不合理我们可以把它们拆分为多个小的存储。或者看是否可以使用别的存储介质存储这种 big key 解决占用内存空间大的问题。
    对于 hot key 我们可以在其他机器上复制这个 key 的备份,让请求进来的时候,去随机的到各台机器上访问缓存。所以剩下的问题就是如何做到让请求平均的分布到各台机器上。
    请介绍几个可能导致 Redis 阻塞的原因?
    Redis 产生阻塞的原因主要有内部和外部两个原因导致:
    内部原因:
    如果 Redis 主机的 CPU 负载过高,也会导致系统崩溃;
    数据持久化占用资源过多;
    对 Redis 的 API 或指令使用不合理,导致 Redis 出现问题。
    外部原因:
    外部原因主要是服务器的原因,例如服务器的 CPU 线程在切换过程中竞争过大,内存出现问题、网络问题等。
    Redis 哨兵和集群的区别是什么?
    Redis 的哨兵作用是管理多个 Redis 服务器,提供了监控、提醒以及自动的故障转移的功能。哨兵可以保证当主服务器挂了后,可以从从服务器选择一台当主服务器,把别的从服务器转移到读新的主机。Redis 哨兵的主要功能有:
    集群监控:对 Redis 集群的主从进程进行监控,判断是否正常工作。
    消息通知:如果存在 Redis 实例有故障,那么哨兵可以发送报警消息通知管理员。
    故障转移:如果主机(master)节点挂了,那么可以自动转移到从(slave)节点上。
    配置中心:当存在故障时,对故障进行转移后,配置中心会通知客户端新的主机(master)地址。
    Redis 的集群的功能是为了解决单机 Redis 容量有限的问题,将数据按一定的规则分配到多台机器,对内存的每秒访问不受限于单台服务器,可受益于分布式集群高扩展性。
    MySQL 里有 2000w 数据,Redis 中只存 20w 的数据,如何保证 Redis 中的数据都是热点数据?
    因为内存的空间是有限的,所以 Redis 淘汰机制主要为了解决在某个时间点,Redis 中存在很多过期键,定期删除策略随机抽查时没有抽查到,并且也没有走惰性删除策略时,大量过期键占用内存的问题。如果内存只能存 20w 数据,而我们需要存储 2000w 的数据时,自然就需要对多出来的数据进行删除或覆盖,保证内存中存储的数据都是热数据。所以当 Redis 内存数据集的大小上升到一定数量时,就会执行数据淘汰策略。
    Redis 常见的性能问题和解决方案?
    master 最好不要做持久化工作,如RDB内存快照和AOF日志文件;
    如果数据比较重要,某个slave 开启AOF 备份数据。策略设置为每秒同步一次;
    为了主从复制的速度和连接的稳定性,Master和Slave 最好在同一局域网内;
    尽量避免在压力很大的主库上增加从库;
    主从结构不要用图状结构,用单向链表更为稳定,即:MAster<-Slave1<-Slave2<-Slave3;这样做的结构方便解决单点故障问题。实现Slave 对 Master 的替换,如果Master 挂了,可以立即启用Slave1 做master,,其他不变;
    Redis 的持久化方式RDB和AOF的区别?
    使用Redis 做缓存,方便多个业务进程之间共享数据,由于Redis 的数据都存在内存中,如果没有配置持久化,Redis 重启后数据就丢失了,于是需要开启redis 的持久化功能,将数据保存到磁盘上,当redis 重启后,可以从磁盘中回复数据。redis 提供的两种方式进行持久化,一种是RDB(Redis DataBase)持久化(原理是将数Redis在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(Apend Only File)持久化(原理是将Redis的操作日志以追加的方式写入文件)。
    二者的区别
    RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程就是有一个fork子进程,先将数据集写入到临时文件中,写入成功后,再替换之前的文件,用二进制压缩存储。
    AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
    二者优缺点
    RDB的优缺点:
    优点:RDB持久化文件,速度比较快,而且存储的是一个二进制文件,传输起来很方便。
    缺点:RDB无法保证数据的绝对安全,有时候就是1s也会有很大的数据丢失。
    AOF的优缺点:
    优点:AOF相对RDB更加安全,一般不会有数据的丢失或者很少,官方推荐同时开启AOF和RDB。
    缺点:AOF持久化的速度,相对于RDB较慢,存储的是一个文本文件,到了后期文件会比较大,传输困难。
    Redis的内存消耗有那些?内存统计使用什么命令?
    对象内存:该内存占用最大,存储用户的所有数据,包括key 的大小和value的大小;
    缓冲内存:主要有客户端缓存,复制积压缓存,AOF 缓存;
    内存碎片:对key 数据更新,数据过期等都可能产生生存碎片;
    Redis 的通信实质?
    Redis 使用的是客户端-服务器(CS)模型和请求/响应协议的TCP 服务器;
    Redis 客户端与Redis 服务器之间使用的是TCP协议进行连接;当一个客户端通过一个socket 连接发起多个请求命令时,每个请求命令发出后client 通常会阻塞并等待redis 服务器处理,当redis 服务器处理完请求命令后将通过响应报文返回给client,所以当执行多条命令的时候都需要等待上一条命令执行完才能执行下一条命令;
    什么是一条redis 命令执行完毕?
    client 发送命令–> 命令排队 -->服务端命令执行 --> 返回结果;
    pipeline 的通信实质?
    管道(pepeline) 可以一次性发送多条命令并执行完后一次性将结果返回给客户端;
    pipeline 的优点?
    piepline 通过减少客户端与redis 通信次数来实现降低往返延时时间;
    pipeline 实现的原理是队列,而队列的原理是先进先出,这样可以保证数据的顺序性;
    请说明Redis 的批量命令与pipeline 有什么不同?
    原子性不同:批量命令操作需要保证原子性的,Pipeline 执行的是非原子性的;
    支持的命令不同:批量命令操作的是一个命令对应多个key,Pipeline 支持多个命令的执行;
    实现方式不同:批量命令由Redis 服务端实现,而Piepline 是需要服务端和客户端共同实现的。
    请介绍一下Redis 的 Pipeline(管道),以及使用场景?
    因为Redis 是基于 TCP 协议的请求/响应服务器,每次通信都需要经过TCP 协议的三次握手,所以当需要执行的命令足够大时,会产生很大的网络延迟。并且网络的传输时间成本和服务器开销没有计入其中,总的延迟可能更大。Pipeline 主要就是为了解决这种情况的场景,对此存在类似的场景可以考虑使用Pipeline.
    适用场景:如果存在批量数据需要写入Redis,并且这些数据允许一定比例的写入失败。那么可以使用Pipeline,后期再对失败的数据进行补偿即可;
    介绍一下Redis 常用的安全设置?
    1.端口设置
    只允许信任的客户端发过来的请求,对其他所有请求都拒绝。如果存在暴露在外网的服务。那么需要使用防火墙阻止外部访问Redis端口。
    2.身份验证:
    使用Redis 提供的身份验证功能,在redis.conf 文件中配置生效,客户端可以发送(AUTH 密码)命令进行身份验证。
    3.禁用特定的命令集:
    可以考虑禁止一些容易产生安全问题的命令,预防被人恶意操作;
    Redis 中管道有什么用?
    使用pipeline(管道)的好处在于可以多次I/O 往返的时间缩短为一次,但是要求管道中执行的指令间没有因果关系;
    Redis 的通信协议是什么?有什么特点?
    Redis 客户端和 Redis 服务器通信使用的是RESP(Redis 序列化协议) 通信协议,该协议是专门为Redis 设计的,但是也可以用于其他客户端和服务器软件项目中。
    RESP 的特点为实现简单,快速解析,可读性好;
    怎么测试Redis 的连通性?
    通过命令 ping 执行后,会得到结果 pong.如果没有得到 pong 的结果说明Redis 法没有正常连通;
    Redis 为什么设计成单线程的?
    多线程处理会设计到锁,并且多线程处理会涉及到线程切换而消耗CPU,采用单线程避免了不必要的上下文切换和竞争条件。其次是CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存或者网络宽带;
    Redis 如何设置密码及验证密码?
    Redis 密码设置有两种方式:
    修改配置文件,需要启动Redis.在Redis.conf 中找到 requirepass 参数,设置Redis 的访问密码。配置方法为 requirepass 访问密码;
    使用命令设置,不需要重启Redis,使用命令设置的方法为:config set requireopass 访问密码。如果需要查询密码,可以使用 config get requirepass 命令。如果需要验证密码。可以使用auth 访问密码,再执行config get requirepass 获取。通过这种方式设置的访问密码,如果redis.conf 配置文件中没有对应的访问密码,那么服务器重启后访问密码会失效;
    什么事Redis事务?具体原理是什么?
    Redis 事务是一组命令的集合,是Redis 的最小执行单位。它可以保证一次执行多个命令,每个事务是一个单独操作隔离,事务中的所有命令都会序列化,按顺序的执行。服务端在执行事务的过程中,不会被其他客户端发来的命令请求打断。它的原理是将一个事务的命令发送给Redis,然后依次执行这些命令;
    Redis 事务的注意点有哪些?
    Redis 事务是不支持回滚的,不像MYSQL 的事务一样,要么都执行,要么都不执行;
    Redis 服务端在执行事务的过程中。不会被其他客户端发来的命令请求打断。直到事务命令全部执行完毕才会执行其他客户端的命令;
    Redis 为什么不支持回滚?
    Redis 的事务不支持回滚,但执行的命令有语法错误,Redis 会执行失败,这些问题可以从程序层面捕获并解决。但是如果出现其他问题,则依然会执行余下的命令。这样做的原因是因为回滚需要增加很多工作,而不支持回滚则可以保持简单快速的特性;
    Redis 适合引用到那些场景?
    1.会话缓存:会话(Session) 是存储在服务端的,但是可以设置存储的时候不以文件的方式存储,而是存到Redis 中,而且Redis 支持数据持久化,不会担心数据因为服务器重启导致Session 数据丢失的问题。这样做的好处不只是提高获取会话的速度,也对网站的整体性能有很大的提升;
    2.数据缓存:Redis 支持多种数据结构,经常用来做缓存中间件使用,缓存的数据不只包括数据库中的数据,也可以缓存一些临时需要存储的数据,eg:token,会话数据等;
    3.队列:Redis支持列表(lists)功能的,可以简单实现一个队列的功能,对数据进行入队,出对操作。实现的队列可以应用到电商的秒杀场景中;
    4.排行榜,计数器:Redis 提供了有序集合,可以对数据进行排名,实现排行榜功能。其次Redis 中提供了 incr 对数字加1命令,也提供了decr 对数字减1 的命令。所以可以实现一个简单的技术器功能;
    5.发布,订阅功能:Redis 中提供了发布订阅的相关命令。可以用来做一些跟发布订阅相关的场景应用等。例如简单的消息队列功能;
    Redis 的同步机制是什么?
    Redis 支持主从同步,从从同步。如果是第一次进行进行主从同步,主节点需要bgsave命令,再将后续修改操作记录到内存缓冲区,等RDB(Redis 内存中存储的全部数据,二进制表示)文件全部同步到复制节点,复制节点接受完成后将RDB镜像记录到内存中。等加载完成,复制节点通知主节点将复制期间修改的操作记录同步到复制节点,即可完成同步过程;
    为什么Redis 需要将所有的数据放到内存中?
    Redis 将数据放在内存中的好处,就是可以实现最快的数据读取,如果数据存在硬盘中,磁盘I/O会严重影响Redis 的性能。而且Redis 还提供了数据持久化功能,不用担心服务器重启对内存中数据的影响。
    Redis 是单进程单线程的吗?
    Redis 是单进程单线程的,它可以通过队列技术将并发访问变成串行访问,避免了传统数据库串行控制的开销;
    什么是Redis?
    Redis是一个key-value 存储系统,跨平台的非关系型数据库,开源,C 语言编写,支持网络;可基于内存,分布式,可选持久性的键值对(key-valuue)存储数据库,并提供多种语言的API;
    Redis特点优势?
    Redis 支持数据持久化,可以将内存中的数据保存到磁盘中,重启的时候可以再次加载使用;
    Redis 支持数据备份,即master-slave模式的数据备份;
    性能极高:Redis 能读的速度是110000次/s,写的速度8122 次/s;
    丰富的数据类型:Sring 字符串;Hash 散列;List 列表;Set 集合;Sorted Set 有序集合;
    原子:Redis 中所有的操作都是原子的,要么执行成功,要么不执行,单个操作是原子性的。多个操作也支持事务,即原子性;
    Redis 还支持publish、subscribe 通知,key 过期等特性;
    缓存雪崩、缓存穿透、缓存击穿?
    缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
    解决方案:
    1…缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生;
    2. 给每一个缓存数据增加相应的缓存标记,记录缓存是否失效,如果缓存标记失效,则更新数
    据缓存。
    3.缓存预热:在启动系统之前写一个接口,把数据先刷到缓存中;
    4.互斥锁:加一个互斥锁,在缓存查数据库的时候让其他请求排队,查到数据之后再释放锁;
    缓存穿透是指缓存和数据库中都没有数据,导致所有请求都落在数据库上,造成数据库短时间内承受大量的请求而崩掉.(情况较少,一般来自于攻击)
    解决方案:
    1.接口层加参数校验,判断如果数据不可能存在,直接拦截不让访问数据库;
    2.缓存取不到数据,数据库也没有,则将key-value 设置为key-null,缓存有效时间设置短一点,防止用户反复用一个ID暴力攻击;
    3.采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力
    缓存击穿是指缓存中没有,但数据库中存在数据,(一般是缓存时间到期),这时由于并发量特别多,同时读缓存没有读到数据,又去数据库取数据,引起数据库压力瞬间增大,造成过大压力,和缓存雪
    崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
    解决方案:
    1.设置热点数据永远不过期。
    2.加互斥锁
    Redis 常用命令?
    cmd访问redis redis-cli.exe -h 127.0.0.1 -p 6379
    key
    keys * 获取所有的key
    Redis 模糊搜索
    keys keyword 模糊匹配
    keys *   匹配数据库中所有 key
    keys h?llo   匹配 hello , hallo 和 hxllo 等。
    keys h*llo   匹配 hllo 和 heeello 等。
    keys h[ae]llo   匹配 hallo 和 hello ,但不匹配 hillo;特殊符号用 \ 隔开。
    select 0 选择第一个库
    move myString 1 将当前的数据库key移动到某个数据库,目标库有,则不能移动
    flushall 清除Redis数据库中所有数据
    randomkey 随机获取key
    type key 获取类型
    set key1 value1 设置key,添加数据
    get key1 获取key
    mset key1 value1 key2 value2 key3 value3 批量添加数据
    mget key1 key2 key3 批量获取数据
    del key1 删除key
    exists key 判断是否存在key 1表示存在 0 表示不存在
    expire key 10 设置过期10 秒
    pexpire key 1000毫秒 他们的区别是设置时间单位不同 s/ms
    persist key 删除过期时间
    string
    getrange key 2 4 字符串分段下标2-4 的字符串,下标从0 开始
    getset name new_cxx 设置值新值,返回旧值
    setnx key value 不存在就插入(not exists)
    setex key time value 过期时间(expire)
    setrange key index value 从index开始替换value
    incr age 递增 如果value 为integer 类型,则递增
    incrby age 10 递增 递增自定义
    decr age 递减
    decrby age 10 递减
    incrbyfloat 增减浮点数
    append 追加
    strlen 长度
    getbit/setbit/bitcount/bitop 位操作

hash
hset myhash name cxx
hget myhash name
hmset myhash name cxx age 25 note “i am notes”
hmget myhash name age note
hgetall myhash 获取所有的
hexists myhash name 是否存在
hsetnx myhash score 100 设置不存在的
hincrby myhash id 1 递增
hdel myhash name 删除
hkeys myhash 只取key
hvals myhash 只取value
hlen myhash 长度

list
lpush mylist a b c 左插入
rpush mylist x y z 右插入
lrange mylist 0 -1 数据集合
lpop mylist 弹出元素
rpop mylist 弹出元素
llen mylist 长度
lrem mylist count value 删除
lindex mylist 2 指定索引的值
lset mylist 2 n 索引设值
ltrim mylist 0 4 删除key
linsert mylist before a 插入
linsert mylist after a 插入
rpoplpush list list2 转移列表的数据

set
sadd myset redis
smembers myset 数据集合
srem myset set1 删除
sismember myset set1 判断元素是否在集合中
scard key_name 个数
sdiff | sinter | sunion 操作:集合间运算:差集 | 交集 | 并集
srandmember 随机获取集合中的元素
spop 从集合中弹出一个元素

zset
zadd zset 1 one
zadd zset 2 two
zadd zset 3 three
zincrby zset 1 one 增长分数
zscore zset two 获取分数
zrange zset 0 -1 withscores 范围值
zrangebyscore zset 10 25 withscores 指定范围的值
zrangebyscore zset 10 25 withscores limit 1 2 分页
Zrevrangebyscore zset 10 25 withscores 指定范围的值
zcard zset 元素数量
Zcount zset 获得指定分数范围内的元素个数
Zrem zset one two 删除一个或多个元素
Zremrangebyrank zset 0 1 按照排名范围删除元素
Zremrangebyscore zset 0 1 按照分数范围删除元素
Zrank zset 0 -1 分数最小的元素排名为0
Zrevrank zset 0 -1 分数最大的元素排名为0
Zinterstore
zunionstore rank:last_week 7 rank:20150323 rank:20150324 rank:20150325 weights 1 1 1 1 1 1 1
排序:
sort mylist 排序
sort mylist alpha desc limit 0 2 字母排序
sort list by it:* desc by命令
sort list by it:* desc get it:* get参数
sort list by it:* desc get it:* store sorc:result sort命令之store参数:表示把sort查询的结果集保存起来
订阅与发布:
订阅频道:subscribe chat1
发布消息:publish chat1 “hell0 ni hao”
查看频道:pubsub channels
查看某个频道的订阅者数量: pubsub numsub chat1
退订指定频道: unsubscrible chat1 , punsubscribe java.*
订阅一组频道: psubscribe java.*
redis事物:
隔离性,原子性,
步骤: 开始事务,执行命令,提交事务
multi //开启事务
sadd myset a b c
sadd myset e f g
lpush mylist aa bb cc
lpush mylist dd ff gg
服务器管理
dump.rdb
appendonly.aof
//BgRewriteAof 异步执行一个aop(appendOnly file)文件重写
会创建当前一个AOF文件体积的优化版本

//BgSave 后台异步保存数据到磁盘,会在当前目录下创建文件dump.rdb
//save同步保存数据到磁盘,会阻塞主进程,别的客户端无法连接

//client kill 关闭客户端连接
//client list 列出所有的客户端

//给客户端设置一个名称
  client setname myclient1
  client getname
  
 config get port
 //configRewrite 对redis的配置文件进行改写

rdb
save 900 1
save 300 10
save 60 10000
aop备份处理
appendonly yes 开启持久化
appendfsync everysec 每秒备份一次
命令:
bgsave异步保存数据到磁盘(快照保存)
lastsave返回上次成功保存到磁盘的unix的时间戳
shutdown同步保存到服务器并关闭redis服务器
bgrewriteaof文件压缩处理(命令)

你可能感兴趣的:(redis,面试,java)