redis

  • window安装:

https://github.com/MSOpenTech/redis/releases
打开cmd,运行redis,命令:

redis-server.exe redis.windows.conf

另打开cmd,连接redis,命令:

redis-cli.exe -h 127.0.0.1 -p 6379
  • linux下安装:

http://redis.io/download

$ wget http://download.redis.io/releases/redis-5.0.7.tar.gz
$ tar xzf redis-5.0.7.tar.gz
$ cd redis-2.8.17
$ make

启动服务:

$ cd src
$ ./redis-server

测试客户端程序redis-cli与redis服务交互

$ cd src
$ ./redis-cli
redis>set test a
ok
redis>get test
"a"


1、redis支持的数据类型

  • String(字符串),格式:set key value ,get key,一个键最大能储存512M
  • Hash(哈希),格式:hmset name key1 value1 key2 value2,hgetall name, hget name key1 ,del object                                  适合储存对象(相当于Map集合,存储键值对)
  • List(列表:双向链表,按照插入顺序排序,元素重复)

        格式:lpush name value(在key对应头部添加字符串元素)
        rpush name value(在key对应的尾部添加字符串元素), 
        lrem name index(删除索引对应的值),llen name(key对应list的长度)
        lrange name 0 2(根据索引查询list下的元素)

  • set(通过哈希表实现,元素不重复,无序集合),格式:sadd name value ,smembers name(查询集合下的元素)
  • zset(通过哈希表实现,元素不重复,有序集合),格式:zadd zset 0 a,zadd zset 1 b,zrangebyscore zset 0 2

用SELECT命令更换数据库:

redis> SELECT 1
redis [1] >
exists key (检查key是否存在)
del key (删除key)
GETSET key value(将给定 key 的值设为 value ,并返回 key 的旧值(old value)

2、redis事务

先以multi开启事务,输入多个命令进入事务,最后由exec触发事务事务可以理解为一个批量的打包执行脚本,但批量执行不是原子化操作,中间某条指令的失败不会导致前面的回滚后面的没办法操作
单个redis命令是原子性的,事务并非是原子性的

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set String a
QUEUED
127.0.0.1:6379> get String
QUEUED
127.0.0.1:6379> exec
1) OK
2) "a"
127.0.0.1:6379>

3、客户端如何通过密码验证连接到 redis 服务,并检测服务是否在运行

redis 127.0.0.1:6379> AUTH "password"
OK
redis 127.0.0.1:6379> PING
PONG

4、什么是redis的持久化

持久化就是把内存的数据写到磁盘中,防止服务宕机内存数据丢失

5、使用redis好处

  • 速度快:数据存在内存中,类似于hashMap,优势查询与操作的时间复杂度都是O(1),每秒可以处理超过十万次的读写操作
  • 支持丰富的数据类型:string,hash,list,set,zset
  • 单个value最大是1G,cache最大是1M
  • 支持事务:操作不是原子性的,即使某些操作错误,也不会影响其他操作的执行
  • 丰富的特性:可用于缓存,按key设置过期时间,过期后将自动删除

6、数据结构的使用场景

  • string:计数功能的缓存(微博数,粉丝数)
  • hash:储存用户信息,商品信息,单点登录用hash储存用户信息,以cookieId作为key,设置30分钟为缓存的过期时间,很好的模拟像session的效果
  • list:可以做简单的消息队列,可以利用lrange命令,做基于redis的分页功能
  • set:利用交集,差集,补集可以计算共同喜好,全部喜好,独有的喜好
  • Sorted set:排行榜应用,取top

7、redis主从复制,哨兵,集群三个的区别

  • 主从复制:读写分离,备份,一个master可以有多个slaves
  • 哨兵:监控,自动转移,哨兵发现主服务器挂了,会从slaves中从新选举新的服务器
  • 集群:为了解决单机redis容量有限的问题

redis哨兵的主要功能:

  1. 集群监控:负责监控redis的master与slave进程是否正常(每隔1s每个哨兵会向集群集群(主服务器+从服务器+其他哨兵服务器)进程发送一次ping命令做一次心跳检测)
  2. 消息通知:如果那个redis实例出现故障,会通知消息给管理员(作为警报)
  3. 故障转移:如果master node挂了,会转移到slave节点上
  4. 配置中心: 如果故障发生转移了,通知client客户端新的master地址

8、redis的架构模式,特点

  • 单机版:特点(简单),问题(内存容量有限、处理能力有限、无法高可用)
  • 主从复制:特点(master/slave数据相同、降低了master读的能力),问题(无法保证高可用、没有解决master写的压力)
  • 哨兵:redis sentinel是分布式系统中监控主从服务器,并在主服务器下线自动进行故障转移,3个特性

监控:sentinel会不断的主从服务器运行是否正常
提醒:当sentinel监控到redis服务器有问题时,会通过api向管理员或其他程序发送通知
自动故障迁移:当一个主服务器不能正常工作时,sentinel会进行自动故障迁移的操作
特点(保证高可用、监控各个节点、自动故障迁移),缺点(主从切换需要时间会丢数据、没有解决master写的压力)

  • 集群(proxy)

Twemproxy 是一个 Twitter 开源的一个 redis 和 memcache 快速/轻量级代理服务器,Twemproxy 是一个快速的单线程代理程序,支持 Memcached ASCII 协议和 redis 协议
特点:

  1. 多种 hash 算法:MD5、CRC16、CRC32、CRC32a、hsieh、murmur、Jenkins 
  2. 支持失败节点自动删除
  3. 后端 Sharding 分片逻辑对业务透明,业务方的读写方式和操作单个 Redis 一致

缺点:增加了新的 proxy,需要维护其高可用 ,failover 逻辑需要自己实现,其本身不能支持故障的自动转移可扩展性差,进行扩缩容都需要手动干预

 9、redis分布式锁实现

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放
如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?
set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!

分布式锁的实现方式:
    1.数据库的乐观锁 2.基于redis的分布式锁 3.基于zookeeper的分布式锁
确保分布式锁可用,要满足4个条件:
    1.互斥锁,在任何条件下,只有一个客户端持有锁(加锁会判断key是否存在)
    2.不会发生死锁,即使一个客户端在持有锁期间崩溃而没有主动解锁,也能保证其他客户端加锁(加锁设置过期时间)
    3.具有容错性,只要大部分redis节点可以正常运行,客户端就可以正常加锁解锁
    4.解铃还须系铃人,加锁解锁必须是同一个客户端,客户端自己不能解其他客户端加的锁(requestId唯一标识)
    
加锁:

jedis.set(String key, String value, String nxxx, String expx, int time);

  
第一个为key,我们使用key来当锁,因为key是唯一的。
第二个为value,我们传的是requestId,很多童鞋可能不明白,有key作为锁不就够了吗,为什么还要用到value?
原因就是我们在上面讲到可靠性时,分布式锁要满足第四个条件解铃还须系铃人,通过给value赋值为requestId,
我们就知道这把锁是哪个请求加的了,在解锁的时候就可以有依据。requestId可以使用UUID.randomUUID().toString()方法生成。
第三个为nxxx,这个参数我们填的是NX,意思是SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;
第四个为expx,这个参数我们传的是PX,意思是我们要给这个key加一个过期的设置,具体时间由第五个参数决定。
第五个为time,与第四个参数相呼应,代表key的过期时间。

总的来说,执行上面的set()方法就只会导致两种结果:1. 当前没有锁(key不存在),那么就进行加锁操作,并对锁设置个有效期,
同时value表示加锁的客户端。2. 已有锁存在,不做任何操作。

我们的加锁代码满足我们可靠性里描述的三个条件。首先,set()加入了NX参数,可以保证如果已有key存在,则函数不会调用成功,
也就是只有一个客户端能持有锁,满足互斥性。其次,由于我们对锁设置了过期时间,即使锁的持有者后续发生崩溃而没有解锁,
锁也会因为到了过期时间而自动解锁(即key被删除),不会发生死锁。最后,因为我们将value赋值为requestId,
代表加锁的客户端请求标识,那么在客户端在解锁的时候就可以进行校验是否是同一个客户端
Redis单机部署的场景,所以容错性我们暂不考虑

解锁:

String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

第一行代码,首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)
第二行代码,我们将Lua代码传到jedis.eval()方法里,并使参数KEYS[1]赋值为lockKey,ARGV[1]赋值为requestId。
eval()方法是将Lua代码交给Redis服务端执行
eval命令执行Lua代码的时候,Lua代码将被当成一个命令去执行,并且直到eval命令执行完成,Redis才会执行其他命令

10、使用过Redis做异步队列么,你是怎么用的,有什么缺点

一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试
缺点:在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等

11、缓存穿透、缓存雪崩、缓存预热、缓存更新、缓存降级

  • 缓存穿透

缓存系统,都是按照key去缓存查询,如果不存在的key(恶意的请求)不断查询redis、数据库,请求量增大,对后端系统造成很大的压力

解决方法:

  1. 对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
  2. 对一定不存在的key进行**过滤*,可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。
  • 缓存雪崩

缓存服务器重启或者大量缓存集中在某一个时间段失效,缓存数据失效,会给后端系统带来很大压力,导致系统崩溃

解决方法:

  1. 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量
  2. 为key 设置不同的缓存失效时间
  3. 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存
  • 缓存预热

系统上线,将缓存数据直接加载到缓存系统,用户直接请求缓存的数据;避免用户请求,先查询数据库,然后再将数据缓存

  • 缓存更新
  1. 定时清理过期的缓存
  2. 用户请求时判断请求所用到的缓存是否过期,过期直接请求数据库,更新缓存
  • 缓存降级

服务出现问题,但仍然要保证服务可用,配置开关实现人工降级

12、redis单点登录

单点登录(SSO):用户只需要登录一次就可以访问所有相互信任的应用系统
一个web工程:访问用户信息,写个拦截器,看session中能不能取到用户信息,取不到返回登录页面,用户登录后用户信息保存到session中
如果是分布式的项目(cloud),sso系统可以放到网关里面做处理,因为所有项目都要走网关
或者是一个专门的sso系统,访问先走sso,再走其他的系统

登录流程:

  1. 登录页面提交用户名密码
  2. 登录后生成token,相当于原来的jsessionid,字符串,可以使用uuid
  3. 把用户信息保存到redis,key是token,value就是user对象转换的json字符串
  4. 使用String类型保存session信息,可以使用“前缀:token”为key
  5. 设置key的过期时间,模拟Session的过期时间
  6. 把token写入cookie中
  7. cookie需要跨域
  8. cookie的有效期,关闭浏览器失效
  9. 登录成功
String token = UUID.randomUUID().toString();
jedisClient.set(USER_INFO+":"+token,JsonUtils.objectToJson(user));
jedisClient.expire(USER_INFO+":"+token,SESSION_EXPIRE);
CookieUtils.setCookie(request,response,COOKIE_TOKEN_KEY,token);

通过token查询用户信息,查询不到,用户信息已经过期,查询到数据,说明已经登录(需要重置key的过期时间)
安全退出:需要根据token删除redis中的key

redis项目使用场景:登录后保存用户的信息(单点登录),商户信息(商户信息登录后会经常被用到,先重redis取)

13、redis与memcache的区别

  1. Redis和Memcache都是将数据存放在内存中,都是内存数据库,不过memcache还可用于缓存其他东西,例如图片、视频等等
  2. Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储
  3. 虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘
  4. 过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期,Redis可以通过例如expire 设定,例如expire name 10
  5. 分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从
  6. 存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)
  7. 灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复
  8. Redis支持数据的备份,即master-slave模式的数据备份
  9. 应用场景不一样:Redis出来作为NoSQL数据库使用外,还能用做消息队列、数据堆栈和数据缓存等 Memcached适合于缓存SQL语句、数据集、用户临时性数据、延迟查询数据和session等

14、redis单线程的理解

Redis客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程。其中执行命令阶段,由于Redis是单线程来处理命令的,所有到达服务端的命令都不会立刻执行,所有的命令都会进入一个队列中,然后逐个执行,并且多个客户端发送的命令的执行顺序是不确定的,但是可以确定的是不会有两条命令被同时执行,不会产生并发问题,这就是Redis的单线程基本模型

15、Redis的单线程为什么这么快

  1. 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);
  2. 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
  3. 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
  4. 使用多路I/O复用模型,非阻塞I/O;
  5. Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

16、为什么不采用多进程或多线程处理

  1. 多线程处理可能涉及到锁
  2. 多线程处理会涉及到线程切换而消耗CPU

17、单线程处理的缺点

  1. 耗时的命令会导致并发的下降,不只是读并发,写并发也会下降
  2. 无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善

18、Redis不存在线程安全问题

Redis采用了线程封闭的方式,把任务封闭在一个线程,自然避免了线程安全问题,不过对于需要依赖多个redis操作(即:多个Redis操作命令)的复合操作来说,依然需要锁,而且有可能是分布式锁。

19、持久化的方式

redis是一个支持持久化的的内存数据库,将内存的数据同步到硬盘保证持久化

  • 方式:
  1. RDB快照(默认):内存中的数据以快照的方式写入一个二进制文件中,默认文件名dump.rdb,RDB是间隔一段时间进行持久化,如果持久化期间redis发生故障,会发生数据丢失
  2. AOF: 将redis执行的每次写命令记录到单独的日志文件中,当重启redis会重新将持久化的日志中文件恢复数据,AOF的文件比RDB大,恢复的速度慢

如果两种方式同时开启,数据恢复redis会优先选择AOF

优缺点:

  • AOF文件比RDB更新频率高,优先使用AOF
  • AOF比RDB更安全
  • RDB性能比AOF好
  • 如果两个都配了优先加载AOF

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值