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的粉丝
微信
微博
人人开源
豆瓣
百度
2 lunix下安装redis
2.1 redis中文官网
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