详解redis

1 初认始redis

1.1起源

redis是一个开源的基于c语言编写,支持网络也开源支持内存持久化的日志类型,key-value 型nosql 数据库,并提供多种语言的api,从10年3月开始redis开发工作有vmware支持.从13年5月开始,redis有pivotal赞助

1.2 特性

1 速度块理论上每秒处理10W次请求

2 广泛的语言支持

3 持久化

4 多种语言结构

5 主从复制

6高可用和分布式

1.3 redis的粉丝

微信

QQ

微博

人人开源

豆瓣

百度

2 lunix下安装redis

2.1 redis中文官网

http://redis.cn/

2.2 安装流程

cd /usr/local/

wget http://download.redis.io/releases/redis-5.0.5.tar.gz

tar -zxvf redis-5.0.5.tar.gz

cd redis-5.0.5

yum install gcc

make

./src/redis-server            #启动reids

出现如下错误

cd src && make allmake[1]: 进入目录“/usr/local/redis-5.0.5/src”    CC Makefile.depmake[1]: 离开目录“/usr/local/redis-5.0.5/src”make[1]: 进入目录“/usr/local/redis-5.0.5/src”    CC adlist.oIn file included from adlist.c:34:0:zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h:没有那个文件或目录 #include <jemalloc/jemalloc.h>

删除解压目录,重新make

3 常用基本配置项

3.1 常用配置项

命令实例说明

daemonizedaemonize yes是否后台运行,默认no

portport 6379设置默认端口号 默认6379

logfilelogfile日志文件设置日志文件

databasesdatabases 255设置redis数据库总量上限是255

dirdir数据文件目录设置数据文件存储目录

requirepassrequirepass 12345设置使用密码

3.2 启动命令加上配置文件

./src/redis-server redis.cut.conf

3.3 客户端交互

./src/redis-cli -p 6666 -a 123456

3.4 redis杀死

./src/redis-cli -p 6666 -a 123456 shutdown

4 redis的通用指令

ping  测试redis网络

exit 退出redis客户端

shutdown 关闭redis服务器

通用命令

命令示例说明

selectselect 0选择0号数据库

keyskeys he* | he[h-1] * | ph?根据Pattern表达式查询符合条件的key(不要再生产环境中使用)

dbsizedbsize返回key的总数

existsexists a检查key==a是不是存在

deldel a删除key=a的数据

expireexpire hello 20设置key=hello  20 秒后过期

ttlttl hello检查key=a的过期时间

5 redis数据结构

5.1 支持的数据结构

String  字符串类型

Hash  hash类型(类似java 的map)

List  列表类型

Set  集合类

ZSet  有序集合类型

5.1 redis的字符串类型


5.2 字符串使用的场景

1 缓存

2 秒杀(使用计算器)

3 分布式锁

4 配置中心

5 对象序列化

6计数器

5.3 redis字符串指令

命令示例说明使用频率

getget hello获取key=hello的结果常用

setset hello world设置key=hello,value=hello常用

msetmset hello world java best一次设置多个kv常用

mgetmget hello java一次获取多个kv常用

deldel hello删除key=hello一般

incr/decrincr count /decr countkey值自增/自减1一般

incrby/decrbyincrby count 99/decrby count 99自增自减指定步长很少

5.4 redis的hash数据结构


hash类型用于存储结构化数据

hash类型可以看作map 中的map

命令示例使用频率说明

hgethget user:1:info age经常获取hash中key=age的值

hsethset user:1:info age 23经常设置hash中age=23

hmsethmset user:2:Info age 30 name kaka经常设置hash中多个值

hmgethmget user:2:info age name一般获取hash中多个值

hgetallhmget user:2:info一般获取hash所有值

hdelhdel user:1:info age一般删除user:1的age

hexistshexists user:1:info name一般检查是不是存在

hlenhlen user:1:info很少获取指定的长度

注意 hash key的命名规则:对象类型:数字:属性

5.5 string-json和hash再处理json数据下对比

命令优点缺点

string-json序列化编程简单 节约内存序列化开销 无法更新部分属性

hash直观 可以部分更新多层嵌套实现困难 序列化和反序列化麻烦

string-json的存储数据如下

{

  name:"aaa"

  ,info :{

        age:12

    }

}

hash存储数据如下

5.6 list结构数据

list列表是简单的字符串列表,按照插入的顺序排序.你可以添加一个元素到列表的前边或者是后边

一个列表最多可以包含2的32次方-1个元素(每个列表超过40亿个元素)

5.7 list常用指令

命令说明

rpush listkey c b a右边插入

lpush listkey f e d左边插入

rpop listkey右边移除

lpop listkey左边移除

llen listkey获取list集合的长度

lrange listkey 0 2从下标是0的开始获取两个元素

lrange listkey 1 -1获取子集从1 到-1 之间的元素 -1从右边数

5.8 set结构数据


redis的Set是string类型的没有顺序的集合,集合成员是唯一的 .这就标识这集合中不会出现重复数据

redis中集合是通过哈希表实现 的,所以添加 删除 查找的速度非常快

集合中做多可以存储40亿个数据

命令示例说明使用频率

saddsadd a b添加元素高

sremsrem a b移除元素高

scardscard user:1:flollow计算集合数量一般

smemberssmembers user:1:flollow获取所有的集合元素(不推荐)低

srandmembersrandmember user:1:flollow随机挑选三个元素低

spopspop user:1:flollow随机弹出元素低

sdiffsdiff set1 set2差集低

sintersinter set1 set2交集低

sunionsunion set1 set2并集低

set应用的场景

1微关系:共同关注的人

2 抽奖

5.9 zset

1 概述

zset是string类型的有序集合,集合成员是唯一的.这就意味这集合中不可以出现重复数据

增加score数据用做排序

2 常用指令

命令示例说明使用频率

zaddzadd key score elemments添加元素到集合中高

zscorezscore key element得到分数低

zcardzcard key元素总数高

zremzrem key element删除数据一般

zrangezrange key scope withscoreres获取排序索引数量高

zcountzcount key scope获取排序数据总量低

zrangebyscorezrangebyscore key获取按分数排名的数据低

zrankzrank key element获得排名低

zadd palyer:rank 100 cluo 200 meixu 600 erduo

zrem palyer:rank erduo

zrange palyer:rank 0 -1 #按顺序排列数据

zrange palyer:rank 0 -1 withscores      排序增加分数

zcount palyer:rank 100 200  分数100到200的数量

zrangebyscore palyer:rank 100 200 withscores  按排序列出数据并且分数一起显示

3 使用场景


6 redis客户端

RedisDesktopManager 如果链接补上再配置文件中增加  bind 0.0.0.0

7 java客户端jedis

jedis是java开发的redis客户端工具包,用于java语言与redis语言进项交互

jedis只是对redis的命令进行了封装,掌握了reids命令就可以轻松使用jedis

jedis遵从Resp协议开发规范,具有很好的通用性和可读性

依赖

<dependency>

   <groupId>com.yugabyte</groupId>

   <artifactId>jedis</artifactId>

   <version>2.9.0-yb-11</version>

</dependency>

测试jedis

@Test

public void testJedis() throws Exception{

   //创建一个Redis通道

   Jedis jedis = new Jedis("192.168.132.128", 6666, 1000);

   try {

       jedis.auth("123456");//设置登录密码

       jedis.select(3);//选择第四个数据库,数据库下标从0开始

       jedis.flushDB();//清空第四个数据库

       jedis.set("hello", "world"); //jedis.xxx方法名字就是命令

       System.out.println( jedis.get("hello"));

       jedis.mset(new String[]{"a", "1", "b", "2", "c" ,"3"});

       List<String> strs =  jedis.mget(new String[]{"a", "c"});

       System.out.println(strs);

       System.out.println(jedis.incr("c"));

       System.out.println(jedis.del("b"));;

   } catch (Exception e) {

       throw e;

   }finally {

       jedis.close();//释放链接

   }

}

@Test

public void testHash() throws Exception {

   Jedis jedis = new Jedis("192.168.132.128", 6666, 1000);

   try {

       jedis.auth("123456");//设置登录密码

       jedis.select(3);//选择第四个数据库,数据库下标从0开始

       jedis.flushDB();//清空第四个数据库

       jedis.hset("user:1:info", "name", "齐毅");

       jedis.hset("user:1:info", "age", "35");

       jedis.hset("user:1:info", "height", "180");

       String name = jedis.hget("user:1:info", "name");

       System.out.println(name);

       Map user1 = jedis.hgetAll("user:1:info");

       System.out.println(user1);

   } catch (Exception e) {

       throw e;

   }finally {

       jedis.close();//释放链接

   }

}

8 JedisPool

1 依赖

<dependency>

   <groupId>com.yugabyte</groupId>

   <artifactId>jedis</artifactId>

   <version>2.9.0-yb-11</version>

</dependency>

测试

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import org.junit.Test;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;

/**

* 连接池测试类

*/

public class JedisPoolTestor {

   @Test

   public void testJedisPool(){

       GenericObjectPoolConfig config = new JedisPoolConfig();

       config.setMaxTotal(100); //设置连接池中最多允许放100个Jedis对象

       //我的建议maxidle与maxTotal一样

       config.setMaxIdle(100);//设置连接池中最大允许的空闲连接

       config.setMinIdle(10);//设置连接池中最小允许的连接数

       config.setTestOnBorrow(false); //借出连接的时候是否测试有效性,推荐false

       config.setTestOnReturn(false); //归还时是否测试,推荐false

       config.setTestOnCreate(false); //创建时是否测试有效

       config.setBlockWhenExhausted(true);//当连接池内jedis无可用资源时,是否等待资源 ,true

       config.setMaxWaitMillis(1000); //没有获取资源时最长等待1秒,1秒后还没有的话就报错

       //创建jedis,这句话运行后就自动根据上面的配置来初始化jedis资源了

       JedisPool pool = new JedisPool(config , "192.168.186.6" , 6379);

       Jedis jedis = null;

       try {

           jedis = pool.getResource(); //从连接池中"借出(borrow)"一个jedis对象

           jedis.auth("12345");

           jedis.set("abc" , "bbb");

           System.out.println(jedis.get("abc"));

       } catch (Exception e) {

           e.printStackTrace();

       } finally {

           if(jedis != null){

               jedis.close();//在使用连接池的时候,close()方法不再是关闭,而是归还(return)

           }

       }

   }

}

3 直连和连接池

优点缺点

直连简单粗暴 适应少数链接的场景jedis线程不安全,存再链接泄露问题

连接池jedis对象预先生成,降低开销,偏于链接资源进行监控和控制实用麻烦,参数较多,规划不合理容易问题

9 springboot+spring cache实现声明式缓存

redis在开发中最重要的应用就是缓存。利用内存的高吞吐解决数据查询慢的问题

spring cache 是spring生态的一员。用于对主流缓存组件进行一致性访问,通过暴露统一的接口,让我们轻松的使用并进行组件之间的切换

spring cache的对缓存的支持

Collection

ConcurrentMap

Redis

Ehcache

Google GuavaCache

Hazlcast

JCache

声明式缓存

声明书缓存通俗来说是采用注解的形式对当前应用的非侵入式扩展

声明式缓存是spring cache默认支持,底层采用spring aop技术实现

10 内部运行原理


内存处理速度快,纳秒级别

非阻塞io,io多路复用,基于事件完成读写

避免线程切换和资源浪费

一次只能使用使用一条命令

经量不要使用慢命令

keys

flushall

flushdb

exec

save

bgsave

11 Rdb

reids所有数据保存到内存中,为了防止数据丢失,会异步把数据保存到硬盘上

快照===》mysql Dump,  reids RDB

写日志==》 mysql Binlog  ,habse hlog  ,  redis aof

11.2 Rdb执行流程


11.3 Rdb 使用方式

save 同步保存

bgsave 异步保存

自动保存

11.4 Rdb的配置项目

save 60 1

自动保存策略 60秒内有一个key发生变化就自动保存

dbfilename dbdump.rdb

设置rdb名字

dir ./

rdb文件保存的位置

stop-writes-on-bgsave-error yes

发生中断时候写入 建议开启

rdbcompression yes

数据文件压缩建议开启

rdbchecksum yes

开启crc64错误校验 建议开启

12 AOF


aof策略

always  随时写入 (不推荐)

everysec 每秒写入(推荐)

no  依赖os规则写入(不推荐)

比较

命令alwayseverysecno

优点不丢失数据每秒一次同步丢1秒数据不用管

缺点io开销大,丢1秒数据不可控

AOF重写


原生aof重写aof

原生的rpush mylist a  rpush mylist brpush                  重写后mylist a b

aof实现方式

bgrewriteof 命令

aof重写配置

aof常用配置

参数说明

appendonly  yes开启aof

appendfilename  aof66.aofaof日志文件名

appendfsync  everysec每秒记录一次日志

no-appendfsync-on-rewrite yes重写过程中是不是向日志文件中写入yes 重写过程中不向aof文件中追加日志,等rewrite执行完后在写入      no 代表重写执行时候也向aof中追加信息

auto-aof-rewrite-percentage 100触发重写文件的百分比 默认是100%

auto-aof-rewrite-min-size  64mb触发最小aof文件尺寸

bgrewriteaof  自动保存aof文件

rewrite说明

aof文件小于64mb 不重写

aof第一大于64m自动重写,压缩到33m

Rdb和aof对比

rdb和aof都开启的情况下 会采用aof来回复数据

日常开发,官方推荐使用aof

redis主从同步底层使用的是rdb

13  redis 主从复制

13.1单机部署的缺陷

单机故障

容量瓶颈(一台机器的内存是有限的 )

QPS瓶颈(每秒请求数量10W次在特殊的环境下不够用)

13.2 主从复制是高可用的基础


13.3 主从的特性

一个master可以有多个slave

一个slave只能有一个master

数据流是单向的,master到slave

主从复制的底层依赖RDB的方式进行全量覆盖

13.4  主从复制的实现

slaveof /slaveof  no one

配置文件

13.5 用客户端命令配置主从同步

slave端操作如下

./src/redis-cli -p 6379 -a 123456  进入客户端

slaveof node-4 6379  在从节点上执行同步命令,会清除掉自己有的数据和从节点进行同步

config set masterauth 123456  设置master密码

info replication  查看同步信息

slaveof no one解除从属关系

13.6 用配置文件使用主从复制

命令方式配置的主从重启后会失效 建议采用配置文件的方式

daemonize yes

port 6379

logfile redis.log

databases  12

dir ./redisdata

requirepass 123456

slaveof node-4 6379

masterauth 123456

slave-read-only yes

14 redis的配置与启动

14.1 主从面临的高可用问题

如上主节点挂掉 从节点变成master 但是程序中怎么办,同步修改问题

14.2 redis sentinel(哨兵)


是一个分布式架构,包含若干个sentinel节点和reids数据节点,每个sentinel节点会对数据节点和其他的sentinel节点进行监视,当发现节点不可达时候对节点做下线处理(标识)

1 有sentinel来代理进行访问

2 如果reids集群的master 节点挂掉,sentinel选举新的master,

所有的节点向新的master节点同步数据

14.3 sentinel节点配置

daemonize yes

port 26379(默认节点)

logfile sentinel.log

dir ./redisdata

sentinel monitor  mymaster  10.10.10.0 6379 2

<!--监控redis集群主节点名字为mymaster ip为10.10.10.0 端口号为6379 的有两个sentinel链接不上该master,就自动转移故障-->

sentinel down-after-milliseconds mymaster 20000

<!--20秒ping不通就认为该节点有故障-->

sentinel parallel-syncs mymaster 1

<!--故障转移后是并行复制还是串行复制-->

sentinel failover-timeout mymaster 600000

<!--故障开始10分钟没有完成转移工作认为转移失败-->

故障转移master节点的redis文件也需要做 masterauth 123456  密码认证

14.4 sentinel 实现故障转移

mavne依赖

<dependency>

   <groupId>com.yugabyte</groupId>

   <artifactId>jedis</artifactId>

   <version>2.9.0-yb-11</version>

</dependency>

代码实现

String nodename = "node-3";

Set<String> set = new HashSet<String>();

set.add("node-3:26379");

set.add("node-4:26379");

set.add("node-5:26379");

JedisSentinelPool jedisSentinelPool = new JedisSentinelPool(nodename, set,"123456");

Jedis resource = jedisSentinelPool.getResource();

resource.select(6);

resource.set("test", "2020-12-12");

resource.close();

15 redis开发规范

15.1 key的规范

业务名:表名:id

减少key的长度,不超过39个字符

key 不要包含特殊字符

15.2 java对象存储方案

javaredis类型说明使用场景

javabeanstring保存对象json序列化字符串,使用简单,节省key。缺点无法局部调整,序列化和反序列化要重新计算保存相对稳定数据,如电商平台的商品,档案

javabeanhash最符合javabean的特征的保存方式,有点key松散管理,可以局部修改数据,缺点hash=》object需要额外的编码同上

list/setstringjson序列化存小数据,修改不多,优点节省空间 缺点无法调整排行旁

list/setn/a变化频率高,数据不断刷新,不要放到redis中做缓存股票实时行情,销售金额等等

15.3 开发建议

不要使用直连,采用jedispool方式开发

建议使用springcache声明式缓存

15.4 reids安全建议

redis不要在外网被访问 禁止 bind 0.0.0.0

更改redis默认端口

使用非root用户

redis设置强度高的密码。别和登录密码相同

定期备份,save命令

防火墙

16 内存和回收策略

info memory

used_memory:13490096数据占用了多少内存(字节)

used_memory_human:12.87M数据占用了多少内存(单位)

used_memory_rss:13490096操作系统已分配的内存量

used_memory_peak:15301192占用内存的峰值(字节)

used_memory_peak_human:14.59M占用内存的峰值(带单位的)

used_memory_lua:31744lua引擎所占用的内存大小(字节)

mem_fragmentation_ratio:1.00内存碎片率

16.2设置内存上限

32位系统最大的可以使用内存是3G

64位系统默认最大为可以使用的内存

maxmemory配置项用于设置最大内存

maxmemory  1gb

maxmemory  120mb

一般预留30% 的内存

16.3 内存回收策略

超过最大内存后自动触发相应的策略

由maxmemory-policy选项控制

maxmemory-policy volatile-lru

maxmemory-policy allkeys-lru

内存回收六种策略

1. noeviction : 永不过期,返回错误(默认)

2. volatile-lru:在即将过期数据删除使用最少的key(推荐)

3. allkeys-lru :在所有数据中删除lru算法的key(推荐)

4. volatile-random:随机删除即将过期key

allkeys-random:所有key随机删除

volatile-ttl : 按到期时间顺序,删除即将过期的key

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342