一、Redis简介
为什么需要用redis
在大数据互联网环境下,网民用户迅速增加,系统访问量也越来越高,用户的体验要求也越来越高,因为传统的关系数据库是基于磁盘iol来做数据的读取和写入,在性能上无法已经无法支持当前的用户需求,那么我们的系统为了给用户提供更高的用户的体验,需要具备以下要求:
- 响应速度
- 海量数据,支持高并发
- 成本控制
而NoSql出现了,代表作为redis,具有高可用\高可扩\高并发等特性,能够更低成本来实现更好的用户体验。
Redis(Remote Dictionary Server )是基于内存的非关系型分布式数据库,内部的数据结构为Key-Value
什么是NOSQL,与传统RDBMS(Relational Database Management System)的区别
(Structured Query Language)关系型数据库指的是使用关系模型(二维表格模型)来组织数据的数据库,由(行和列)二维表及其之间的联系所组成的一个数据组织。如mysql、oracle、sql server; 优势:
- 支持通用的SQL(结构化查询语言)语句
- 支持事务,遵循事务的acid,保障数据的一致性
- 支持复杂查询
劣势: - 表结构格式固定,扩展性差
- 相对与nosql数据库,写入效率低下
非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,常见的数据类型有 键值、文档、图形、列簇
优势:
- 格式灵活
- 性能高:可基于硬盘或内存存储数据
- 扩展性强
- 成本低:开源软件,不收钱
劣势: - 学习成本高,每款nosql都可能有自己的语法
- 无事务控制,(mongodb除外)
- 结构复杂,很多sql不提供复杂查询
常用nosql举例
-
键值(Key-Value)数据库 Redis 适用的场景: 储存用户信息,比如会话、配置文件、参数、购物车等等。这些信息一般都和ID(键)挂钩,这种情景下键值数据库是个很好的选择。 缺点:Redis需要把数据存在内存中,这也大大限制了Redis可存储的数据量,不支持复杂查询 -
文档数据库 MongoDB(数据存储和管理服务) 在mongodb 4.2 中已支持分布式事务。MongoDB 通过二阶段提交的方式,实现在多个 分片 间发生的修改,要么同时发生,要么都不发生,保证事务的 ACID 特性。 适用的场景: mongodb适用于需求变化快,表结构变更频繁的场景,字段类型可以随时修改 游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新 物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。 -
elasticsearch(数据检索服务) elasticsearch更多适用于搜索和分析引擎,支持了复杂聚合查询,不适合做数据库,es会对所有字段做倒排索引 缺点: ES需要在创建字段前要预先建立Mapping(关系数据库中的schema表定义),Mapping中包含每个字段的类型信息,ES需要根据Mapping为字段建立合适的索引。由于这个Mapping的存在,ES中的字段一但建立就不能再修改类型了。你建的数据表的某个字段忘了加全文搜索,你想临时加上,但是表已经建好并且已经有很多数据了,那这个时候只能删除重建mapping。
适用的场景: ElasticSearch、Logstash 和 Kibana搭配来做日志的查询分析
-
列式数据库 hbase 适用的场景: 海量数据TB级数据存储,大数据查询,聊天消息,订单数据等 缺点:和redis一样,只能依赖rowkey做查询,不支持复杂查询 总结: -
对数据的读写要求极高,并数据规模不大,也不需要长期存储,选redis; -
数据规模较大,数据的读性能要求很高,数据表的结构需要经常变,有时还需要做一些聚合查询,选MongoDB; -
需要构造一个搜索引擎或者你想搞一个数据可视化平台,并且你的数据有一定的分析价值,选ElasticSearch; -
需要存储海量数据,不知道数据规模将来会增长多么大,那么选HBase。
什么叫分布式数据库
分布式数据库系统通常使用较小的计算机系统,每台计算机可单独放在一个地方,每台计算机中都可能有DBMS的一份完整拷贝副本,或者部分拷贝副本,并具有自己局部的数据库,位于不同地点的许多计算机通过网络互相连接,共同组成一个完整的、全局的逻辑上集中、物理上分布的大型数据库。
1 高可扩展性:分布式数据库必须具有高可扩展性,能够动态地增添存储节点以实现存储容量的线性扩展,数据分布存储在不同的节点上,在逻辑上数据统一。
2 高并发性:分布式数据库必须及时响应大规模用户的读/写请求,能对海量数据进行随机读/写。
3 高可用性:分布式数据库必须提供容错机制,能够实现对数据的冗余备份,保证数据和服务的高度可靠性。
Redis(多主多从)具有数据分片、副本集从集中数据库转化为分布式数据库
CAP理论 Consistency (一致性) 所有副本集在同一时间的数据完全一致,这就是分布式数据库的一致性
Availability (可用性) 服务一直可用,而且是正常响应时间
Partition Tolerance (分区容错性): 分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性或可用性的服务,分区容错性要求能够使应用虽然是一个分布式系统,而看上去却好像是在一个可以运转正常的整体,如现在的分布式系统中有某一个或者几个机器宕掉了,其他剩下的机器还能够正常运转
大部分分布式系统都需要在C\A中做取舍,而分布式数据最常见的例子是读写分离
Base 理论 BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网分布式系统实践的总结
- 基本可用(Basically Available)
假设系统,出现了不可预知的故障,但还是能用 -
- 响应时间上的损失:正常情况下的搜索引擎0.5秒即返回给用户结果,而基本可用的搜索引擎可以在2秒作用返回结果。
-
- 功能上的损失:在一个电商网站上,正常情况下,用户可以顺利完成每一笔订单。但是到了大促期间,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。
- 软状态(Soft State)
允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时 - 最终一致性(Eventually Consistent)
不可能一直是软状态,必须有个时间期限。在期限过后,应当保证所有副本保持数据一致性,从而达到数据的最终一致性
而Redis集群遵从base理论,允许副本存在数据延时,但最终数据要完成同步,主从保障基本可用
redis特性
-
高并发 所有数据都存储在内存中,相比于磁盘操作,具有更高的性能,能支持更多的并发量,读11w/s,写 8w/s,基于io多路复用模型 -
高可用 redis支持集群模式,多主多从,假如系统某一个master宕机,从节点也会继续提供服务 -
高可扩 redis集群的所有槽点数为16384个,创建集群时会分配相应的槽点,假如redis需要横向扩展,那么只需要给新加入的集群分配相应的槽点,然后完成数据迁移,在扩容的时候,整个集群仍然提供服务 -
数据多样性 相比于memcache只有string数据类型,redis具有更多的数据类型,如list,set,zset等 -
可持久化 redis提供rdb和aof两种持久化方式,假如redis发生宕机,也会保存数据的副本,避免数据的大批量丢失,假如redis配置了save属性,那么根据配置的时间,redis会fork一个子进程来保存当前数据副本。 -
原子性,支持lua脚本 redis因为是采用单线程模型来处理客户端连接的,所以单命令的操作具有原子性,假如一次要执行多条命令,可以使用lua脚本完成。
二、Redis的安装与配置文件介绍
安装
Redis压力测试
Redis自带一个性能测试工具:redis-benchmark。
系统的吞吐量是指系统的抗压、负载能力,指的是单位时间内处理的请求数量。 通常情况下,吞吐率用 “字节数/秒” 来衡量,也可以用 “请求数/秒”,“页面数/秒”,其实,不管是一个请求还是一个页面,本质都是网络上传输的数据,那么表示数据的单位就是字节数
QPS Queries Per Second,每秒查询数,即是每秒能够响应的查询次数,注意这里的查询是指用户发出请求到服务器做出响应成功的次数,简单理解可以认为查询=请求request TPS Transactions Per Second ,每秒处理的事务数。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数。 针对单接口而言,TPS可以认为是等价于QPS的,比如访问一个页面/index.html,是一个TPS,而访问/index.html页面可能请求了3次服务器比如css、js、index接口,产生了3个QPS。
响应时间RT Response Time,简单理解为系统从输入到输出的时间间隔,宽泛的来说,代表从客户端发起请求到服务端接收到请求并响应所有数据的时间差。一般取平均响应时间。
一般会采用P99.9值,也就是99.9%用户耗时作为指标,意思就是1000个用户里面,999个用户的耗时上限,通过测量与优化该值,就可保证绝大多数用户的使用体验。 至于P99.99值,优化成本过高,而且服务响应由于网络波动、系统抖动等不能解决之情况,因此大多数时候都不考虑该指标。
[root@VM-0-3-centos ~]# redis-benchmark --help
Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests>] [-k <boolean>]
-h <hostname> Server hostname (default 127.0.0.1)
-p <port> Server port (default 6379)
-s <socket> Server socket (overrides host and port)
-a <password> Password for Redis Auth
--user <username> Used to send ACL style 'AUTH username pass'. Needs -a.
-c <clients> Number of parallel connections (default 50)
-n <requests> Total number of requests (default 100000)
-d <size> Data size of SET/GET value in bytes (default 3)
--dbnum <db> SELECT the specified db number (default 0)
--threads <num> Enable multi-thread mode.
--cluster Enable cluster mode.
--enable-tracking Send CLIENT TRACKING on before starting benchmark.
-k <boolean> 1=keep alive 0=reconnect (default 1)
-r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD,
random members and scores for ZADD.
Using this option the benchmark will expand the string __rand_int__
inside an argument with a 12 digits number in the specified range
from 0 to keyspacelen-1. The substitution changes every time a command
is executed. Default tests use this to hit random keys in the
specified range.
-P <numreq> Pipeline <numreq> requests. Default 1 (no pipeline).
-q Quiet. Just show query/sec values
--precision Number of decimal places to display in latency output (default 0)
--csv Output in CSV format
-l Loop. Run the tests forever
-t <tests> Only run the comma separated list of tests. The test
names are the same as the ones produced as output.
-I Idle mode. Just open N idle connections and wait.
--help Output this help and exit.
--version Output version and exit.
Examples:
Run the benchmark with the default configuration against 127.0.0.1:6379:
$ redis-benchmark
Use 20 parallel clients, for a total of 100k requests, against 192.168.1.1:
$ redis-benchmark -h 192.168.1.1 -p 6379 -n 100000 -c 20
Fill 127.0.0.1:6379 with about 1 million keys only using the SET test:
$ redis-benchmark -t set -n 1000000 -r 100000000
Benchmark 127.0.0.1:6379 for a few commands producing CSV output:
$ redis-benchmark -t ping,set,get -n 100000 --csv
Benchmark a specific command line:
$ redis-benchmark -r 10000 -n 10000 eval 'return redis.call("ping")' 0
Fill a list with 10000 random elements:
$ redis-benchmark -r 10000 -n 10000 lpush mylist __rand_int__
On user specified command lines __rand_int__ is replaced with a random integer
with a range of values selected by the -r option.
redis-benchmark -n 100000
====== SET ======
100000 requests completed in 1.40 seconds
50 parallel clients
3 bytes payload
keep alive: 1
host configuration "save":
host configuration "appendonly": no
multi-thread: no
Latency by percentile distribution:
0.000% <= 0.175 milliseconds (cumulative count 1)
50.000% <= 0.431 milliseconds (cumulative count 51820)
75.000% <= 0.559 milliseconds (cumulative count 75600)
87.500% <= 0.687 milliseconds (cumulative count 87833)
93.750% <= 0.767 milliseconds (cumulative count 93888)
96.875% <= 0.815 milliseconds (cumulative count 97247)
98.438% <= 0.847 milliseconds (cumulative count 98575)
99.219% <= 0.887 milliseconds (cumulative count 99246)
99.609% <= 0.959 milliseconds (cumulative count 99615)
99.805% <= 1.175 milliseconds (cumulative count 99805)
99.902% <= 1.543 milliseconds (cumulative count 99903)
99.951% <= 3.247 milliseconds (cumulative count 99952)
99.976% <= 3.679 milliseconds (cumulative count 99976)
99.988% <= 8.063 milliseconds (cumulative count 99988)
99.994% <= 8.103 milliseconds (cumulative count 99994)
99.997% <= 8.159 milliseconds (cumulative count 99997)
99.998% <= 8.183 milliseconds (cumulative count 99999)
99.999% <= 8.207 milliseconds (cumulative count 100000)
100.000% <= 8.207 milliseconds (cumulative count 100000)
Cumulative distribution of latencies:
0.000% <= 0.103 milliseconds (cumulative count 0)
0.002% <= 0.207 milliseconds (cumulative count 2)
9.121% <= 0.303 milliseconds (cumulative count 9121)
45.394% <= 0.407 milliseconds (cumulative count 45394)
66.334% <= 0.503 milliseconds (cumulative count 66334)
81.275% <= 0.607 milliseconds (cumulative count 81275)
89.080% <= 0.703 milliseconds (cumulative count 89080)
96.683% <= 0.807 milliseconds (cumulative count 96683)
99.352% <= 0.903 milliseconds (cumulative count 99352)
99.718% <= 1.007 milliseconds (cumulative count 99718)
99.781% <= 1.103 milliseconds (cumulative count 99781)
99.819% <= 1.207 milliseconds (cumulative count 99819)
99.860% <= 1.303 milliseconds (cumulative count 99860)
99.882% <= 1.407 milliseconds (cumulative count 99882)
99.898% <= 1.503 milliseconds (cumulative count 99898)
99.912% <= 1.607 milliseconds (cumulative count 99912)
99.922% <= 1.703 milliseconds (cumulative count 99922)
99.930% <= 1.807 milliseconds (cumulative count 99930)
99.942% <= 3.103 milliseconds (cumulative count 99942)
99.980% <= 4.103 milliseconds (cumulative count 99980)
99.994% <= 8.103 milliseconds (cumulative count 99994)
100.000% <= 9.103 milliseconds (cumulative count 100000)
Summary:
throughput summary: 71326.68 requests per second
latency summary (msec):
avg min p50 p95 p99 max
0.475 0.168 0.431 0.791 0.871 8.207
三、Redis基本数据类型与命令介绍
四、Redis持久化
五、Redis主从复制
六、Redis集群
数据存储方式
Redis的存储采用数据分片的方式,也就是hash slot来存储数据,一个redis cluster 最多有16384个hash slot,存储在Redis Cluster中的所有键都会被映射到这些slot中,集群中的每个键都属于这16384个哈希槽中的一个。按照槽来进行分片,通过为每个节点指派不同数量的槽,可以控制不同节点负责的数据量和请求数.
哈希槽计算公式 集群使用公式slot=CRC16(key)/16384来计算key属于哪个槽,其中CRC16(key)语句用于计算key的CRC16 校验和。 而我们常用的java客户端如jedis 也是按照这个规则来获取相应节点的连接的
七、Redis发布订阅模型
八、Redis常见问题
Redis运行速度变慢
如果当前redis存储需要占用的内存超过了redis可使用的最大内存,操作系统会将不可用的数据或老旧数据放至swap区(windows也存在这种功能分区,叫虚拟内存),从而给redis腾出更多的运行内存,但swap分区实际是用硬盘实现的,所以读写效率远远无法跟内存比较,这时候redis的性能会受到极大影响
- 硬件手段,加内存
- 如果缓存数据较小,使用32位的redis实例,32实例数据结构只占64位数据的一半
- 设置key的过期时间,避免数据永久保存
- 使用hash结构数据存储数据
- 主动设置key回收策略,当内存不够时,执行回收
|