1 NoSQL概述
01为什么要使用NoSQL
大数据时代:大数据一般的数据库无法进行分析处理了
- 单sql时代:一个基本的网站访问量一般不会太大,单个数据库即可;服务器压力较小
- APP-DAL-MySQL
- 缺点:
- 数据太大的时候,一个机器放不下
- 数据索引(B+Tree),一个机器放不下(超过300万的时候必须建立索引)
- 访问量(读写混合)一个服务器承受不了
- Memcached+MySQL +垂直拆分(读写分离) 缓存
-
APP-DAL-(MySQL1,MySQL2(写内容),MySQL3)
-
为了减轻数据库的压力,可以使用缓存(缓存主要是为了解决读的问题)
-
发展过程:优化数据结构和索引–>文件缓存(IO)–>Memcached
-
- 分库分表 + 水平拆分 + MySQl集群
本质:数据库的读写
早些年的MyISAM:表锁,十分影响效率,高并发下会发生严重的锁问题
转战Innodb:行锁
主键开始使用分库分表来解决写的压力,MySQL在当时推出了表分区(但是使用较少,更多的是集群) - 近期
- 新型数据库:图型 ;json
- 当mysql存储一些很大 的文件的时候,效率会很低
- 大数据的IO压力下,表几乎无法更改
- 目前基本的互联网项目
- 为什么使用NoSQL
- 爆发式增长的数据无法使用关系型数据库(如用户的个人信息,社交网络,地理位置,用户日志等等),NoSQL可以处理这些情况
02什么是NoSQL
什么是NoSQL
-
NoSQL = Not Only SQL
泛指非关系型数据库,随着web2.0互联网的诞生,传统的非关系库很难应付web2.0时代,尤其是大规模的搞开发的社区,NoSQL在当今大数据环境下发展十分迅速,Redis是发展最快的关系型数据库:表格 行 列 (POI:通过java程序和poijar包来操作Excel)
很多的数据类型用户的个人信息、社交网络、地理位置,这些数据类型的存储不需要一个固定的格式,不需要多余的操作就可以横向扩展的
使用Map的(k,v)来控制:k为String类型,v为object类型
NoSQL的特点
解耦
- 方便扩展(数据之间没有关系,很好扩展)
- 大数据量,高性能(Redis 1s可以写8w字,读取11w字,NoSQL的缓存记录集是一种细粒度的缓存,性能较高)
- 数据类型多样(不需要事先设计数据库,随取随用:使用getter和setter方法,如果是数据量十分大的表,就较难设计了)
- 传统RDBMS和NoSQL区别
- 传统RDBMS
- 结构化组织
- SQL
- 数据和关系都存在单独的表中
- 数据操作语言,数据定义语言
- 严格的一致性
- …
- NoSQL
- 不仅仅是数据
- 没有固定的查询语言
- 键值对存储,列存储,文档存储,图形数据库(社交关系)
- 最终一致性
- CAP定理和BASE理论(异地多活)
- 高性能,高可用,高可扩展
- …
- 传统RDBMS
CAP原则
- 一致性(Consistency):每次读操作都能保证返回的是最新数据;
- 可用性(Availablity):任何一个没有发生故障的节点,会在合理的时间内返回一个正常的结果;
- 分区容忍性(Partition-torlerance):当节点间出现网络分区,照样可以提供服务。
CAP三者只能取其二,不可兼得
BASE理论
- Basically Available:基本可用性,即允许分区失败,除了问题仅服务降级;
- Soft-state:软状态,即允许异步;
- Eventual Consistency:最终一致性,允许数据最终一致性,而不是时刻一直。
了解:3V + 3高
- 大数据时代的3V:主要是描述问题的
- 海量 Volume
- 多样 Variety
- 实时 Velocity
- 大数据时代的3高:主要是解决问题的
- 高并发
- 高可扩(随时水平拆分,机器不够时,可以通过扩展机器来解决)
- 高性能(保证用户体验和性能)
真正在公司中的实践:NoSQL + RDBMS
03阿里巴巴的演进分析
任何一家互联网的公司,都不可能只是简简单单让用户能用就好了
大量的公司做的都是相同的业务—竞品协议—促进发展
架构师:面向千层饼编程(封装 抽象)
存储逻辑
- 商品的基本信息
- 名称 价格 商家信息 ==> 关系型数据库即可:MySQL Oracle (淘宝早年就去IOE了–王坚模式)
- 去IOE:由阿里巴巴造出的概念,在阿里巴巴的IT架构中,去掉IBM的小型机、Oracle数据库、EMC存储设备,代之以自己在开源软件基础上开发的系统。
- 淘宝内部的MySQL不是普遍认知的MySQL,底层有变化
推荐阅读:阿里云的这群疯子 (40mins)
- 商品的描述、评论 (文字性比较多)
- 文档型数据库中,如MangoDB
- 图片
- 分布式文件系统 FastDFS
- 淘宝自己的 TFS
- Google的 GFS
- Hadoop HDFS
- 阿里云的 oss
- …
- 商品的关键字(搜索)
- 搜索引擎 solr elasticsearch
- 淘宝中使用的ISearch:多隆(阿里云的第一位程序员)
- 商品热门的波段信息
- 内存数据库
- Redis Tair Memcache
- 商品的交易 外部的支付接口
- 三方应用
大型互联网应用的问题
- 数据类型太多
- 数据源繁多,经常重构
- 数据要改造的时候,需要进行大面积的改造
解决方法
统一的数据服务层UDSL:在应用集群和底层数据源之间,构建一层代理,统一数据层
04NoSQL的四大分类
KV键值对
- 新浪:Redis
- 美团:Redis + Tair
- 阿里、百度:Redis + Memcache
文档型数据库(bson格式 和json类似)
- MongoDB(一般必须掌握)
- 是一种基于分布式文件存储的数据库,由C++编写,主要用来处理大量的文档
- MongoDB是一种介于关系型数据库和关系型数据库的产品,MongoDB是非关系型数据库中功能最丰富最像关系型数据库的
- ConthDB
列存储数据库
- HBase
- 分布式文件系统
图关系数据库
- 不是用来放图片的,而是用来存放关系的:朋友圈社交网络,广告推荐
- Neo4j ,InfoGrid
四者对比
2 Redis入门
2-1概述
- Redis是什么
- Redis(Remote Dictionary Server),远程字典服务。是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
- 区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
- “免费” “开源” “当下最热门的NoSQL技术之一,也被人们称为结构化数据库”
- 支持语言
- Redis能干什么
- 内存存储,持久化
- 内存中几乎是断电即失的,所以说持久化很重要
- Redis中持久化的两种机制:RDB、AOF
- 效率高,用于高速缓存
- 发布订阅系统
- 地图信息分析
- 计时器,计数器(统计浏览量等)
- …
- 内存存储,持久化
- 特性
- 多样的数据类型
- 持久化
- 集群
- 事务
- …
- 学习中需要用到的东西
- 公众号:
- 狂神:狂神说
- 官网:https://redis.io/(英文)
- 中文官网:http://www.redis.cn/
- 下载地址:通过官网下载
- Windows版本在github上下载(停更很久了):官方不建议在Windows下开发Redis
Redis推荐都是在Linux服务器上搭建的,本套课程基于Linux学习
- 公众号:
2-2 Redis部署在Linux(Ubuntu)
-
wget http://download.redis.io/releases/redis-5.0.8.tar.gz
下载版本:如果下载慢也可以使用U盘拷贝
-
解压:
tar -zxvf redis-5.0.8.tar.gz
-
进入redis目录
cd redis-5.0.8
-
编译
make
-
安装
make PREFIX=/usr/local/redis install
- /usr/local/redis :是自定义的安装目录
- 或者使用
make install
-
拷贝redis.conf,之后使用的是拷贝后的redis.conf
cp redis.conf /usr/local/redis
- 进入/usr/local/redis目录
cd /usr/local/redis/
- 编辑redis.conf
vim redis.conf
1.后台启动,daemonize yes
2.绑定端口,port 6379 默认是6379 #需要安全组开放端口
3.绑定IP,bind 127.0.0.1 #默认值,需要时可更改
4.指定数据存放路径,dir /usr/local/redis/log rdb #存放的路径
5.指定持久化方式,appendonly yes
6.requirepass redis129 #设置密码
编辑完毕之后, esc
--》 :wq
-
后端启动redis:
./bin/redis-server ./redis.conf
;通过指定的配置文件启动服务 -
查看是否启动成功
ps aux | grep redis
-
进入客户端,处理中文乱码
./bin/redis-cli --raw //处理中文乱码问题
- 开启redis 客户端
./bin/redis-cli -p 6379
- ping(若得到为PONG则为连接成功)
- 测试 :
set name qd
get name #得到:"qd"
- 查看所有key:
keys *
- 查看所有redis进程
ps -ef|grep redis
- 关闭redis进程
./bin/redis-cli shutdown # 也可以直接shutdown,这样会变成未连接状态,然后输入 exit退出
kill -9 pid //进程
- 之后会使用单机多Redis启动集群测试
redis的默认安装路径:usr/local/bin
遇到的问题:
- 几个warning
- gcc-c++(所需环境)
- java环境
参考文章:https://blog.csdn.net/lp199994/article/details/106724079
2-3 测试性能
简介
- redis-benchmark是一个压力测试工具(官方自带的性能测试工具)
redis-benchmark 命令参数
测试
-
测试:100个并发连接 100000请求
- 测试命令:
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
- 测试的时候若显示让安装redis-tools ,可使用命令:
suo apt install redis-tools
,
可能显示:
解决方法:sudo rm -r -f /var/lib/dpkg/lock
- 测试命令:
-
运行结果:
====== PING_INLINE ======
100000 requests completed in 3.67 seconds
100 parallel clients
3 bytes payload
keep alive: 1
13.47% <= 1 milliseconds
58.44% <= 2 milliseconds
88.72% <= 3 milliseconds
95.50% <= 4 milliseconds
98.44% <= 5 milliseconds
99.51% <= 6 milliseconds
99.83% <= 7 milliseconds
99.99% <= 8 milliseconds
100.00% <= 8 milliseconds
27225.70 requests per second
====== PING_BULK ======
100000 requests completed in 3.64 seconds
100 parallel clients
3 bytes payload
keep alive: 1
15.68% <= 1 milliseconds
61.51% <= 2 milliseconds
90.81% <= 3 milliseconds
96.17% <= 4 milliseconds
98.58% <= 5 milliseconds
99.44% <= 6 milliseconds
99.67% <= 7 milliseconds
99.90% <= 8 milliseconds
99.97% <= 9 milliseconds
100.00% <= 9 milliseconds
27472.53 requests per second
# 对100000请求进行写入测试
====== SET ======
100000 requests completed in 3.52 seconds # 100000个请求在3.52s完成
100 parallel clients # 100个并发客户端
3 bytes payload # 默认每次写入3个字节(可修改)
keep alive: 1 # 只有一台服务器来处理这些请求:测试的是单机性能
11.81% <= 1 milliseconds
60.08% <= 2 milliseconds
88.36% <= 3 milliseconds
95.02% <= 4 milliseconds
97.54% <= 5 milliseconds
98.46% <= 6 milliseconds
98.96% <= 7 milliseconds
99.39% <= 8 milliseconds
99.65% <= 9 milliseconds
99.75% <= 10 milliseconds
99.79% <= 11 milliseconds
99.84% <= 12 milliseconds
99.93% <= 13 milliseconds
100.00% <= 13 milliseconds
28409.09 requests per second # 每秒处理28409.09个请求
====== GET ======
100000 requests completed in 3.66 seconds
100 parallel clients
3 bytes payload
keep alive: 1
12.60% <= 1 milliseconds
58.44% <= 2 milliseconds
88.63% <= 3 milliseconds
95.25% <= 4 milliseconds
98.29% <= 5 milliseconds
99.30% <= 6 milliseconds
99.74% <= 7 milliseconds
99.87% <= 8 milliseconds
99.92% <= 9 milliseconds
99.97% <= 10 milliseconds
99.99% <= 11 milliseconds
100.00% <= 11 milliseconds
27352.30 requests per second
====== INCR ======
100000 requests completed in 3.58 seconds
100 parallel clients
3 bytes payload
keep alive: 1
13.35% <= 1 milliseconds
60.68% <= 2 milliseconds
89.89% <= 3 milliseconds
95.75% <= 4 milliseconds
98.04% <= 5 milliseconds
99.12% <= 6 milliseconds
99.56% <= 7 milliseconds
99.77% <= 8 milliseconds
99.96% <= 9 milliseconds
100.00% <= 11 milliseconds
27948.57 requests per second
====== LPUSH ======
100000 requests completed in 3.80 seconds
100 parallel clients
3 bytes payload
keep alive: 1
8.99% <= 1 milliseconds
53.37% <= 2 milliseconds
83.58% <= 3 milliseconds
92.11% <= 4 milliseconds
96.14% <= 5 milliseconds
97.93% <= 6 milliseconds
98.61% <= 7 milliseconds
99.21% <= 8 milliseconds
99.43% <= 9 milliseconds
99.58% <= 10 milliseconds
99.72% <= 11 milliseconds
99.75% <= 12 milliseconds
99.79% <= 13 milliseconds
99.94% <= 14 milliseconds
99.98% <= 23 milliseconds
99.99% <= 24 milliseconds
100.00% <= 24 milliseconds
26336.58 requests per second
====== RPUSH ======
100000 requests completed in 3.45 seconds
100 parallel clients
3 bytes payload
keep alive: 1
10.00% <= 1 milliseconds
59.16% <= 2 milliseconds
87.40% <= 3 milliseconds
95.17% <= 4 milliseconds
98.35% <= 5 milliseconds
99.58% <= 6 milliseconds
99.89% <= 7 milliseconds
99.96% <= 8 milliseconds
100.00% <= 9 milliseconds
28943.56 requests per second
====== LPOP ======
100000 requests completed in 3.43 seconds
100 parallel clients
3 bytes payload
keep alive: 1
10.92% <= 1 milliseconds
61.29% <= 2 milliseconds
89.10% <= 3 milliseconds
95.38% <= 4 milliseconds
98.19% <= 5 milliseconds
99.09% <= 6 milliseconds
99.46% <= 7 milliseconds
99.72% <= 8 milliseconds
99.87% <= 9 milliseconds
99.91% <= 10 milliseconds
99.93% <= 11 milliseconds
99.97% <= 12 milliseconds
100.00% <= 12 milliseconds
29188.56 requests per second
====== RPOP ======
100000 requests completed in 3.62 seconds
100 parallel clients
3 bytes payload
keep alive: 1
10.62% <= 1 milliseconds
57.83% <= 2 milliseconds
87.53% <= 3 milliseconds
94.98% <= 4 milliseconds
98.00% <= 5 milliseconds
99.00% <= 6 milliseconds
99.43% <= 7 milliseconds
99.63% <= 8 milliseconds
99.74% <= 9 milliseconds
99.84% <= 10 milliseconds
99.97% <= 12 milliseconds
100.00% <= 13 milliseconds
100.00% <= 13 milliseconds
27631.94 requests per second
====== SADD ======
100000 requests completed in 3.73 seconds
100 parallel clients
3 bytes payload
keep alive: 1
12.88% <= 1 milliseconds
57.84% <= 2 milliseconds
87.81% <= 3 milliseconds
94.76% <= 4 milliseconds
97.73% <= 5 milliseconds
99.10% <= 6 milliseconds
99.55% <= 7 milliseconds
99.93% <= 8 milliseconds
99.99% <= 9 milliseconds
100.00% <= 9 milliseconds
26780.93 requests per second
====== HSET ======
100000 requests completed in 3.33 seconds
100 parallel clients
3 bytes payload
keep alive: 1
10.61% <= 1 milliseconds
61.88% <= 2 milliseconds
89.17% <= 3 milliseconds
95.59% <= 4 milliseconds
98.49% <= 5 milliseconds
99.27% <= 6 milliseconds
99.52% <= 7 milliseconds
99.73% <= 8 milliseconds
99.89% <= 9 milliseconds
99.95% <= 10 milliseconds
100.00% <= 10 milliseconds
30048.08 requests per second
====== SPOP ======
100000 requests completed in 3.72 seconds
100 parallel clients
3 bytes payload
keep alive: 1
13.82% <= 1 milliseconds
58.37% <= 2 milliseconds
88.10% <= 3 milliseconds
95.18% <= 4 milliseconds
98.27% <= 5 milliseconds
99.22% <= 6 milliseconds
99.54% <= 7 milliseconds
99.76% <= 8 milliseconds
99.86% <= 9 milliseconds
99.91% <= 10 milliseconds
99.91% <= 12 milliseconds
99.93% <= 13 milliseconds
99.98% <= 14 milliseconds
100.00% <= 14 milliseconds
26874.50 requests per second
====== LPUSH (needed to benchmark LRANGE) ======
100000 requests completed in 3.54 seconds
100 parallel clients
3 bytes payload
keep alive: 1
9.53% <= 1 milliseconds
57.85% <= 2 milliseconds
86.54% <= 3 milliseconds
94.24% <= 4 milliseconds
97.76% <= 5 milliseconds
98.97% <= 6 milliseconds
99.46% <= 7 milliseconds
99.68% <= 8 milliseconds
99.83% <= 9 milliseconds
99.95% <= 10 milliseconds
99.97% <= 11 milliseconds
99.99% <= 12 milliseconds
100.00% <= 12 milliseconds
28216.71 requests per second
====== LRANGE_100 (first 100 elements) ======
100000 requests completed in 8.71 seconds
100 parallel clients
3 bytes payload
keep alive: 1
0.03% <= 1 milliseconds
1.42% <= 2 milliseconds
9.72% <= 3 milliseconds
34.52% <= 4 milliseconds
56.78% <= 5 milliseconds
70.85% <= 6 milliseconds
81.12% <= 7 milliseconds
88.43% <= 8 milliseconds
92.43% <= 9 milliseconds
94.93% <= 10 milliseconds
96.62% <= 11 milliseconds
97.37% <= 12 milliseconds
98.06% <= 13 milliseconds
98.70% <= 14 milliseconds
98.99% <= 15 milliseconds
99.33% <= 16 milliseconds
99.54% <= 17 milliseconds
99.68% <= 18 milliseconds
99.74% <= 19 milliseconds
99.77% <= 20 milliseconds
99.81% <= 21 milliseconds
99.87% <= 22 milliseconds
99.91% <= 23 milliseconds
99.98% <= 24 milliseconds
99.99% <= 25 milliseconds
100.00% <= 25 milliseconds
11477.10 requests per second
====== LRANGE_300 (first 300 elements) ======
100000 requests completed in 21.69 seconds
100 parallel clients
3 bytes payload
keep alive: 1
0.00% <= 1 milliseconds
0.02% <= 2 milliseconds
0.15% <= 3 milliseconds
0.60% <= 4 milliseconds
1.38% <= 5 milliseconds
3.29% <= 6 milliseconds
5.18% <= 7 milliseconds
12.63% <= 8 milliseconds
26.50% <= 9 milliseconds
38.66% <= 10 milliseconds
50.44% <= 11 milliseconds
60.37% <= 12 milliseconds
67.37% <= 13 milliseconds
72.60% <= 14 milliseconds
77.28% <= 15 milliseconds
80.88% <= 16 milliseconds
84.17% <= 17 milliseconds
87.19% <= 18 milliseconds
89.60% <= 19 milliseconds
91.50% <= 20 milliseconds
92.98% <= 21 milliseconds
94.08% <= 22 milliseconds
94.93% <= 23 milliseconds
95.64% <= 24 milliseconds
96.32% <= 25 milliseconds
96.85% <= 26 milliseconds
97.32% <= 27 milliseconds
97.80% <= 28 milliseconds
98.24% <= 29 milliseconds
98.56% <= 30 milliseconds
98.82% <= 31 milliseconds
99.04% <= 32 milliseconds
99.22% <= 33 milliseconds
99.37% <= 34 milliseconds
99.55% <= 35 milliseconds
99.66% <= 36 milliseconds
99.71% <= 37 milliseconds
99.78% <= 38 milliseconds
99.81% <= 39 milliseconds
99.85% <= 40 milliseconds
99.86% <= 41 milliseconds
99.89% <= 42 milliseconds
99.91% <= 43 milliseconds
99.92% <= 44 milliseconds
99.94% <= 45 milliseconds
99.96% <= 46 milliseconds
100.00% <= 47 milliseconds
100.00% <= 48 milliseconds
100.00% <= 48 milliseconds
4611.06 requests per second
====== LRANGE_500 (first 450 elements) ======
100000 requests completed in 29.22 seconds
100 parallel clients
3 bytes payload
keep alive: 1
0.00% <= 2 milliseconds
0.01% <= 3 milliseconds
0.04% <= 4 milliseconds
0.14% <= 5 milliseconds
0.68% <= 6 milliseconds
1.35% <= 7 milliseconds
2.09% <= 8 milliseconds
3.07% <= 9 milliseconds
4.28% <= 10 milliseconds
6.97% <= 11 milliseconds
15.43% <= 12 milliseconds
27.24% <= 13 milliseconds
42.02% <= 14 milliseconds
55.51% <= 15 milliseconds
65.16% <= 16 milliseconds
71.48% <= 17 milliseconds
77.01% <= 18 milliseconds
81.26% <= 19 milliseconds
84.44% <= 20 milliseconds
87.14% <= 21 milliseconds
89.23% <= 22 milliseconds
91.06% <= 23 milliseconds
92.62% <= 24 milliseconds
93.96% <= 25 milliseconds
95.07% <= 26 milliseconds
95.89% <= 27 milliseconds
96.56% <= 28 milliseconds
97.18% <= 29 milliseconds
97.83% <= 30 milliseconds
98.23% <= 31 milliseconds
98.56% <= 32 milliseconds
98.82% <= 33 milliseconds
99.05% <= 34 milliseconds
99.32% <= 35 milliseconds
99.52% <= 36 milliseconds
99.63% <= 37 milliseconds
99.75% <= 38 milliseconds
99.82% <= 39 milliseconds
99.87% <= 40 milliseconds
99.90% <= 41 milliseconds
99.92% <= 42 milliseconds
99.94% <= 43 milliseconds
99.94% <= 44 milliseconds
99.96% <= 45 milliseconds
99.96% <= 46 milliseconds
99.97% <= 47 milliseconds
99.97% <= 48 milliseconds
99.98% <= 49 milliseconds
99.99% <= 50 milliseconds
99.99% <= 51 milliseconds
100.00% <= 52 milliseconds
100.00% <= 52 milliseconds
3422.08 requests per second
====== LRANGE_600 (first 600 elements) ======
100000 requests completed in 40.08 seconds
100 parallel clients
3 bytes payload
keep alive: 1
0.00% <= 1 milliseconds
0.00% <= 2 milliseconds
0.00% <= 3 milliseconds
0.01% <= 4 milliseconds
0.01% <= 5 milliseconds
0.21% <= 6 milliseconds
0.37% <= 7 milliseconds
0.54% <= 8 milliseconds
0.73% <= 9 milliseconds
0.94% <= 10 milliseconds
1.30% <= 11 milliseconds
1.69% <= 12 milliseconds
2.19% <= 13 milliseconds
3.12% <= 14 milliseconds
6.22% <= 15 milliseconds
13.49% <= 16 milliseconds
24.88% <= 17 milliseconds
36.22% <= 18 milliseconds
45.60% <= 19 milliseconds
53.41% <= 20 milliseconds
59.64% <= 21 milliseconds
64.26% <= 22 milliseconds
68.25% <= 23 milliseconds
71.69% <= 24 milliseconds
74.68% <= 25 milliseconds
77.29% <= 26 milliseconds
79.50% <= 27 milliseconds
81.57% <= 28 milliseconds
83.46% <= 29 milliseconds
85.17% <= 30 milliseconds
86.82% <= 31 milliseconds
88.37% <= 32 milliseconds
89.78% <= 33 milliseconds
91.00% <= 34 milliseconds
92.04% <= 35 milliseconds
92.90% <= 36 milliseconds
93.60% <= 37 milliseconds
94.25% <= 38 milliseconds
94.78% <= 39 milliseconds
95.26% <= 40 milliseconds
95.63% <= 41 milliseconds
95.96% <= 42 milliseconds
96.34% <= 43 milliseconds
96.66% <= 44 milliseconds
97.00% <= 45 milliseconds
97.28% <= 46 milliseconds
97.52% <= 47 milliseconds
97.77% <= 48 milliseconds
98.02% <= 49 milliseconds
98.22% <= 50 milliseconds
98.41% <= 51 milliseconds
98.57% <= 52 milliseconds
98.67% <= 53 milliseconds
98.76% <= 54 milliseconds
98.84% <= 55 milliseconds
98.91% <= 56 milliseconds
98.98% <= 57 milliseconds
99.07% <= 58 milliseconds
99.14% <= 59 milliseconds
99.21% <= 60 milliseconds
99.25% <= 61 milliseconds
99.29% <= 62 milliseconds
99.36% <= 63 milliseconds
99.40% <= 64 milliseconds
99.44% <= 65 milliseconds
99.46% <= 66 milliseconds
99.48% <= 67 milliseconds
99.50% <= 68 milliseconds
99.52% <= 69 milliseconds
99.55% <= 70 milliseconds
99.58% <= 71 milliseconds
99.61% <= 72 milliseconds
99.64% <= 73 milliseconds
99.64% <= 74 milliseconds
99.65% <= 75 milliseconds
99.67% <= 76 milliseconds
99.68% <= 77 milliseconds
99.70% <= 78 milliseconds
99.74% <= 79 milliseconds
99.75% <= 80 milliseconds
99.76% <= 81 milliseconds
99.81% <= 82 milliseconds
99.83% <= 83 milliseconds
99.84% <= 84 milliseconds
99.85% <= 85 milliseconds
99.88% <= 86 milliseconds
99.89% <= 87 milliseconds
99.90% <= 88 milliseconds
99.91% <= 89 milliseconds
99.92% <= 90 milliseconds
99.93% <= 91 milliseconds
99.93% <= 92 milliseconds
99.93% <= 93 milliseconds
99.94% <= 94 milliseconds
99.94% <= 95 milliseconds
99.94% <= 96 milliseconds
99.95% <= 97 milliseconds
99.96% <= 98 milliseconds
99.96% <= 100 milliseconds
99.97% <= 101 milliseconds
99.97% <= 108 milliseconds
99.97% <= 110 milliseconds
99.98% <= 111 milliseconds
99.99% <= 114 milliseconds
99.99% <= 115 milliseconds
99.99% <= 116 milliseconds
100.00% <= 117 milliseconds
100.00% <= 117 milliseconds
2494.95 requests per second
====== MSET (10 keys) ======
100000 requests completed in 5.53 seconds
100 parallel clients
3 bytes payload
keep alive: 1
0.03% <= 1 milliseconds
0.93% <= 2 milliseconds
3.07% <= 3 milliseconds
17.59% <= 4 milliseconds
59.78% <= 5 milliseconds
73.89% <= 6 milliseconds
83.32% <= 7 milliseconds
89.16% <= 8 milliseconds
92.73% <= 9 milliseconds
95.20% <= 10 milliseconds
96.49% <= 11 milliseconds
97.37% <= 12 milliseconds
98.47% <= 13 milliseconds
99.02% <= 14 milliseconds
99.26% <= 15 milliseconds
99.63% <= 16 milliseconds
99.82% <= 17 milliseconds
99.87% <= 18 milliseconds
99.87% <= 21 milliseconds
99.88% <= 22 milliseconds
99.88% <= 23 milliseconds
99.88% <= 24 milliseconds
99.89% <= 25 milliseconds
99.90% <= 33 milliseconds
99.90% <= 35 milliseconds
99.93% <= 36 milliseconds
99.99% <= 37 milliseconds
100.00% <= 37 milliseconds
18096.27 requests per second
2-4 Redis基础知识
- Redis默认有16个数据库,默认使用的是第0个数据库,可以使用
select
进行切换数据库
# 运行客户端后,可使用以下命令进行测试
select [index] # 切换到第 index 个数据库(0~15)
dbsize # 查看当前数据库存储空间(已经使用的空间???)
set [attr] [value]
get [key] # 不同db中的keys是不共享的
keys * # 查看db所有的key
flushdb # 清空当前db
flushall # 清空所有db
exists [key] # 判断某个属性是否存在;存在:1;不存在:0
move [key] [index] # 移动一个属性到第index个库
expire [key] [secends] # 设置一个属性secends秒之后过期 使用单点登录的时候可以用
ttl [key] # 判断key的剩余存活时间 单位是s;如果失效,会返回 -2
type [key] # 查看key的value类型
# 官网上有全部的命令和对应的例子
- Redis是单线程的
- Redis是很快的
- Redis是基于内存操作的,CPU并不是Redis的性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了
- Redis是由C语言编写的,官方提供的数据为100000+的QPS,完全不比同样使用key-value的Memcache差
Redis为什么单线程还这么快?
- 两个误区
- 高性能的服务器一定是多线程的
- 多线程(CPU上下文会切换)一定比单线程效率高
- 速度:CPU>内存>硬盘
核心:Redis是将所有的数据全部存放在内存中,所以说使用单线程去操作效率是最高的,多线程(CPU上下切换,比较耗时),对于内存系统来说,如果没有上下文切换效率就是最高的,多次读写都是在一个CPU上,在内存情况下,单线程就是最佳方案 (单核CPU下???)
3 五大数据类型
官网文档
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件MQ。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
String
大多数java程序员使用的是String
- 常用命令
# group 1:增加,求长 append strlen
set name qd # set [key] [value]
append name 123 # append [key] [append_value] 追加字符串
strlen name # strlen [key] 判断key的字符串长度
append name2 zhangsan # append [key] [value] 如果没有当前key,就相当于set name2 zhangsan
# group 2: 自增 自减 按照步长自增 按照步长自减 incr decr incrby decrby
set views 0 # set [key] [value]设置浏览量为0
incr views # incr [key] 给浏览量加一==》 1
decr views # decr [key] 给浏览量减一==》0,之后就不可以在自减了,会报error
incrby views 10 # incrby [key] [step] 自增步长:10
decrby views 10 # decrby [key] [step] 自减步长:10
# group 3:字符串范围 getrange [startIndex] [endIndex] 一般情况下,两者都大于0,且endIndex>startIndex
getrange name 0 3 # getrange [key] [startIndex] [endIndex] 按照范围取字符串:index的值从0开始,会从star取到end 若按照正常的数值,取到的字符串长度为end-star+1
getrange name 0 -1 #getrange [key] [startIndex] -1 从starIndex取到最后
#group 4:替换指定位置开始的字符串 setrange (相当于String中的replace)
setrange name 2 sub # setrange [key] [startIndex] [subString] 使用subString替代从statIndex开始的之后和subString相同长度的字符串;返回的为替代之后的长度
get name # 得到的为 lisubolu
# 示例2
setrange name 7 sub2
get name # 得到的为lisubolsub2
# group 5: setex(作用同expire) setnx
#setex (set with expire) 设置过期时间
#setnex (set if not exit) 不存在则设置(在分布式锁常常使用)
setex name 30 "hello" # setex [key] [expireTime] [value] 设置key存活时长为expireTime,设置值为value (若key不存在则创建)
setnx key1 "qd" # setnx [key] [value] 当key不存在的时候设置值为value;存在会创建失败:(设置成功会返回1,设置失败会返回0)
# group 6:批量设置mset mget msetex msetnx
mset k1 v1 k2 v2 k3 v3 # 批量设置(k1,v1),(k2,v2),(k3,v3) mset [key1] [value1] [key2] [value2] [key3] [value3] ... 存储的顺序是哈希算法设置的
mget k1 k2 # 批量获取 k1 k2... mget [key1] [key2] ...
msetnx k1 v1 k4 v4 # msetnx是一个原子性操作,要么一起成功,要么一起失败
# 进阶 使用对象
set user:1 {name:zhangsan,age:3} # 设置一个user:1对象 值为json字符串来保存一个对象
# 如何获取到单独的属性值????
mset user:1:name name1 user:1:age 2 # 批量设置对象属性 [object]:[id]:[field]
mget user:1:name user:1:age # 批量获取数据
# group 7:getset 先get再set
getset db redis # 返回(nil) 获取的是db之前的值,如果之前没有设置,则返回(nil),之后获取的值为当前设置的值(redis)
get db # 本次返回的redis
- String类似的场景:value除了是字符串也可以是数字
- 应用:计数器 统计多单位的数量 粉丝数 对象缓存存储
- 扩展:CAS:比较并交换
JRedis:java操作的客户端,这些命令都会成为方法
结构是相同的
List
- 基本的数据类型
- 在redis中,可以将list玩成栈、队列、阻塞队列
- 大部分list命令都是由
l
开头:除了lpush和rpush表示左右,其他的l都表示list - 基础命令
# group 1 插入 lpush rpush
lpush list one # 将一个值或者多个值,插入到列表头部(从左端插入:头插)
lpush list two
lpush list three
lrange list 0 -1 # 获取list中的值:输出为 three two one (没有rrange)
lrange list 0 1 # 通过区间获取具体的值
rpush list four # 将一个值或者多个值,插入到列表尾部(从右端插入:尾插)
lrange list 0 -1 # 得到的结果为:three two one four
# group 2 移除lpop rpop
lpop list # 向左移除一个元素,返回的是元素内容:three
rpop list # 向右移除一个元素,返回的是元素内容:four
# group 3 按照索引取值
lindex list 0 # 索引从0开始,-1代表取最后一个元素 没有rindex
# group 4 获取列表长度 llen
llen list # 返回列表长度
# group 5 移除指定值 count>0 移除count个(从前往后) count=0 移除所有 count<0移除count个(从后往前)
lrem list 0 one # 移除list中所有的one
lrem list 1 one # 移除list中的一个one
# group 6 截断操作
lpush list2 one two three four # 新的list:list2[one,two,three,four]
ltrim list2 1 2 # 截断:截断的时候两个参数是index(从0开始),会改变list
# group 7 rpoplpush:移出列表的最后一个元素,并将它放到一个新list中 旧的list可以和新的list是同一个
lpush list3 one two three four # 新的list:list3[one,two,three,four]
rpoplpush list3 list4 # "one"
lrange list3 0 -1 # 得到的结果为: four three two
lrange list4 0 -1 # 得到的结果为:one
# group 8 lset 给一个已经存在的list修改已经存在的index的值:相当于更新操作
lpush list5 one two three four # 新的list:list5[one,two,three,four]
exists list5 # 判断是否存在,返回0(不存在)或 1(存在)
lset list5 0 item # 将list5中的第0个元素设置为“item”,注意index的位置
# group 9 linsert 将某个具体的value插入到列表中某个元素的前面或后面
lpush list6 one one three four # 新的list:list6[one,one,three,four]
linsert list6 before one qd # 将qd插入到one前面:list6[qd,one,one,three,four]
linsert list6 after one qd2 # 将qd2插入到one后面:list6[qd,one,qd2,one,three,four]
# 如果有重复,会按照第一个为标准
小结:
- 实际上是一个链表,before node after,left,right都可以插入值
- 如果key不存在,则创建新的链表
- 如果key存在新增内容
- 如果移除了所有值,即空链表,也代表不存在
- 当在两边插入或者改动值的时候,效率最高;操作中间元素的时候相对效率会低一些
- 应用:消息排队,消息队列(lpush,rpop),栈(lpush,lpop)
Set 集合
- 无序不能重复值
- 基础命令
sadd set0 "one" "two" "three" "four" # set0集合中添加元素
smembers set0 # 查看set0的值
sismember set0 one # 判断set0中是否存在 one 元素
scard set0 #查看set0的元素个数
srem set0 one # 移除set0中的指定元素
srandmember set0 # 随机从set0中取元素,默认为取一个
srandmember set0 2 # 随机从set0中取两个元素
spop set0 # 随机移除set0中的一个元素;返回值为移除的值
spop set0 2 # 随机移除set0中的两个元素;返回值为移除的值
sadd set1 "hello" "123" "qd" # 创建set1
sadd set2 "hello2" "1232" "qd2" # 创建set2
smove set1 set2 "hello" # 将set1中的"hello" 移动到set2
# 差集sdiff 交集sunion 并集sinter
sadd key1 a b c # 创建key1
sadd key2 b c d # 创建key2
sdiff key1 key2 # 求key1与key2的差集
sinter key1 key2 # 求key1与key2的交集
sunion key1 key2 # 求key1与key2的并集
- 应用:微博,A用户将所有关注放在一个set中,将其粉丝放在一个集合中:可以求和其他用户的共同关注,共同爱好,二度好友(六度分割理论),推荐好友(六度分割理论)
Hash(哈希)
- 想成一个Map集合:key-value(map):此处的value是map的类型
- 基础命令
# group 1
hset myhash field1 lxl # 创建一个hash:myhash
hmset myhash field1 lxl field2 qd # 可以一次赋值多个(也可以用hset操作)
hget myhash field1 # 获取一个field的值
hmget myhash field1 field2 # 获取多个field的值
hgetall myhash # 获取全部的数据
# group 2
hdel myhash field1 # 删除hash指定的field,也会删除对应的value
hlen myhash # 查看hash中有多少对键值对
hexists myhash field1 # 判断hash中是否有对应的field 返回1或者0
# group 3 只获取key 只获取value
hkeys myhash # 获取所有的field
hvals myhash # 获取所有的value
# group 4 hincrby hsetnx
hset myhash field3 5 # 给myhash设置一个field3 值为5
hincrby myhash field3 2 # 使得myhash中的field3自增2(不可以省略步长)
hincrby myhash field3 -2 # 使得myhash中的field3自减2(不可以省略步长,没有hdecrby方法)
hsetnx myhash field4 hello # 如果不存在,则创建,存在则创建失败
- 应用:
- hash存储一些变更的数据: name age …,尤其是用户信息之类的经常变动的信息
- hash更实用于对象的存储,String更适合字符串存储
hset user:1 name qd age 20 # 设置id为1的用户的name age
hget user:1 name # 获取user:1的name
hmset user:1 name age # 获取user:1的name age
Zset(有序集合)
- 在set的基础上增加了一个值:set k1 v1 zset k1 score1 v1
- 有序集合底层数据结构是跳跃链表(常见面试考点)
- 基础命令
# score是可以重复的,元素值不重复
zadd myset 1 one # 创建zset 添加一个值
zadd myset 2 two 3 three # 一次添加多个值
# group 2 排序
zadd salary 2500 xiaohong
zadd salary 5000 zhangsan
zadd salary 500 qd
zrangebyscore salary -inf +inf # 显示所有用户,从小到大排序范围:[-inf,+inf] (前者<后者,不能相等),返回的值只有元素值,不带着score
# 使用zrevrangebyscore 可以实现从大到小排列,这时候传的值需要前者大于后者,同样不可以相等
zrangebyscore salary 500 5500
zrangebyscore salary -inf +inf withscores # 带着score
# 移除
zrem salary xiaohong # 移除一个元素 xiaohong,同时移除score
# 获取指定区间的成员数量
zcard salary # 获取有序集合元素中的个数
zcount salary 500 5500 # 统计薪资在[500,5500]的人数
- 应用:
- set排序 存储班级成绩表 工资表排序 排行榜
- 带权重进行判断
4 三种特殊数据类型
geospatial(地理位置)
- 朋友定位 附近的人 打车距离计算
- Redis的Geo在Redis3.2版本就出了,这个功能可以推算地理位置的信息,两地之间的距离,方圆n里的人等等
- 只有六个命令
有效经度:-180~180
有效维度:-85.05112878~85.05112878
# geoadd 添加地理位置 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中
# 规则:两级无法直接添加,一般会直接下载城市数据,然后通过java程序一次性导入
# 参数:key 经度 维度 名称
geoadd china:city 116.40 39.90 beijing # 添加城市
geoadd china:city 121.47 31.23 shanghai
geoadd china:city 160.50 29.53 chongqing
geoadd china:city 114.05 22.52 shenzhen
geoadd china:city 120.16 30.24 hangzhou 108
geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian # 一次添加多个城市
# geopos:从key里返回所有给定位元素的位置(经度和维度),是一个坐标值,得到的信息不一定是存储的数据
geopos china:city beijing # 获取存储的城市地理信息
geopos china:city beijing chongqing # 一次性获取多个
# geodist 返回给定两个地点的位置
# 如果其中一个不存在,则返回nil
# 指定单位:m km mi(英里) ft(英尺) 默认是m
geodist china:city beijing chongqing # 返回的是直线距离
geodist china:city beijing chongqing km # 指定单位
# georadius 以给定的经纬度为半径,找出某一半径内的元素
georadius china:city 110 30 1000 km # (110 30)为定位基准,1000 km为半径的大小,前提是china:city中含有这些城市
georadius china:city 110 30 1000 km withdist # 查出城市同时给出直线距离(显示直线距离)
georadius china:city 110 30 1000 km withcoord # 查出城市的同时查出经纬度(显示他人的定位信息)
georadius china:city 110 30 1000 km withdist withcoord count 3 # 查出城市的同时查出直线距离 经纬度 限定查询个数
# georadiusbymember:找出位于指定元素周围的其他元素
georadiusbymember china:city beijing 1000 km # 查找距离北京1000 km的城市
# geohash(了解)返回一个或多个位置元素的geohash表示(返回11个字符的Geohash字符串)
geohash china:city beijing # 将二维的经纬度转换为一维的字符串
geohash china:city beijing chongqing # 如果两个字符串越接近,则距离越近
- GEO底层的实现原理:Zset,可以使用Zset操作geo
zrange china:city 0 -1 # 查看地图中全部元素
zrem china:city beijing # 移除指定元素
hyperloglog
- 什么是基数:一个集合中不重复的元素的个数,可以接受误差(0.81%)
A{1,3,5,7,8,7} 基数:5
- Redis 2.8.9版本更新了Hyperloglog的数据结构
- Redis Hyperloglog是用来做基数统计的算法。 优点:占用的内存是固定的 12KB,若从内存角度来比较的话Hyperloglog为首选
- 应用:网页的UV(一个人访问一个网站多次还是算作一个人)
- 传统的方式:set保存用户的id,然后就可以统计set中的元素数量作为标准判断
- 这种方法如果保存大量的用户id会比较麻烦。我们的目的是为了计数而不是保存用户id
- 基本命令
pfadd myhyper a b c d e f g a b c # 创建一个hyperloglog
pfcount myhyper # 求基数,结果:7
pfadd myhyper j k l # 向Hyperloglog中添加元素
pfcount myhyper # 求基数,结果:10
pfadd myhyper2 a o p # 创建一个hyperloglog
pfmerge myhyperl3 myhyper myhyper2 # 合并myhyper和myhyper2为myhyper3
pfcount myhyper3 # 求基数,结果:12
如果允许容错Hyperloglog为首选
如果不允许容错,则使用set或自己的数据结构
bitmaps
bitmaps 和 hash 结合,就有了 布隆过滤器,用于解决缓存击穿问题
- 位存储;Bitmaps位图,是一种数据结构,都是操作二进制位来进行记录,只有0和1两个状态
- 基本命令
# 使用bitmap记录周一到周日的打卡,0为未打卡,1为打卡
setbit sign 0 1 #
setbit sign 1 0
setbit sign 2 0
setbit sign 3 1
setbit sign 4 1
setbit sign 5 0
setbit sign 6 0
# 查看是否打卡
getbit sign 3 # 查看周四是否打卡
getbit sign 6 # 查看周日是否打卡
# 统计打卡天数
bitcount sign # 不加范围,默认统计全部
- 应用:
- 统计疫情感染人数:0为未感染,1为感染
- 统计用户信息,活跃/不活跃,登录/不登录,打卡
- 其他两个状态的情况
to be continued…