赞
踩
参考文献:https://baike.so.com/doc/5569749-5784951.html
在90年代,一个网站的访问量一般都不大,用单个数据库完全可以轻松应付。
在那个时候,更多的都是静态网页,动态交互类型的网站不多。
上述架构下,我们来看看数据存储的瓶颈是什么?
DAL : Data Access Layer(数据访问层 – Hibernate,MyBatis)
数据量的总大小一个机器放不下时。
数据的索引(B+ Tree)一个机器的内存放不下时。
访问量(读写混合)一个实例不能承受。
如果满足了上述1 or 3个时,只能对数据库的整体架构进行重构。
后来,随着访问量的上升,几乎大部分使用MySQL架构的网站在数据库上都开始出现了性能问题,web程序不再仅仅专注在功能上,同时也在追求性能。程序员们开始大量的使用缓存技术来缓解数据库的压力,优化数据库的结构和索引。开始比较流行的是通过文件缓存来缓解数据库压力,但是当访问量继续增大的时候,多台web机器通过文件缓存不能共享,大量的小文件缓存也带了了比较高的IO压力。在这个时候,Memcached就自然的成为一个非常时尚的技术产品。
Memcached作为一个独立的分布式的缓存服务器,为多个web服务器提供了一个共享的高性能缓存服务,在Memcached服务器上,又发展了根据hash算法来进行多台Memcached缓存服务的扩展,然后又出现了一致性hash来解决增加或减少缓存服务器导致重新hash带来的大量缓存失效的弊端。
由于数据库的写入压力增加,Memcached只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysql的master-slave模式成为这个时候的网站标配了。
在Memcached的高速缓存,MySQL的主从复制,读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,由于MyISAM在写数据的时候会使用表锁,在高并发写数据的情况下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。
同时,开始流行使用分表分库来缓解写压力和数据增长的扩展问题。这个时候,分表分库成了一个热门技术,是面试的热门问题也是业界讨论的热门技术问题。也就在这个时候,MySQL推出了还不太稳定的表分区,这也给技术实力一般的公司带来了希望。虽然MySQL推出了MySQL Cluster集群,但性能也不能很好满足互联网的要求,只是在高可靠性上提供了非常大的保证。
MySQL数据库也经常存储一些大文本字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库。比如1000万4KB大小的文本就接近40GB的大小,如果能把这些数据从MySQL省去,MySQL将变得非常的小。关系数据库很强大,但是它并不能很好的应付所有的应用场景。MySQL的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySQL的开发人员面临的问题。
最前面的是企业级防火墙,后面通过负载均衡主机(软负载:Nginx,硬负载:F5)在 web 服务器集群之间进行调度,再由具体的 web 服务器(Tomcat)去访问缓存,访问数据库。
今天我们可以通过第三方平台(如:Google,Facebook等)可以很容易的访问和抓取数据。用户的个人信息,社交网络,地理位置,用户生成的数据和用户操作日志已经成倍的增加。我们如果要对这些用户数据进行挖掘,那SQL数据库已经不适合这些应用了, NoSQL 数据库的发展却能很好的处理这些大的数据。
为了解决高并发,高可用,高扩展,大数据存储等一系列问题而产生的数据库解决方案,这就是NoSql.
NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。他不能代替关系型数据库只能作为关系型数据库的良好补充。
MongDB、 Redis、Memcached
该类数据库使用哈希表,在哈希表中包含特定的key和与其对应的指向特定数据的指针。常用的有Redis.
该类数据库主要用来应对分布式存储的海量数据,一个键指向了多个列。常用的有HBase。
该类数据库将结构化、半结构化的文档以特定格式存储,如json格式。一个文档相当于关系型数据库中的一条记录,也是处理信息的基本单位。常用的有MongoDB。
该类数据库使用图形理论来存储实体之间的关系信息,最主要的组成部分是:结点集、连接节点的关系。常用的有Neo4j,朋友圈社交网络,广告推荐!如脉脉。
非关系型数据库的特点:
1.数据模型比较简单。
2.对数据库性能的要求比较高
3.不需要高度的数据一致性
1.对数据库高并发读写的需求
2.对海量数据的高效率存储和访问的需求
3.对数据库的高可扩展性和高可用性的需求
1.高可扩展性 2. 分布式计算 3.低成本 4.架构的灵活性,半结构化数据
1. 没有标准化 2.有限的查询功能 3.最终一致是不直观的程序
NoSQL数据库的出现,弥补了关系数据(比如MySQL)在某些方面的不足,在某些方面能极大的节省开发成本和维护成本。
MySQL和NoSQL都有各自的特点和使用的应用场景,两者的紧密结合将会给web2.0的数据库发展带来新的思路。让关系数据库关注在关系上,NoSQL关注在存储上。
Mysql主从读写分离
由于数据库的写入压力增加,Memcached只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysql的master-slave模式成为这个时候的网站标配了。
当前主流的关系型数据库:使用表结构存储,易于维护
Oracle、DB2、Microsoft SQL Server、Microsoft Access、MySQL等。
1.易于维护:都是使用表结构,格式一致;
2.使用方便:SQL语言通用,可用于复杂查询;
3.支持SQL,可以进行Join等复杂查询,可用于一个表以及多个表之间非常复杂的查询。
4.事务支持使得对于安全性能很高的数据访问要求得以实现。
1. 读写性能比较差,尤其是海量数据的高效率读写;
2. 表格固定,灵活性差
存储方式多,数据可分散存储,减少对服务器的压力
NoSql、Cloudant。
临时性键值存储(memcached、Redis)、永久性键值存储(ROMA、Redis)、面向文档的数据库(MongoDB、CouchDB)、面向列的数据库(Cassandra、HBase)
1.格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等。使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
2.速度快:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘;
3.高扩展性,基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
4.易于数据的分散,分布式数据库
5.成本低,使用开源数据库。
1. 不提供关系型数据库对事物的处理。
2. 基本上不提供复杂事物的处理,弥补关系型数据库的不足。
1、下载安装包:https://github.com/dmajkic/redis/releases2、下载完毕得到压缩包:3、解压到自
己电脑上的环境目录下的就可以的!Redis十分的小,只有5M 4、开启Redis,双击运行服务即可!
使用redis客户单来来连接redis!
1、安装编译环境 yum install gcc-c++
2、上传源码包到linux 服务器上;我已经上传到了root目录下:
/opt/software/redis-5.0.5.tar.gz
3、make
这里可以直接make是因为redis已经自己写好了make fifile了;也就是说不用再执行confifigure了、
make后编译好的文件会保存到src目录下
4、make install
这一步会把src目录下的二进制文件复制到/usr/local/bin/目录下;由于把文件保存到/usr/local/bin/目
录下的方式不方便管理,于是我们把文件统一保存到
tar -xzvf redis-5.0.5.tar.gz cd /opt/software/redis-5.0.5 make ll 总用量 196 -rw-rw-r-- 1 root root 75147 8月 2 17:00 00-RELEASENOTES -rw-rw-r-- 1 root root 53 8月 2 17:00 BUGS -rw-rw-r-- 1 root root 1805 8月 2 17:00 CONTRIBUTING -rw-rw-r-- 1 root root 1487 8月 2 17:00 COPYING drwxrwxr-x 7 root root 4096 9月 17 18:38 deps -rw-rw-r-- 1 root root 11 8月 2 17:00 INSTALL -rw-rw-r-- 1 root root 151 8月 2 17:00 Makefile -rw-rw-r-- 1 root root 4223 8月 2 17:00 MANIFESTO -rw-rw-r-- 1 root root 6834 8月 2 17:00 README.md -rw-rw-r-- 1 root root 46695 8月 2 17:00 redis.conf -rwxrwxr-x 1 root root 271 8月 2 17:00 runtest -rwxrwxr-x 1 root root 280 8月 2 17:00 runtest-cluster -rwxrwxr-x 1 root root 281 8月 2 17:00 runtest-sentinel -rw-rw-r-- 1 root root 7109 8月 2 17:00 sentinel.conf drwxrwxr-x 2 root root 4096 9月 17 18:39 src drwxrwxr-x 10 root root 4096 8月 2 17:00 tests drwxrwxr-x 7 root root 4096 8月 2 17:00 utils/usr/local/redis/bin/目录下 mkdir -p /usr/local/redis/bin/ cd src cp redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server redis-trib.rb /usr/local/redis/bin/ 可以和一起 make & make install
5、修改环境变量
export PATH=/usr/local/redis/bin:$PATH
6、启动redis
redis-server
7、启动客户端
redis-cli
注意:
这样启动后有限制
1、启动服务时,会导致页面卡住,所以需要配置后启动。
2、其他ip地址无法访问,要放开权限。
3、阿里云不安全,需要设置一个密码,这就牵扯到修改配置文件
7、将配置文件也移动至该目录
cp /opt/software/redis-5.0.5/redis.conf /usr/local/redis/bin/
8、修改配置文件
protected-mode no
bind 0.0.0.0
//后台
daemonize yes
//找到这个选项,放开注射
requirepass hch123
9、启动
cd /usr/local/redis/bin
./redis-server redis.conf
测试性能****
redis-benchmark是一个压力测试工具! 官方自带的性能测试工具!
如何查看这些分析呢?#测试:100个并发连接100000请求redis-benchmark -h localhost -p 6379 -c
100 -n 100000
====== MSET (10 keys) ======
100000 requests completed in 1.45 seconds
100 parallel clients
3 bytes payload
keep alive: 1
66.73% <= 1 milliseconds
99.47% <= 2 milliseconds
99.99% <= 3 milliseconds
100.00% <= 3 milliseconds
68965.52 requests per second
****REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统。即远程字典服务。
Redis是一个开源的使用ANSI C语言编写的非关系型数据库、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API,可以用作数据库、缓存、消息中间件。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。
是将数据先放在内存,然后写入磁盘指定位置。
所谓的单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程。
redis采用多路复用机制:即多个网络socket复用一个io线程,实际是单个线程通过记录跟踪每一个Sock(I/O流)的状态来同时管理多个I/O流.
可以减轻数据库压力,查询内存比查询数据库效率高。
token存储、session共享、分布式锁、自增id、验证码,消息列队,发布订阅等。
1.性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
2.数据类型丰富,支持五大数据类型的存储
3.保证操作的原子性,支持事务
4.Redis支持数据的备份,即master-slave模式的数据备份是将数据先放在内存,然后写入磁盘指定位置。
5.将数据放在内存中是为了提高读写的一个速度,用内存作为权衡 平衡数据和硬盘之间的数据大小,不能超过硬盘大小。另一个特点就是内存操作简单,redis可以操作一些内部复杂性很强的事情
持久化功能:将储存在内存里面的数据保存到硬盘里面,保障数据安全,方便进行数据备份和恢复。
发布与订阅功能:将消息同时分发给多个客户端,用于构建广播系统。
过期键功能:为键设置一个过期时间,让它在指定的时间之后自动被删除。
事务功能:原子地执行多个操作,并提供乐观锁功能,保证处理数据时的安全性。
脚本功能:在服务器端原子地执行多个操作,完成复杂的功能,并减少客户端与服务器之间的通信往返次数。
复制:为指定的 Redis 服务器创建一个或多个复制品,用于提升数据安全性,并分担读请求的负载。
哨兵Sentinel:监控 Redis 服务器的状态,并在服务器发生故障时,进行自动故障转移。
集群:创建分布式数据库,每个服务器分别执行一部分写操作和读操作。
1.Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
2.Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
3.Redis支持数据的备份,即master-slave模式的数据备份。
1.Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。
2.Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。
Redis是以单线程的形式处理指令的
Redis默认有16个数据库 默认使用第0个
简单命令:key
添加: set key value
获取:get key
切换数据库: select 第几个数据库
清楚当前数据库: flushdb
清空全部数据库的内容:flushall
获取所有的key: keys *
设置key的过期时间,单位为秒: expire key 10
查看当前key的剩余时间: ttl key
查看该key是否存在: exists key
移除当前key :move key
查看这个key类型: type age
硬盘:顺序读取 内 存:随机读取 硬盘的读取速度要小于内存
1.查看指定类型中的命令: help @String
2.自增命令: incr key (每次+1)
3.自增自定义命令: incrby key 5 (在原有的基础上增加5)
4.自减命令:decr key
5.自减自定义: decrby key 5 (在原有的基础上减少5次)
6.例如:文章阅读量,抖音点赞,微博热搜
7.在指定键值对中追加 append key 追加内容
8.查找自定字符串(截取字符串) :getrange key start end
9.修改指定值: getset key 值
10.一次性添加多个键值对: mset key value key value (遵循事务的原子性,要么都成功要么都失败)
11.一次性查找多个键值对: mget key key (遵循事务的原子性,要么都成功要么都失败)
12.添加时查看是否存在这个键值对 如果存在 不更改 不存在 更改:setnx key value
13.修改指定值中的部分从位移开始:setrange key 3 ddddd 从下标为3开始修改
14.设置过期时间:set key value ex 秒 set key value px 毫秒
String常用的几个命令 : set get mset mget setnx incr
计数器:如文章阅读数、粉丝数。INCR本身就具有原子性特性,所以不会有线程安全问题
验证码:通过设置key的过期时间来销毁过期的验证码,和业务系统解耦。
存储对象: 如用户基本信息json{“id”:“1”,“username”:“name”}
bitmap位图:如签到、打卡等场景统计
分布式锁:用过string类型的setnx命令“当key不存在时,设值并返回1,当key已经存在时,不设值并返回0”,“判断key是否存在”和“设值”两个操作是原子性地执行的,因此可以用string类型作为分布式锁,返回1表示获得锁,返回0表示没有获得锁。
1. LPUSH key value:左入队 (进) 从左边添加进去
2. LPOP key:左出队 (出) 从list最前边出去
3. RPUSH key value:右入队 (进) 从右边添加进去
4. RPOP key:右出队 (出 ) 从list最后边出
5. LLEN key:获取list的长度 一个对象代表一个长度
6. RPOPLPUSH key key1 :右出左进 有一个list中弹到另一个list中
7. Linsert key before value new 在指定键中的某个值前 插入一个值
8. Lpushx key value 先判断key是否存在,如存在在指定key左边进入
9. Lrange key start stop 在指定key中 从第几个值拿到第几个
10. Lrem key count value 指定key中删除值
11. Ltrim key start stop 在指定key中 以下标的形式从第几个存到第几个,其余的都删除
常用的list命令:Lpush Lpop Rpush Rpop Lrange Llen Ltrim
左进右出 (队列,先进先出) 在已有的数据前添加
左进左出(栈)
1、消息队列(例如微信朋友圈)
list类型的lpop和rpush (或者反过来,Ipush和rpop) 能实现队列的功能,故而可以用Redis的list类型实现简单的点对点的消息队列。不过我不推荐在实战中这么使用,因为现在已经有Kafka. NSQ、 RabbitMQ等成熟的消息队列了,它们的功能已经很完善了,除非是为了更深入地理解消息队列
2.最新列表(例如评论)
list类型的lpush命令和lrange命令能实现最新列表的功能,每次通过lpush命令往列表里插入新的元素,然后通过lrange命令读取最新的元索列表,如朋友圈的点赞列表、评论列表。
3.链表常用来做异步队列使用
将需要延后处理的任务结构体序列化(JSON)成字符串塞进 Redis 的列表
另一个线程从这个列表中轮询数据进行处理。
lpush + lpop = stack 先进后出的栈
lpush + rpop = queue 先进先出的队列
lpush + ltrim = capped collection 有限集合
lpush + brpop = message queue 消息队列
1. SADD key member [member …] 向集合 xxx 中添加元素 m
2. SCARD key 获取集合 xxx 中 元素个数
3. SREM key member [member …] 删除集合xxx中的元素 m0
4. SMEMBERS key 查看集合 xxx 中所有元素
5. SISMEMBER key member 检测元素m2是否存在于 集合 xxx中
6. SRANDMEMBER key [count] 在集合中随机读取一个元素
7.SPOP key [count] 随机获取一个元素(并删除)(抽奖)
8. SDIFF key [key …] 查找 后者key中 前者key未拥有的值 (差集)(可能认识的人,推荐)
9. SDIFFSTORE destination key [key …] 存储后者key中的未拥有的值
10. SINTER key [key …] 两个key中共同存在的值
11. sunion hou liu 查找前者跟后者中共同拥有的值
在微博中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合,redis还为集合提供了交集,并集,差集等操作。可以非常方便的实现:共同关注 功能 推荐好友
Spop抽奖小程序
Map集合,key-map时候这个值是一个map集合!本质和String类型没有太大的区别,还是一个简单的key-value!
hash特别适用于存储对象(应为对象可能会包含很多属性),特别是对象中有字段经常被修改
1. hset key field val 设置 hash的 值
2.hmset key field1 val1 field2 val2 … 设置多个值
3.hget key field2 取出 hash中的 field2字段的值
4.hmget key field1 field2 … 取出hash中多个字段的值
5.hgetall key 获取 hash中所有的键值
6.hdel key field5 删除 hash 中 field5字段
7.hincrby key fieldx n hash中的 fieldx字段的值 +n
8.hexists key field7 判断 field7字段是否存在
9.hlen key 获取 hash中字段的个数
10.hkeys field 获取所有的键
Hash应用场景 电商购物车
以用户id为key
商品id为field
3)商品数量为value
购物车的操作
1) 添加商品 hset cart:1001 100088 1
2) 增加数量 hincreby cart:1001 100088 1
3) 商品总数 hlen cart:1001 10088
删除商品 hdel cart:1001 10088
获取购物车列表 hgetall cart:1001
1.zadd sset n m1 向有序集合 sset中添加分值为n的元素 m1
2.zrange sset 0 -1 [withsocres] 【正序】查看有序集合中所有元素[分数]
3.zrevrange sset 0 -1 [withsocres] 【倒序】查看有序集合中所有元素[分数]
4.zrem sset xxx 删除有序集合 sset中的 元素xxx
5.zrank sset xxx 获取有序集合中元素xxx的索引值(从0开始)
6.zscore sset xxx 获取有序集合 sset中 xxx的分值
7.zcard sset 获取有序集合 sset中 元素个数
8.zcount sset x y 统计分值 在 x与y之间的元素个数
9.zincrby sset x m1 增加sset中元素 m1的分值x
10.zpopmax sset 弹出sset中分值最大的元素
11.zpopmin sset 弹出sset总分支最小的元素
12.zrangebyscore sset x y 查看分值在x与y之间的元素
排行榜!!!
销量排名、积分排名、成绩排名等…
1. 发表时间作为score存储,这样子获取的时候就是自动排好序的
2. 成绩作为score
3. 带权重队列,让重要的任务优先执行
1. 用户签到
2. 用户在线状态
3. 统计活跃用户
4. 各种状态值
5. 自定义布隆过滤器
6. 点赞功能
对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
SETBIT key offset value
offset 参数必须大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。
对 key 所储存的字符串值,获取指定偏移量上的位(bit)。
GETBIT key offset
计算给定字符串中,被设置为 1 的比特位的数量。
BITCOUNT key
返回位图中第一个值为 bit 的二进制位的位置。
BITPOS key bit [start] [end]
对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
BITOP operation destkey key [key …]
operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种
BITOP AND destkey key [key …] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。
bitfield 有三个子指令,分别是 get/set/incrby,它们都可以对指定位片段进行读写,但是最多只能处理 64 个连续的位,如果超过 64 位,就得使用多个子指令,bitfield 可以一次执行多个子指令。
1. GEOADD key longitude latitude member [longitude latitude member …] 增加某个地理位置的坐标;
2.GEOPOS key member [member …] 获取某个地理位置的坐标;
3.GEODIST key member1 member2 [unit] 获取两个地理位置的距离;
m 表示单位为米。
km 表示单位为千米。
mi 表示单位为英里。
ft 表示单位为英尺
4.GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count] 根据给定地理位置坐标获取指定范围内的地理位置集合;
5.GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count] 根据给定地理位置获取指定范围内的地理位置集合;
6.GEOHASH key member [member …] 获取某个地理位置的geohash值。
LBS(Location Based Service)基于位置的服务,它是通过电信移动运营商的无线电通讯网络(如GSM网、CDMA网)或外部定位方式(如GPS)获取移动终端用户的位置信息(地理坐标,或大地坐标)
常见的有,附近的位置,附近的人,摇一摇,获取两点之间的距离等等
默认自动开启 文件存储在src目录
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过
程 都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作
的。
保存的文件是dump.rdb都是在我们的配置文件中快照中进行配置的!
执行机制:快照,直接将databases中的key-value的二进制形式存储在了rdb文件中
**优点:**性能较高(因为是快照,且执行频率比aof低,而且rdb文件中直接存储的是key-values的二进制形式,对于恢复数据也快)
使用单独子进程来进行持久化,主进程不会进行任何IO操作,保证了redis的高性能
**缺点:**在save配置条件之间若发生宕机,此间的数据会丢失
RDB是间隔一段时间进行持久化,如果持久化之间redis发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
**存储:**自动的持久化数据存储到dump.rdb后。实际只要重启redis服务即可完成(启动redis的server时会从dump.rdb中先同步数据)
以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件,但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日
志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。aof保存的是appendonly.aof文件
**执行机制:**将对数据的每一条修改命令追加到aof文件
**优点:**数据不容易丢失
可以保持更高的数据完整性,如果设置追加file的时间是1s,如果redis发生故障,最多会丢失1s的数据;且如果日志写入不完整支持redis-check-aof来进行日志修复;AOF文件没被rewrite之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的flushall)
**缺点:**性能较低(每一条修改操作都要追加到aof文件,执行频率较RDB要高,而且aof文件中存储的是命令,对于恢复数据来讲需要逐行执行命令,所以恢复慢)
AOF文件比RDB文件大,且恢复速度慢。
Redis 事务可以一次执行多个命令,批量操作在发送 EXEC 命令前被放入队列缓存。收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。所以事务不具备回滚性
事务具备一致性指的是,如果数据库在执行事务之前是一致的,那么在事务执行之后,无论事务是否成功,数据库也应该是一致的。
从 Redis 来说可以从 2 个层面看,一个是执行错误是否有确保一致性,另一个是宕机时,Redis 是否有确保一致性的机制。
加上业务去谈一致性,例如,A 转账给 B,A 减少 10 块钱,B 增加 10 块钱,因为 Redis 并不具备回滚,也就不具备传统意义上的原子性,所以 Redis 也应该不具备传统的一致性。
隔离性指的是,数据库中有多个事务并发的执行,各个事务之间不会相互影响,并且在并发状态下执行的事务和串行执行的事务产生的结果是完全相同的。
Redis 因为是单线程操作,所以在隔离性上有天生的隔离机制,当 Redis 执行事务时,Redis 的服务端保证在执行事务期间不会对事务进行中断,所以,Redis 事务总是以串行的方式运行,事务也具备隔离性。
事务的持久性指的是,当一个事务执行完毕,执行这个事务所得到的结果被保存在持久化的存储中,即使服务器在事务执行完成后停机了,执行的事务的结果也不会被丢失。
Redis 是否具备持久化,这个取决于 Redis 的持久化模式:
纯内存运行,不具备持久化,服务一旦停机,所有数据将丢失。
RDB 模式,取决于 RDB 策略,只有在满足策略才会执行 Bgsave,异步执行并不能保证 Redis 具备持久化。
AOF 模式,只有将 appendfsync 设置为 always,程序才会在执行命令同步保存到磁盘,这个模式下,Redis 具备持久化。(将 appendfsync 设置为 always,只是在理论上持久化可行,但一般不会这么操作)
Redis 具备了一定的原子性,但不支持回滚。
Redis 不具备 ACID 中一致性的概念。(或者说 Redis 在设计时就无视这点)
Redis 具备隔离性。
Redis 通过一定策略可以保证持久性。
在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。具体步骤是:
1)先删除缓存
2)再写数据库
3)休眠500毫秒(根据具体的业务时间来定)可以将1秒内所造成的缓存脏数据,再次删除。(为何是1秒?需要评估自己的项目的读数据业务逻辑的耗时。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。当然这种策略还要考虑redis和数据库主从同步的耗时
4)再次删除缓存。
那么,这个500毫秒怎么确定的,具体该休眠多久呢?
需要评估自己的项目的读数据业务逻辑的耗时。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。
当然,这种策略还要考虑 redis 和数据库主从同步的耗时。最后的写数据的休眠时间:则在读数据业务逻辑的耗时的基础上,加上几百ms即可。比如:休眠1秒。
从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。所有的写操作以数据库为准,只要到达缓存过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存
结合双删策略+缓存超时设置,这样最差的情况就是在超时时间内数据存在不一致,而且又增加了写请求的耗时。
引入MQ异步更新缓存(队列)
方案(一)
流程如下所示
(1)更新数据库数据;
(2)缓存因为种种问题删除失败
(3)将需要删除的key发送至消息队列
(4)自己消费消息,获得需要删除的key
(5)继续重试删除操作,直到成功
然而,该方案有一个缺点,对业务线代码造成大量的侵入。于是有了方案二,在方案二中,启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。
随着web2.0的进一步发展,网民的生产力进一步提升,存储总量开始增加。 此时虽然仍然是读多写少的模式,但写入量已经大大提升。 原有的缓存技术不能缓解写入压力,而且原有的空间也受硬盘限制,因此开始出现分库分表,实现读写分离。 集中模式的数据库就这样开始逐渐分化:由一个集中的、稳定的、强关系的结构,朝一个分化的、容错的、弱关系的结构发展。 数据的存储空间与数据访问时间也进一步分离。 即原来是数据存在什么地方,就去什么地方访问。现在是数据还是存在老地方(硬盘),但是访问却在另一个地方(比如内存,或另一个服务器)。其目的,就在于缩短IO路径或分离IO,实现高效访问。
一主二仆 A(B、C) 一个Master两个Slave
薪火相传(去中心化)A - B - C ,B既是主节点(C的主节点),又是从节点(A的从节点)
反客为主(主节点down掉后,手动操作升级从节点为主节点) & 哨兵模式(主节点down掉后,自动升级从节点为主节点)
一主二从设计
三台linux准备好,也可以一台机子搭建伪分布式,使用不同端口,怎么修改端口自己查
主redis 101.200.48.99 从redis 39.97.162.205 从redis 39.106.113.48
在3台linux都装好redis,参考: Redis单机安装
方式1:修改配置文件
启动时,服务器读取配置文件,并自动成为指定服务器的从服务器,从而构成主从复制的关系
在从机器上修改从redis的配置,其他(默认配置)配置略过
slaveof 101.200.48.99 6379
masterauth 123456
重启从服务器
ps -ef| grep redis
kill -9 -进程码
关闭防火墙
systemctl stop firewalld
将redis依次启动
登录主redis客户端
[root@iZ2ze6e6cscvpn6upi9p8vZ bin]# ./redis-cli -a 123456 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6379> info replication \# Replication role:master connected_slaves:2 slave0:ip=39.106.113.48,port=6379,state=online,offset=168,lag=1 slave1:ip=39.97.162.205,port=6379,state=online,offset=154,lag=1 master_replid:e341f44d2e365650e9e94738c79c92dcd7d27cc5 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:168 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:168
向主redis写入数据,flushall清空数据,避免干扰
127.0.0.1:6379> set name hhhh
OK
从redis都可以读到数据库
127.0.0.1:6379> get name "hhhh"
向从redis写入数据失败,默认slave-read-only yes,如果为no则可以向从写数据
127.0.0.1:6379> set age 12
(error) READONLY You can't write against a read only replica.
方式2:启动命令添加
./redis-server --slaveof 101.200.48.99 6379 --masterauth 123456
在启动redis时指定当前服务成为某个主Redis服务的从Slave
手动容灾处理
当Master服务出现故障,需手动将slave中的一个提升为master, 剩下的slave挂至新的master上(冷
处理:机器挂掉了,再处理)
命令:
将主redis关闭
将39.97.162.205从redis提升为主redis
slaveof no one,将一台slave服务器提升为Master (提升某slave为master) slaveof 39.97.162.205 6379(将slave挂至新的master上)
3**、哨兵模式**
主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工
**干预,费事费力,还会造成一段时间内服务不可用。**这不是一种推荐的方式,更多时候,我们优先考虑
哨兵模式。
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会
独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
127.0.0.1:6379> set name zhangnan
OK
127.0.0.1:6379> get name
“zhangnan”
127.0.0.1:6379> set age 12
(error) READONLY You can’t write against a read only replica.
./redis-server --slaveof 101.200.48.99 6379 --masterauth zn123
1、数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
2、故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务 的冗余
3、负载均衡:在主从复制的基础上,配合读写 分离,可以由主节点提供写服务,由从节点提供读服务 (即写Redis数据时应用连接主节点,读Redis数 据时应用连接从节点),分担服务器负载;尤其是在写 少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
4、高可用(集群)基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复 制是Redis高可用的基础。
1.从数据库向主数据库发送了sync(数据同步)命令
2.主数据库接收同步命令后,会保存快照,创建一个RDB文件。
3.当主数据库执行完保持快照后,会向从数据库发送RDB文件,而从数据库会接收并载入该文件
4.主数据库将缓存区的所有写命令发给从服务执行
5.以上处理完之后,之后主数据库每执行一条命令,都会将被执行的写命令发送给从数据库
注意:在Redis
在高并发的环境下,查询一个不存在的数据,缓存不会被命中,需要从mysql数据库查询,查不到数据则不写入缓存,这会导致这个不存在的数据每次请求都会到数据库去查询,攻击数据库,造成缓存穿透,例如:活动系统里查询一个不存在的活动
2.直接缓存NULL值
应对缓存穿透最有效的方法是直接缓存NULL值,但是缓存NULL的时间不能太长,否则NULL数据长时间得不到更新,也不能太短,否则达不到防止缓存击穿的效果。浪费空间。
3.限流
应对缓存穿透的常用方法之一是限流,常见的限流算法有滑动窗口,令牌桶算法和漏桶算法,或者直接使用队列、加锁等,在layering-cache里面我主要使用分布式锁来做限流
4.布隆过滤器
优点:简单,方便集成,空间效率、查询时间远超一般算法
缺点:容错性、不能很好支持大数据(费内存,不能横向扩展)
在高并发下,对一个特定的值进行查询,但是这个时候缓存正好过期了,缓存没有命中,导致大量请求 直接落到数据库上,如活动系统里面查询活动信息,但是在活动进行过程中活动缓存突然过期了。
一般利用分布式锁–mutex。访问热点数据的线程,如果没有在缓存层获取到数据,只有一个可以获取到一把互斥锁,有资格访问存储层,然后将数据缓存到缓存层。其它需要睡眠等待后重新访问缓存层热点数据。
在高并发下,大量的缓存key在同一时间失效,导致大量的请求落到数据库上,导致CPU或内存负载过高,如活动系统里面同时进行着非常多的活动,但是在某个时间点所有的活动缓存全部过期。如redis直接宕机。
1.redis集群大面积故障
2.缓存失效,但依然大量请求访问缓存服务redis
3.redsi大量失效后,大量请求转向到mysql数据库
4.mysql的调用量暴增,很快就扛不住 ,甚至直接宕机
5.由于大量的应用服务依赖mysql和redis的服务,,这时候就很快会演变成各服务器的集群雪崩,最后网站彻底崩溃。
1.缓存的高可用性
缓存层设计成高可用,防止缓存大面积故障。即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务,例如Redis Sentinel和Redis Cluster都实现了高可用。
2.缓存降级
可以利用ehcache等本地缓存(时支持),但主要还是对源服务访问进行限流资源隔离(熔断)、降级等。当访问量剧增、服务出现问题仍然需要保证服务还是可用的。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级,这里会涉及到运维的配合。
3.Redis备份和快速预热
1)Redis数据备份和恢复
2)快速缓存预热
4.提前演练
最后,建议还是在项目上线前,演练缓存层宕掉后,应用以及后端的负载情况以及可能出现的问题,对高可用提前预演,提前发现问题。
5.设置随机失效时间
设置不同的key,不同的过期时间,如设置1~5分钟的随机数。
6.缓存预热
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。
这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
解决思路
1、直接写个缓存刷新页面,上线时手工操作下;
2、数据量不大,可以在项目启动的时候自动进行加载;
目的就是在系统上线前,将数据加载到缓存中。
用途:判断大量数据中某个URL是否存在
Redis 官方提供的布隆过滤器到了 Redis 4.0 提供了插件功能之后才正式登场。布隆过滤器作为一个插件加载到 Redis Server 中,给 Redis 提供了强大的布隆去重功能。
布隆过滤器有二个基本指令,bf.add
添加元素,bf.exists
查询元素是否存在,它的用法和 set 集合的 sadd 和 sismember 差不多。注意bf.add
只能一次添加一个元素,如果想要一次添加多个,就需要用到bf.madd
指令。同样如果需要一次查询多个元素是否存在,就需要用到bf.mexists
指令。
127.0.0.1:6379> bf.add codehole user1 (integer) 1 127.0.0.1:6379> bf.add codehole user2 (integer) 1 127.0.0.1:6379> bf.add codehole user3 (integer) 1 127.0.0.1:6379> bf.exists codehole user1 (integer) 1 127.0.0.1:6379> bf.exists codehole user2 (integer) 1 127.0.0.1:6379> bf.exists codehole user3 (integer) 1 127.0.0.1:6379> bf.exists codehole user4 (integer) 0 127.0.0.1:6379> bf.madd codehole user4 user5 user6 (integer) 1 (integer) 1 (integer) 1 127.0.0.1:6379> bf.mexists codehole user4 user5 user6 user7 (integer) 1 (integer) 1 (integer) 1 (integer) 0
我们上面使用的布隆过滤器只是默认参数的布隆过滤器,它在我们第一次 add 的时候自动创建。Redis 其实还提供了自定义参数的布隆过滤器,需要我们在 add 之前使用bf.reserve
指令显式创建。如果对应的 key 已经存在,bf.reserve
会报错。bf.reserve
有三个参数,分别是 key,error_rate
和initial_size
。错误率越低,需要的空间越大。initial_size
参数表示预计放入的元素数量,当实际数量超出这个数值时,误判率会上升。
所以需要提前设置一个较大的数值避免超出导致误判率升高。如果不使用 bf.reserve,默认的error_rate
是 0.01,默认的initial_size
是 100。
1、相互排斥,即任一时刻,只能有一个客户端持有锁;
2、无死锁,持有锁的客户端宕机或网络延迟下仍可获取锁;
3、有始有终,一个客户端加了锁,只能自己释放锁,当然也不能被其他客户端解锁;
4、容错性,只要大部分redis节点还存活,那么客户端就应该可以正常加锁和释放锁;
谈到Redis服务器的高可用,如何保证备份的机器是原始服务器的完整备份呢?
这时候就需要哨兵和复制。
哨兵(Sentinel) :可以管理多个Redis服务器,它提供了监控,提醒以及自动的故障转移的功能。
复制(Replication) :则是负责让一个Redis服务器可以配备多个备份的服务器。
Redis正是利用这两个功能来保证Redis的高可用。
什么是哨兵?
哨兵是Redis集群架构中非常重要的一个组件,哨兵的出现主要是解决了主从复制出现故障时需要人为干预的问题。
(1)集群监控:负责监控Redis master和slave进程是否正常工作
(2)消息通知:如果某个Redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
(3)故障转移:如果master node挂掉了,会自动转移到slave node上
(4)配置中心:如果故障转移发生了,通知client客户端新的master地址
**主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。**这不是一种推荐的方式,更多时候,我们优先考虑
哨兵模式。
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。****
1.哨兵机制建立了多个哨兵节点(进程),共同监控数据节点的运行状况。
2.同时哨兵节点之间也互相通信,交换对主从节点的监控状况。
3.每隔1秒每个哨兵会向整个集群: Master主服务器+Slave从服务器+其他Sentinel (哨兵)进程,发送一次ping命令做一次心跳检测。
通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服
务器,修改配置文件,让它们切换主机。
故障切换(failover)
这个就是哨兵用来判断节点是否正常的重要依据,涉及两个新的概念:主观下线和客观下线。
1.主观下线:一个哨兵节点判定主节点down掉是主观下线。
2.客观下线:只有半数哨兵节点都主观判定主节点down掉,此时多个哨兵节点交换主观判定结果,才会判定主节点客观下线。
3.原理:基本上哪个哨兵节点最先判断出这个主节点客观下线,就会在各个哨兵节点中发起投票机制Raft算法(选举算法) ,最终被投为领导者的哨兵节点完成主从自动化切换的过程。
把哨兵配置文件拷贝一下方便使用
cp/root/redis5.0.5/sentinel.conf /usr/local/redis/bin/
vi sentinel.conf
#修改内容
#监控哪一个主服务器 1代表票数
sentinel monitor mymaster 192.168.0.222 6379 1
#设置哨兵监控主服务器密码
sentinel auth-pass mymaster 123456
#打开注释,取消保护机制
protected-mode no
配置3个哨兵和1主2从的Redis服务器来演示这个过程。
多哨兵监控Redis
首先配置Redis的主从服务器,修改redis.conf文件如下
# 使得Redis服务器可以跨网络访问
bind 0.0.0.0
# 设置密码
requirepass 123456
# 指定主服务器,注意:有关slaveof的配置只是配置从服务器,主服务器不需要配置
slaveof 101.200.48.99 6379
# 主服务器密码,注意:有关slaveof的配置只是配置从服务器,主服务器不需要配置
masterauth 123456上述内容主要是配置Redis服务器,从服务器比主服务器多一个slaveof的配置和密码。
配置3个哨兵,每个哨兵的配置都是一样的。在Redis安装目录下有一个sentinel.conf文件,copy一份进行修改
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
下图展示了频道 channel1 ,以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时,这个消息就会被发送给订阅它的三个客户端:
1.开启本地 Redis 服务,开启两个 redis-cli 客户端。
2.在第一个 redis-cli 客户端输入 SUBSCRIBE runoobChat,意思是订阅 runoobChat 频道。
3.在第二个 redis-cli 客户端输入 PUBLISH runoobChat “Redis PUBLISH test” 往 runoobChat 频道发送消息,这个时候在第一个 redis-cli 客户端就会看到由第二个 redis-cli 客户端发送的测试消息。
下表列出了 redis 发布订阅常用命令:
序号 | 命令及描述 |
---|---|
1 | PSUBSCRIBE pattern [pattern …] 订阅一个或多个符合给定模式的频道。 |
2 | PUBSUB subcommand [argument [argument …]] 查看订阅与发布系统状态。 |
3 | PUBLISH channel message 将信息发送到指定的频道。 |
4 | PUNSUBSCRIBE [pattern [pattern …]] 退订所有给定模式的频道。 |
5 | SUBSCRIBE channel [channel …] 订阅给定的一个或多个频道的信息。 |
6 | UNSUBSCRIBE [channel [channel …]] 指退订给定的频道。 |
在设置键的过期时间的同时,创建一个定时任务. 让定时任务在键的过期时间来临时,立即执行对键的删除操作。
放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。
每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。
Mysql里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
从数据集(server.db[i].dict)中任意选择数据淘汰
禁止驱逐数据
注意这里的 6 种机制,volatile 和 allkeys 规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据,后面的 lru、ttl 以及 random 是三种不同的淘汰策略,再加上一种 no-enviction 永不回收的策略。
1、如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率
低,则使用 allkeys-lru
2、如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用
allkeys-random
参考文献:https://blog.csdn.net/JinXYan/article/details/99449934
https://blog.csdn.net/weixin_45099622/article/details/107497957
Redis是一个响应式的服务,当客户端发送一个请求后,就处于阻塞状态等待Redis返回结果。这样一次命令消耗的时间就包括四个部分:请求从客户端到服务器的时间、命令排队的时间和命令真正执行时间、结果从服务器到客户端的时间,第一个和第四个消耗的时间总和称为RTT(Round Trip Time),当客户端与服务器存在网络延时时,RTT就可能会很大,这样就会导致性能问题。
管道(Pipeline)就是为了改善这个情况的,利用管道,客户端可以一次性发送多个请求而不用等待服务器的响应,待所有命令都发送完后再一次性读取服务的响应,这样可以极大的降低RTT时间从而提升性能。需要注意到是用pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并不是打包的命令越多越好。
Redis是一种基于客户端-服务端模型(C/S模型)
以及请求/响应协议
的TCP服务。
这意味着通常情况下一个请求会遵循以下步骤:
redis命令执行流程
1.发送请求
2.命令排队
3.执行命令
4.返回结果
1+4=往返时延(RTT)
所谓RTT(Round-Trip Time),就是往返时延,在计算机网络中它是一个重要的性能指标,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。
为了解决这个问题,Redis支持通过管道,来达到减少RTT的目的。
1、Redis提供了批量操作命令,如mget,mset,但有些命令不支持批量操作,如果有一个场景需要批量操作某些key,假如有1000个,在我们没有使用批量操作时所需要的时间是1000次RTT时间+1000次命令执行时间:
2、使用pipeline操作一次传递命令时,所需要的时间是1次RTT时间+1000次命令执行时间:
当管道中累计了大量请求以后,CUP使用率迅速升到了100%,这是非常危险的操作。
对于监听队列的场景,一个简单的做法是当发现队列返回的内容为空的时候,就让线程休眠几秒钟,等队列中累积了一定量数据以后再通过管道去取,这样就既能享受管道带来的高性能,又避免了CPU使用率过高的风险。
Thread.currentThread().sleep(10 * 1000);
read()
和write()
系统调用,减少客户端与服务器之间的通信次数,节约时间read()
系统调用读取许多命令,而通过单个系统调用传递多个答复write()
。因此,每秒执行的总查询数最初会随着管道较长而线性增加,最后会趋近于不使用管道的10倍。Memcached 是一个开源的,高性能的内存绶存软件,从名称上看 Mem 就是内存的意思,而 Cache 就是缓存的意思。Memcached 的作用:通过在事先规划好的内存空间中临时绶存数据库中的各类数据,以达到减少业务对数据库的直接高并发访问,从而达到提升数据库的访问性能,加速网站集群动态应用服务的能力。
1、Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 list,set,zset,hash 等数据结的存储。而 memcache 只支持简单数据类型,需要客户端自己处理复杂对象
2、Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用(PS:持久化在 rdb、aof)。
3、由于 Memcache 没有持久化机制,因此宕机所有缓存数据失效。Redis 配置为持久化,宕机重启后,将自动加载宕机时刻的数据到缓存系统中。具有更好的灾备机制。
4、Memcache 可以使用 Magent 在客户端进行一致性 hash 做分布式。Redis 支持在服务器端做分布式(PS:Twemproxy/Codis/Redis-cluster 多种分布式实现方式)
5、Memcached 的简单限制就是键(key)和 Value 的限制。最大键长为 250 个字符。可以接受的储存数据不能超过 1MB(可修改配置文件变大),因为这是典 型 slab 的最大值,不适合虚拟机使用。而 Redis 的 value长度支持到 512mb。
6、Redis 使用的是单线程模型,保证了数据按顺序提交。Memcache 需要使用 cas 保证数据一致性。CAS(Check and Set)是一个确保并发一致性的机制,属于“乐观锁”范畴;原理很简单:拿版本号,操作,对比版本号,如果一致就操作,不一致就放弃任何操作cpu 利用。由于 Redis 只使用单核,而 Memcached 可以使用多核,所以平均每一个核上 Redis 在存储小数据时比 Memcached 性能更 高。而在 100k 以上的数据中,Memcached 性能要高于 Redis 。
7、memcache 内存管理:使用 Slab Allocation。原理相当简单,预先分配一系列大小固定的组,然后根据数据大小选择最合适的块存储。避免了内存碎片。(缺点:不能变长,浪费了一定空间)memcached 默认情况下下一个 slab 的最大值为前一个的 1.25 倍。
8、redis 内存管理: Redis 通过定义一个数组来记录所有的内存分配情况, Redis采用的是包装的 malloc/free,相较于 Memcached 的内存 管理方法来说,要简单很多。由于 malloc 首先以链表的方式搜索已管理的内存中可用的空间分配,导 致内存碎片比较多
1、Memcached 所有的值均是简单的字符串,redis 作为其替代者,支持更为丰
富的数据类
2、Redis 的速度比 Memcached 快很
3、Redis 可以持久化其数据
1、Master 最好不要写内存快照,如果 Master 写内存快照,save 命令调度 rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务
2、如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一
3、为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网
4、尽量避免在压力很大的主库上增加从
5、主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1<- Slave2 <- Slave3…这样的结构方便解决单点故障问题,实现 Slave 对 Master的替换。如果 Master 挂了,可以立刻启用 Slave1 做 Master,其他不变。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。