目前一个基本的互联网项目
1. nosql 概述
传统RDBMS 和 NoSQL
什么是nosql?
not only sql ,指非关系型数据库
关系型数据库:表格,行,列
为什么使用nosql?
- 大数据,大规模高并发,是关系型数据库难以解决的瓶颈问题
- 许多数据难以用关系型数据库的行列这种固定形式来表示:社交网络,地理位置
nosql 四大分类
- K-V对存储数据库: redis,Tair,memecache
- 文档数据库:MongoDB,couchDB
基于分布式文件存储的数据库,处理大量文件,介于关系型数据库和非关系型数据库之间的,是非关系型中最像关系型的数据库。 - 列存储数据库:HBase
- 图形数据库:Neo4j,InfoGrid
2. Redis 入门
Redis (remote dictionary server 远程字典服务),Redis 是一个高性能的key-value数据库
可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)
这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的
为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
三个作用:做数据库存数据,做缓存,做消息中间件 mq
1. redis 安装 启动 简单使用
redis 一般推荐在 Linux 服务器上进行开发
- windows 安装
- github 上下载安装包
- 解压到自己电脑的环境目录下就可以了:解压后,包含:服务器程序,客户端程序等
- 可以启动了,双击运行 服务程序就启动了
- 默认端口号6379.运行客户端,就可以连接上服务端了。
- linux 安装
- 下载安装包
- 下载安装包
-
连接远程linux 服务器,把安装包放上去,进行解压,解压到 /opt
tar -zxvf redis-6.0.6.tar.gz
-
查看系统是否安装gcc,
gcc --version
若出现如上图所示gcc版本信息,则说明已经安装,否则,执行如下命令进行安装:sudo apt-get install gcc
- 安装redis(在linux中,刚才解压的是程序,还需要进行安装)
在刚才的解压目录下,执行以下两条指令:
make
make install
- 安装redis(在linux中,刚才解压的是程序,还需要进行安装)
-
待程序执行完成后,redis相关配置文件会自动(默认)安装到/usr/local/bin/目录下:
-
将redis解压目录下的redis.conf 复制到 安装目录下的redisconf(需要创建)文件夹下。以后启动redis就用redisconf下的配置文件,原解压目录下的原封不动。
-
redis 默认不是后台运行的,需要设置
采用vim 命令编辑redis.conf,将“daemonize no”修改为“daemonize yes”,设置为后台进行运行,修改完成后后保存退出。
-
启动redis服务器 和客户端程序,进行连接测试
-
查看redis进程是否启动
-
关闭redis
-
进程已关闭
2. redis-benchmark 性能测试工具
官方自带的压力测试工具
redis-benchmark 测试命令
例如:redis-benchmark -h 127.0.0.1 -p 6379 -c 50 -n 10000
3. redis 基础知识
- redis默认有16个数据库0-15,默认使用第0个,可以使用 select进行切换
- redis是单线程的,基于内存操作,是很快的。CPU不是redis的性能瓶颈(多线程,CPU上下文切换,会耗时),redis的瓶颈是不同机器的内存和网络带宽
- 基本操作命令 (可以去官网查看命令)
select 1 选择第1数据库
DBSIZE 查看数据库大小
set key value 添加数值对
get key 获取value值
keys * #查看所有key
flushdb 清空当前数据库
FLUSHALL 清空所有数据库
EXISTS key 查看当前key是否存在
EXPIRE key time 设置key 过期时间
move key 移除当前key
ttl key 查看当前key剩余时间
type key 查看key类型
4. redis 五大数据类型
String 字符串
常用命令:
append 追加
strlen 长度
incr 自增1
decr 自减1
INCRBY key 10 增加10
DECRBY key 10 减少10
getrange key 1 3 截取字符串
setrange key 1 value 替换功能
setex key 10 value 设置过期时间
setnx key value 不存在则设置,存在则失败
mset 批量设置
mget 批量获取
msetnx 批量不存在设置,原子操作
set user:1 {name:zhansan,age:32} 设置对象 json字符串
get user:1 获取对象
mset user:1:name ahznasn user:1:age 38 设置对象
mget user:1:name user:1:age 获取对象
getset 先获取再设置
适用场景
1.计数器
2.统计数据量
3.粉丝数
对象缓存存储
List
在redis中,list是一个链表,左右都可以操作
list 可以用做栈(lpush,ipop),队列,消息队列(lpush,rpop),阻塞队列。
命令以 l或r开头。
空代表不存在
在两边操作效率会高,中间效率低
- 常用命令
lpush 从左插入
rpush 从右侧插入
lrange 获取指定范围值
lrange 0 -1 获取全部
lpop 从左移除
rpop 从右移除
lindex 通过下标获取值
llen 获取长度
lrem 移除指定个数指定值
ltrim 截取指定范围的元素
rpop lpush 组合命令
exists 存在判断
lset 设置指定下标值
linsert 在指定元素前或后插入值
Set
集合,无序,不重复
命令以S开头
交并差 集运算
常用命令
sdd 添加元素
smembers 获取所有元素
sismember 判断是否有指定元素
scard 获取元素个数
srem 移除指定元素
srandmember 随机抽选元素
spop 随机删除元素
smove 将元素从一个集合移动到另一个集合
sdiff 集合1相对集合2的差集
sinter 两个集合交集
sunion 两个集合并集
Hash
map类型
更适合存储对象
常用命令
hset
hget
hmset
hmget
hgetall
hlen
hexists
hkeys
hvals
hincrby
hsetnx
Zset
有序集合
场景:排行榜等
常用命令
zadd
zrange
zrangebyscore -inf +inf
zrem
zcard
zrevrange
zcount
5. 三种特殊类型数据
Geospatial 地理位置
场景:定位,找附近的人,计算距离,地理位置
geo 底层其实是zset原理实现的,也可以使用zset来操作geo
命令
geoadd 设置
geopos 获取指定的经度纬度
geodist 计算两地直线距离 m米 km千米 mi英里 ft英尺
georadius 以指定经纬位置为中心,获取指定半径内的元素 withdist 显示到中心的距离 withcoord显示他人定位信息
georadiusbymember 以集合中的指定元素为中心,获取指定半径的方圆内元素
geohash 将二维的位置转换为一维的字符串,两个字符串越相近,距离越近。
Hyperloglog 基数统计
基数,就是不重复的元素个数,可以接收误差
传统方式 set 保存,重复的直接覆盖掉,保存大量的数据时,就比较麻烦
Hyperloglog 占内存小
命令
pfadd pkey a b c d
pfcount pkey 统计不重复数
pfmerge 合并
Bitmap 位图场景
位存储
统计用户信息,活跃度,登陆与否,打卡
两个状态的,都可以使用它
setbit sign 3 0
bitcount sign 统计1的记录数
五大基本数据类型 底层原理
底层数据结构:
- SDS是"simple dynamic string"的缩写。redis中所有场景中出现的字符串,基本都是由SDS来实现的;可动态扩展,收缩
- 双向链表
- int
- ziplist: 连续内存,从后向前遍历,会产生连锁更新
- 哈希表
- intset
- 跳表
6. 事务
redis 单条命令保证原子性,事务不保证原子性
redis事务没有隔离级别概念
事务,就是一组的命令,一次性,顺序性,排他性的执行
所有命令在事务中,并没有直接被执行,只有发起执行命令时,才会执行 Exec
redis的事务:
- 开启事务(multi)
- 命令入队(…)
- 执行事务(exec)按入队顺序依次执行
- discard 放弃事务(取消事务)
编译型异常,(代码错误,) 事务中的命令都不会执行
运行时异常 如果事务存在语法性错误,其他命令依然会被执行
7.redis 实现乐观锁
== redis 监控机制 watch unwatch==秒杀场景
watch mony 监视mony,相当于获取mony当前版本值
unwatch 解除监视
3. Jedis连接redis数据库
Jedis是redis官网 推荐的java连接开发工具,使用java操作redis的中间件。
测试
- 导入 jedis 依赖包
<dependencies>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
</dependencies>
- 修改redis服务器配置文件:redis.conf
在配置文件中 redis保护模式 设置为no
在配置文件中注释掉bind 127.0.0.1 即允许所有ip进行连接 - 编码 测试命令
public class RedisTest {
public static void main(String[] args) {
//1. new Jedis() 对象 ,连接redis数据库
Jedis jedis=new Jedis("49.235.181.180" ,6379);//远程主机
//2.执行各种命令,这里的jedis命令 就是在redis中练习的各种指令
System.out.println( jedis.ping());
}
}
4. SpringBoot 整合redis
1. 连接redis
- 导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置连接
SpringBoot 所有的配置类,都有一个自动配置类,自动配置类都会绑定一个properties配置文件,我们可以在application.properties中修改他的配置文件中的默认属性值。
4. 测试
class SpringbootRedisApplicationTests {
@Autowired
RedisTemplate redisTemplate;
@Test
void contextLoads() {
redisTemplate.opsForValue().set("s1","luxaingmin");//这种操作很繁琐,以后都是有一个工具类对所有操作进行封装,我们调用工具类的方法就可以了。
System.out.println("2020.8.9 开心的"+redisTemplate.opsForValue().get("s1"));
redisTemplate.opsForValue().set(111,22222);
System.out.println("2020.8.9 开心的"+redisTemplate.opsForValue().get(111));
}
}
2.序列化
首先,所有的POJO类,都要实现序列化
RedisTemplate是Spring对于Redis的封装
StringRedisTemplate继承RedisTemplate,它们采用的序列化策略不同
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
在使用 RedisTemplate时,需要修改他的序列化方式(对象放入redis的方式)
1.自己定义一个redisconfig类,进行序列化设置
@Configuration
public class RedisConfig {//自己定义的RedisConfig配置类,实现自己的序列化需求
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
//key 为String类型 value为object类型
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);//连接
//json形式的序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//string形式的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
redis.conf配置文件
redis 启动,就是通过配置文件启动的
配置文件里面有很多配置项可以定制,修改。
redis 持久化
dump.rdb
appendonly.aof
RDB(redis database)
对应 dump.rdb文件
默认开启
- rdb 触发机制
- 按照 redis.conf 配置文件中的 save 规则,在一定的时间间隔内,生成dump.rdb文件
- 执行 flushall 命令,会生成dump.rdb文件
- redis关机(shutdown),也会生成dump.rdb文件
- 对rdb文件中的数据的恢复
- 只要dump.rdb 文件放在redis启动目录下,启动时,会自动恢复文件中的数据。
- config get dir 可以查看文件保存的位置在哪里
- rdb 方式的优点:
- 适合大规模数据恢复
- 对数据完整性要求不高
- rdb 方式的缺点:
- 需要一定的时间间隔,如果redis意外宕机,最后的数据就无法保存备份
- fork进程,会占用一定的内存空间
AOF(append only file)
appendonly.aof文件
以日志的形式,保存每个写操作。(就是一个文件,打开,能看懂,按顺序保存的命令,rdb文件打开看不懂)
默认不开启 ,将配置文件中的appendonly 改为 yes,就开启了
aof文件如果有错位,redis是启动不了的,需要修复aof文件redis-check-aof --fix
工具
优点:
- 每一次修改,都同步,文件完整性更好 appendfsync always
- 每秒同步一次,可能回丢失这秒的数据 appendfsync everysec
- 从不同步时,效率最高 appendfsync no
缺点:
aof 运行效率要比rdb慢,
aof文件要远大于rdb,修复速度也比rdb慢
redis 发布订阅
一种消息通信模式 pub /sub 发布、订阅
场景:实时消息推送,实时聊天,关注系统
发布者 频道 订阅者
命令:
- PSUBSCRIBE pattern [pattern1 …]
- 说明:订阅一个或多个符合给定模式的频道,每个模式以*作为匹配符
- 参数:pattern(给定的模式)
- 返回:接受到的信息
- PUNSUBSCRIBE pattern [pattern1 …]
- 说明:用于退订所有给定模式的频道
- 参数:pattern(给定的模式)
- 返回:这个命令在不同的客户端中有不同的表现。
- SUBSCRIBE channel [channel1 …]
- 说明:用于订阅给定的一个或多个频道的信息
- 参数:channel(给定的频道名)
- 返回:接收到的信息
- UNSUBSCRIBE channel [channel1 …]
- 说明:用于退订给定的一个或多个频道的信息
- 参数:channel(给定的频道名)
- 返回:这个命令在不同的客户端中有不同的表现
- PUBLISH channel message
- 说明:用于将信息发送到指定的频道
- 参数:channel(频道名称),message(将要发送的信息)
- 返回:接收到此消息的订阅者数量
- PUBSUB < subcommand > argument [argument1 …]
- 说明:用于查看订阅与发布系统状态,它由数个不同格式的子命令组成
- 参数:subcommand(子命令),argument(子命令参数)
- 返回:由活跃频道组成的列表
例子
订阅者
发布者
redis 主从复制
主从复制,将一台redis服务器(主)的数据复制到其他redis服务器(从)上
数据单向复制
主可以有多个从,从只能有一个主
读写分离,主负责写业务,从负责读业务
数据库的操作,读多余写
主从复制主要作用:
- 数据冗余
- 故障恢复
- 负载均衡
- 高可用 ,哨兵和集群实现的基础
redis 集群环境搭建
只配置从库,不用配置主库
主机可以写,从机不能写只能读
- 查看当前库的信息:
- 搭建伪集群
-
- 开启3个机子,配1主2从
-
- 将redis.conf文件再复制3份,每个redis服务器的开启都需要有一个配置文件。
- 将redis.conf文件再复制3份,每个redis服务器的开启都需要有一个配置文件。
-
- 修改配置文件信息:
端口
pid名字
log文件名
dump.rdb文件名
-
- 启动3个redis服务器
- 启动3个redis服务器
- 修改配置文件信息:
-
-
1主2从配置(只配从机)
slaveof ip port 通过命令配置,暂时的
slaveof no one 当主机宕机了,这个命令可以将从机变为主机对 配置文件进行配置,永久生效
主机信息
从机信息
-
复制原理: 全量复制 增量复制
哨兵模式 (自动选择老大)
1.添加配置文件 sentinel.conf
2.编辑配置文件:sentinel monitor myredis ip port 1
开启哨兵进程 redis-sentinel …/sentinel.conf
单哨兵模式
哨兵,是“谋朝篡位”的自动实现机制
哨兵是一个独立的进程
如果主机故障,根据投票数,自动将其中一台从机升为主机(投票算法)
如果之前的主机回来了,只能作为当前主机的从机
多哨兵模式
redis 缓存穿透和雪崩
缓存穿透
一个查询请求,在缓存没有命中的时候,会去持久层的数据库中查询;当出现大量这样的查询请求,底层数据库会产生很大的压力,称为缓存穿透
解决方案:
- 布隆过滤器:
布隆过滤器原理
- 缓存空对象
缓存击穿
雪崩