Redis项目实战(一)--redis基础

redis(Remote Dictionary Server)
 
一、原理及特性层面:
    1、优势:
       1)数据加载在内存中,执行速度快, 数据结构类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)。
       2)单线程多路复用,I/O多路复用(防止  I/O 阻塞)-- 一种效率更高的 I/O 模型, 在单个线程中通过记录跟踪每一个sock(I/O流) 的状态来管理多个I/O流。(相比多线程效率更高, .跟多线程相比较,线程切换需要切换到内核进行线程切换,需要消耗时间和资源, I/O多路复用不需要切换线/进程)
       3)协议简单,客户端和服务端使用 RESP协议(容易实现、快速解析), RESP是二进制安全的而且从一个进程发块数据给另一个进程的时候不需要做转换,因为他会在块数据之前加上长度。
  eg:执行aof文件重写指令之后的内容
    *2 //以下有2组命令,即GET name
$
3 //redis协议中指定指令的长度 GET $4 name

 2、特点及应用:

        0)支持lua脚本, 在Redis中,执行Lua语言是原子性,也就是说Redis执行Lua的时候是不会被中断的,具备原子性,这个特性有助于Redis对并发数据一致性的支持。
        1)支持事务、 watch,操作命令都是原子的。
              Redis事务: Redis中的事务(transaction)是一组命令的集合。  Redis保证一个事务中的所有命令要么都执行,要么都不执行。如果在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行。而一旦客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令。 Redis的事务还能保证一个事务内的命令依次执行而不被其他命令插入。 
              注意: 和传统的mysql事务不同的事,redis事务不支持回滚。
              Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断( 为了避免竞态条件,或多线程其的情况)
 //伪代码
 WATCH key  
 isFieldExists = HEXISTS key, field  
 if isFieldExists is 1  
 MULTI  
 HSET key, field, value  
 EXEC  
 else  
 UNWATCH  
 return isFieldExists
      2)支持管道Pipline,批量指令操作操作,能减少网络交互时间;
             缺陷:允许一定比例的写入失败,对可靠性要求很高的系统不适用;
      3)支持消息发布与订阅;
             缺陷:相对于kafka,redis吞吐量不高,redis接收端挂掉重启,不会接收之前发送的消息。
      4)可以设置key的过期时间;
      5)支持5种数据类型;
      6)支持数据持久化;
      7)支持主从(master-slave)复制来实现数据备份,主机会自动将数据同步到从机。

 

二、 基本使用

1、redis创建用户
 //创建普通用户****
  useradd -d /appdeploy -m appdeploy
//创建用户组并加入 刚刚创建的用户****
  useradd -g appdeploy -n appdeploy(可不执行)
//修改文件或文件夹的权限,使新增用户可以拥有该文件的查看权限****
  chmod -R 777 /usr/local/soft/elasticsearch-6.4.0/
  或者授权文件归属于另一个用户组的用户 (chown -R appdeploy:appdeploy /usr/local/soft/elasticsearch-6.4.0//将用户添加到用户组而不脱离该用户原来的组
  usermod -a -g groupA appdeploy(可不执行)
//将文件夹的归属给某个组
chown root:mygroup /user/local/soft(可不执行)
2、redis启动
前端启动:在redis的安装目录下直接启动redis-server
 ./redis-server
 
后台启动:
把/root/redis-3.0.0/redis.conf复制到/usr/local/redis/bin目录下
cp redis.conf /usr/local/redis/bin/
修改配置文件:
./redis-server redis.conf
 
查看redis进程:
ps aux|grep redis
如下信息:
root      5190  0.1  0.3  33936  1712 ?        Ssl  18:23   0:00 ./redis-server *:6379   
root      5196  0.0  0.1   4356   728 pts/0    S+   18:24   0:00 grep redis
 
指定端口启动(&表示后台运行)
./redis-server --port 6380& 
3、Redis-cli
//默认连接localhost运行在6379端口的redis服务。
./redis-cli
 
//指定IP和端口连接
//-h:连接的服务器的地址
//-p:服务的端口号
./redis-cli -h 192.168.25.153 -p 6379
 
关闭redis:
./redis-cli shutdown
 
//设置密码的连接方式
./redis-cli -h 127.0.0.1 -p 6379 -a Password
4、五种数据类型
1). String    String数据结构是简单的key-value类型,value其实不仅可以是String,也可以是数字。
2). Hash    Hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。 比如我们可以Hash数据结构来存储用户信息,商品信息等等。
3). List     list就是链表,Redis list的实现为一个双向链表,即可以支持反向查找和遍历。
     应用:
  使用Redis实现消息队列
  普通队列:一般使用list结构作为队列,rpush生产消息,lpop消费消息, blpop阻塞消费。
  消费多次:生产一次消费多次的情况使用发布/订阅模式
  延时队列:使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理
4).Set    set是可以自动排重的。
5).Sorted Set   sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。
5、 Key命令
设置key的过期时间。
Expire key second:设置key的过期时间
Ttl key:查看key的有效期
Persist key:清除key的过期时间。Key持久化。
> expire Hello 100
(integer) 1
> ttl Hello
(integer) 77
 
Incr
对 key 的值做加加操作,并返回新的值。注意 incr 一个不是 int 的 value 会返回错误,incr一个不存在的key,则设置 key为1
 
应用:Redis实现限制访问频率, 限制每个用户每分钟最多只能访问100个页面。
实现思路:用户每次访问将value的值通过INCR命令自增1.如果自增后的值是1同时设置过期时间为1分钟。这样用户每次访问的时候都读取该键的值,如果超过了100就表明该用户的访问频率超过了限制,需要提示用户稍后访问。且该键每分钟会自动被删除。所以下一分钟又会重新计算,也就达到了限制访问频率的目的。
 
其他命令:
incrby
同 incr 类似,加指定值 ,key 不存在时候会设置 key,并认为原来的 value 是 0
Decr
对 key 的值做的是减减操作,decr 一个不存在 key,则设置 key 为-1
Decrby
同 decr,减指定值。
Append
给指定 key 的字符串值追加 value,返回新字符串值的长度。
Strlen
取指定 key 的 value 值的长度。
persist xxx(取消过期时间)
选择数据库(0-15库)
Select 0 //选择数据库
move age 1//把age 移动到1库
Randomkey随机返回一个key
Rename重命名
Type 返回数据类型
 

6、持久化方案:

         RDB:快照形式,定时且达到触发条件(配置文件的策略),redis会创建一个子进程,子进程中的所有数据和主进程中保持一致,把当前时刻的内存中的全量数据保存到磁盘(先写入到临时文件,待持久化结束后再用这个临时文件替换上次持久化的文件),Redis默认支持的持久化方案(单机环境中可以关闭,集群环境中无法关闭,集群环境中需要通过该方式进行主从节点之间数据同步)。缺点:速度快但是服务器断电的时候会丢失部分数据。

         AOF:append only file。AOF模式会开辟一个AOF缓存区,在主进程中把所有对redis数据库操作的命令,增删改操作的命令,以追加的方式保存到文件中,数据库恢复时把所有的命令执行一遍即可。AOF文件来恢复数据库,能保证数据的完整性。缺点:速度慢,一个内存中数据的增删改操作就对应写入一次磁盘。

  混合模式(优化重写持久化文件,使其占用空间更小):redis4.0版本之后补充了混合模式(5.0版本之后,默认开启),即,RDB模式下创建子进程将共享内存副本中当前时刻的全量数据写入AOF文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式个AOF格式的AOF文件替换旧的AOF文件。也就是新的AOF文件前半段是RDB格式(占用空间更小,但是可读性较差)的全量数据后半段是AOF格式的增量数据。优点是混合持久化结合了RDB持久化和AOF持久化的特点,由于绝大部分都是RDB格式,加载数据快,同时结合AOF,增量数据以AOF方式保存了,数据更少地丢失。

 

   持久化方案选择(优化建议):

  • 如果redis仅仅是用来做为缓存服务器的话,我们可以不使用任何的持久化(建议redis启动时进行全量数据同步或定时全量同步);

  • 官方建议两种持久化的方式都开启,同时开启情况下,redis优先使用AOF持久化机制;

  • 在主从节点中,RDB作为我们的备份数据,只在salve(从节点)上启动,同步时间可以设置的长一点,只留(save 900 1)这条规则就可以了;

  • 开启AOF的情况下,主从同步是时候必然会带来IO的性能影响,此时我们可以调大auto-aof-rewrite-min-size的值,比如5GB,来减少IO的频率;

  • 不开启AOF的情况下,可以节省IO的性能影响,主从节点通过RDB持久化同步,但如果主从都挂掉,影响较大。

备注:

  1、redis中的save指令,主进程持久化数据;bgsave指令,创建一个子进程持久化数据。

  2、aof文件重写机制(瘦身),如下图所示,第一次重写文件大小达到指定配置时重写。第二次重写,文件大小达到配置比例时触发。重写需要fork一个子进程,开销很大(相当于运行2个redis),故生产环境中需要配置的大一些(5G以上),避免频繁进行重写。

  

  3、RDB持久化模式会fork一个子进程进行,AOF模式不会,但是AOF的重写机制会fork一个子进程。

三、Redis缓存、ehcache、memcached比较
      特点:
       ehcache直接在jvm虚拟机中缓存,速度快,效率高;但是缓存共享麻烦,集群分布式应用不方便。
       memcache保存在内存,支持分布式,只存储String类型数据,不支持持久化。
       redis是通过socket访问到缓存服务,效率比ecache低(相差一个数量级),比数据库要快很多,支持数据类型较为丰富,支持集群和分布式缓存,有成熟的方案。
       
      技术选型: 
      单个应用,降低应用的复杂性或者对缓存访问要求很高的应用,用ehcache。
      如果是大型系统,存在缓存共享、分布式部署、缓存内容很大的,建议用redis。
      memcache,老牌缓存服务,相关领域支持比较丰富,window和linux都可以使用。
 
      补充:ehcache也有缓存共享方案,不过是通过RMI或者Jgroup多播方式进行广播缓存通知更新,缓存共享复杂,维护不方便;简单的共享可以,但是涉及到缓存恢复,大数据缓存,则不合适。
 
四、扩展

    redis内存淘汰策略:     

   高版本的Redis中当内存达到极限时,内存淘汰策略主要采用了6种方式进行内存对象的释放操作
  1).volatile-lru:从设置了过期时间的数据集中,选择最近最久未使用的数据释放
  2).allkeys-lru:从数据集中(包括设置过期时间以及未设置过期时间的数据集中),选择最近最久未使用的数据释放
  3).volatile-random:从设置了过期时间的数据集中,随机选择一个数据进行释放
  4).allkeys-random:从数据集中(包括了设置过期时间以及未设置过期时间)随机选择一个数据进行入释放
  5).volatile-ttl:从设置了过期时间的数据集中,选择马上就要过期的数据进行释放操作
  6).noeviction:不删除任意数据(但redis还会根据引用计数器进行释放呦~),这时如果内存不够时,会直接返回错误
  默认的内存策略是noeviction,在Redis中LRU算法是一个近似算法,默认情况下,Redis随机挑选5个键,并且从中选取一个最近最久未使用的key进行淘汰,在配置文件中可以通过maxmemory-samples的值来设置redis需要检查key的个数,但是栓查的越多,耗费的时间也就越久,但是结构越精确(也就是Redis从内存中淘汰的对象未使用的时间也就越久~)。
 
   LRU算法简单介绍:

      1)LRU算法作为内存管理的一种有效算法,其含义是在内存有限的情况下,当内存容量不足时,为了保证程序的运行,这时就不得不淘汰内存中的一些对象,释放这些对象占用的空间。

      2)LRU (英文:Least Recently Used), 意为最近最少使用,如果一块数据最近被访问,那么它将来被访问的几率也很高,根据数据的历史访问来淘汰长时间未使用的数据。

      3)在操作系统中LRU算法淘汰的不是内存中的对象,而是页,当内存中数据不足时,通过LRU算法,选择一页(一般是4KB)将其交换到虚拟内存区(Swap区)。

 
借鉴了不少文章,感谢各路大神分享,转载请注明出处,谢谢:https://www.cnblogs.com/huyangshu-fs/p/11255410.html 
posted on 2019-07-27 16:57  ys-fullStack  阅读(3013)  评论(0编辑  收藏  举报