赞
踩
成功呈概率分布,关键是你能不能坚持到成功开始呈现的那一刻
在我们日常的Java Web开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题,可是一旦涉及大量数据的请求,比如主页访问量瞬间较大的时候,数据库操作数据会因为面向磁盘,磁盘读/写速度比较慢的问题而存在严重的性能弊端,一瞬间成千上万的请求到来,需要系统在极短的时间内完成成千上万次的读/写操作,这个时候往往不是数据库能够承受的,极其容易造成数据库系统瘫痪,最终导致服务器宕机,造成严重后果。
为了解决上述问题,减轻数据库负担,Redis 应运而生,Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库, 是一款高性能的 NoSQL 系列的非关系型数据库, 是一种基于内存的数据库, 并且提供一定的持久化功能。 它的性能十分优越,可以支持每秒十几万次的读/写操作,其性能远超数据库,并且还支持 集群、分布式、主从同步 等配置,原则上可以无限扩展,让更多的数据存储在内存中,更让人称赞的是它还 支持一定的事务能力,这保证了高并发的场景下数据的安全和一致性 。
目前为止Redis支持的键值数据类型如下:
1) 字符串类型 string
2) 哈希类型 hash
3) 列表类型 list
4) 集合类型 set
5) 有序集合类型 sortedset
相比于其他数据库类型,Redis具备的特点是:
1)C/S通讯模型
2)单进程单线程模型
3)丰富的数据类型
4)操作具有原子性
5)持久化
6)高并发读写
7)支持lua脚本
小贴士: NoSQL(NoSQL = Not Only SQL),意即 “不仅仅是SQL”,是一项全新的数据库理念,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。
成本 | nosql数据库简单易部署,基本都是开源软件,不需要像使用oracle那样花费大量成本购买使用,相比关系型数据库价格便宜。 |
---|---|
查询速度 | nosql数据库将数据存储于缓存之中,关系型数据库将数据存储在硬盘中,自然查询速度远不及nosql数据库。 |
存储数据的格式 | nosql基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL层的解析,所以性能非常高。存储格式是 key,value形式 、文档形式、图片形式 等等,所以可以存储基础类型以及对象或者是集合等各种格式,而数据库则只支持基础类型。 |
扩展性 | 关系型数据库有类似join这样的多表查询机制的限制导致扩展很艰难。 |
1)维护的工具和资料有限,因为nosql是属于新的技术,不能和关系型数据库10几年的技术同日而语。
2)不提供对sql的支持,如果不支持sql这样的工业标准,将产生一定用户的学习和使用成本。
3)不提供关系型数据库对事务的处理。
关系型数据库与NoSQL数据库并非对立而是互补的关系,即通常情况下使用关系型数据库,在适合使用NoSQL的时候使用NoSQL数据库,让NoSQL数据库对关系型数据库的不足进行弥补。一般会将数据存储在关系型数据库中,在nosql数据库中备份存储关系型数据库的数据
储存类型 | 相关产品 | 典型应用 | 数据模型 | 优势 | 劣势 |
---|---|---|---|---|---|
键值(Key-Value)存储数据库 | Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB | 内容缓存,主要用于处理大量数据的高访问负载 | 一系列键值对 | 快速查询 | 存储的数据缺少结构化 |
列存储数据库 | Cassandra, HBase, Riak | 分布式的文件系统 | 以列簇式存储,将同一列数据存在一起 | 查找速度快,可扩展性强,更容易进行分布式扩展 | 功能相对局限 |
文档型数据库 | CouchDB、MongoDB | Web应用(与Key-Value类似,Value是结构化的) | 一系列键值对 | 数据结构要求不严格 | 查询性能不高,而且缺乏统一的查询语法 |
图形(Graph)数据库 | Neo4J、InfoGrid、Infinite Graph | 社交网络 | 图结构 | 利用图结构相关算法 | 需要对整个图做计算才能得出结果,不容易做分布式的集群方案 |
• 缓存(数据查询、短连接、新闻内容、商品内容等等)
• 聊天室的在线好友列表
• 任务队列(秒杀、抢购、12306等等)
• 应用排行榜
• 网站访问统计
• 数据过期处理(可以精确到毫秒
• 分布式集群架构中的session分离
• Redis 在 Java Web 主要有两个应用场景:1. 存储 缓存 用的数据;2. 需要高速读/写的场合使用它快速读/写。
缓存就是数据交换的缓冲区(称作:Cache),当某一硬件要读取数据时,会首先从缓存汇总查询数据,有则直接执行,不存在时从内存中获取。由于缓存的数据比内存快的多,所以缓存的作用就是帮助硬件更快的运行。
缓存往往使用的是RAM(断电既掉的非永久存储),所以在用完后还是会把文件送到硬盘等存储器中永久存储。电脑中最大缓存就是内存条,硬盘上也有16M或者32M的缓存。
高速缓存是用来协调CPU与主存之间存取速度的差异而设置的。一般CPU工作速度高,但内存的工作速度相对较低,为了解决这个问题,通常使用高速缓存,高速缓存的存取速度介于CPU与主存之间。系统将一些CPU在最近几个时间段经常访问的内容存在高速缓存,这样就在一定程度上缓解了由于主存速度低造成的CPU“停工待料”的情况。
缓存就是把一些外存上的数据保存在内存上而已,为什么保存在内存上,我们运行的所有程序里面的变量都是存放在内存中的,所以如果想将值放入内存上,可以通过变量的方式存储。在JAVA中一些缓存一般都是通过Map集合来实现的。
缓存在不同的场景下,作用是不一样的具体举例说明:
✔ 操作系统磁盘缓存 ——> 减少磁盘机械操作。
✔ 数据库缓存——>减少文件系统IO。
✔ 应用程序缓存——>减少对数据库的查询。
✔ Web服务器缓存——>减少应用服务器请求。
✔ 客户端浏览器缓存——>减少对网站的访问。
摘自: 什么是缓存,缓存策略有哪些?
中文网:http://www.redis.net.cn/ (建议这里下载,官网加载比较慢)
解压直接可以使用:
redis.windows.conf
:配置文件redis-cli.exe
:redis 客户端redis-server.exe
:redis 服务器端目录结构:
小贴士: value值可加引号,也可不加, 前面说了 value值都是 String 类型,故加不加在redis都是String型,java 读取数据,有时需要类型转化, 比如: Integer.parseint(age)
创建数据命令: set key value
例: ( set username “xxw” )
获取值: get key
例: ( get username )
查看过期时间: ttl key
例: ( ttl username ) , -1 表示永久(key 存在,但没有设置剩余生存时间) , -2 表示 不存在
设置过期时间: expire key seconds
例: (expire key 10086)
给已有的值追加新值:append key value
小贴士: redis 里面所有的 value,都是字符串类型的。
设置多个 key-value: mset key value key value . . .
例:(mset username “xxw” password “123456”)
获取多个 key-value:mget key key . . .
例:(mget username password )
删除key-value: del key
例: (del username)
是一个键值(key=>value)对集合。是string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象, field 域, value 值
创建数据命令; hset key field value
例:(hset user username “xxw”)
将field-value设置到hash表中,若key不存在会新建hash表再赋值,已存在则会覆盖
创建多个数据命令; hmset key field value [field value]
例:(hmset user username “xxw” age 19 sex male)
获取值: hget key field
例: (hget user username)
获取多个值: hmget key field field
例: (hmget user username age sex)
删除值: hdel key field
例: (hdel user username)
获取全部 field-value : hgetall key
例: (hgetall user)
获取所有的field: hkeys key
例:(hkeys user)
获取所有的value: hvals key
例: (hvals user)
获取field的个数: hlen key
例: (hlen user)
List类型是一个字符串列表,可以在列头或列尾添加/删除数据,在插入数据时,如果该键不存在,redis将为该键创建一个。
添加数据:左压栈 lpush key value
例: (lpush my_list a b c );右压栈 rpush key value
例:(rpush my_list a b c )
查看数据: lrange key start stop
查看索引范围内元素的值, 查看所有:lrange my_list 0 -1
,查看位于index 位置上的元素 ,返回列表中元素的值。index从0开始,当index超出索引时返回null: lindex key index
, 例: (lindex my_list 0 2)
获得list的元素个数: llen key
例: (llen my_list)
修改数据: 指定索引号进行修改 lset key index value
( 第一个value index = 0 ) , 例: (lset my_list 2 d)
出栈(删除)数据:
lpop 删除左边第一个 lpop key
例: (lpop my_list);
rpop 删除右边第一个 rpop key
例: (rpop my_list);
lrem 删除指定 lrem key count value
元素为string类型, 无序集合元素, 具有唯一性,不重复
创建数据: sadd key value [value]
(唯一,无序),将一个或多个member元素加入到集合key中,若 member 已存在那么会忽略此元素, 例: (sadd my_set a b c d e f a)
获取元素: smembers key
例: (smembers my_set)
删除元素: srem key value
例: (srem my_set c)
随机删除元素: spop key
例: (spop my_set)返回被删除的值
移动一个集合的值到另一个集合: smove oldkey newkey member
例: (smove my_set test_set b)
判断集合存在某个值: sismember key value
例: (sismember my_set a,sismember my_set c )
两个set 集合交集: sinter key1 key2 ..
例: (sinter my_set test_set)
把 key1 key2 的交集合并到newkey: sinterstore newkey key1 key2
例: (sinterstore new_set my_set test_set)
两个set集合的并集: sunion key1 key2 ...
例: (sunion my_set test_set)
把 key1 key2的并集合并到 newkey: sunionstore newkey key1 key2
例: (sunionstore new_set1 my_set test_set)
两个set集合的差集:(操作一上面类似,不展示操作), sdiff key1 key2
例: (sdiff my_set test_set)
把 key1 key2的差集合并到newkey: (操作一上面类似,不展示操作), sdiffstore newkey key1 key2
, 例:(sdiffstore new_set2 my_set test_set)
获取集合个数: scard key
例: (scard my_set)
随机返回一个元素: srandmember key
例:( srandmember my_set)
不允许重复元素,且元素有顺序.每个元素都会关联一个double类型的分数 (Score) 。redis正是通过分数来为集合中的成员进行从小到大的排序, 成员是唯一的,但分数(score)却可以重复
创建数据: zadd key score member
例: (看图)
获取元素:
zrange正序 : zrange key start stop (withscores )
带上withscores 即连同分数一起输出 , 例: (zrange my_zset 0 -1 withscores)
zrevrange倒序: zrevrange key start stop (withscores )
, 例: (zrevrange my_zset 0 -1 withscores)
删除元素: zrem key member
例: (zrem my_zset two)
查询元素索引:
zrank key member
例: (zrank my_zset three)zrevrank key member
例: (zrevrank my_zset three)以下操作就不做演示了:
查看有序集合元素数: zcard key
例: (zcard my_zset)
返回集合中 score 在给定区间的元素 : zrangebyscore my_zset 0 -1 withscores
例: (zrangebyscore my_zset 2 3 withscores) 返回了 score 在 2~3 区间的元素
返回集合中 score 在给定区间的数量: zcount key min max
例:(zcount my_zset 2 3)
查看score值: zscore key member
例: (zscore my_zset two)
删除集合中排名在给定区间的元素(正向): zremrangebyrank my_zset 0 -1 withscores
例: (zremrangebyrank my_zset 1 3)
删除集合中 score 在给定区间的元素: zrange my_zset 0 -1 withscores
例: (zremrangebyscore my_zset 3 5)
4.3.6、 通用命令:
keys *
: 查询所有的键
type key
: 获取键对应的value的类型
del key
:删除指定的key value
以上都是redis 基础常用命令操作,更多高端操作请前往官方文档进行学习 -> redis 开发文档
Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为 “半持久化模式”);也可以把每一次数据变化都写入到一个append only file(aof)里面(这称为 “全持久化模式” )
由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。
redis提供两种方式进行持久化:
- RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化)
- AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)
RDB(时间点快照)持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
以下截图摘自:彻底搞懂Redis持久化之RDB原理
AOF(追加)持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作都会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
持久类型 | 优点 |
---|---|
RDB | 1. 整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美,可自定义归档备份周期;2.对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。3.性能最大化,对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。 |
AOF | 1. 该机制可以带来更高的数据安全性,即数据持久性,Redis中提供了3种同步策略,即每秒同步、每修改同步和不同步,就算服务器宕机,那么也就这一秒的数据将会丢失,造成影响较小; 2.由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。 3. 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性 |
持久类型 | 缺点 |
---|---|
RDB | 1. 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。2. 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟 |
AOF | 1. 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快 ; 2. 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效 |
关于二者选择的标准: 看自己意愿,是牺牲性能换取更高缓存一致性(AOF),还是愿意追求性能,定时备份(RDB)
RDB持久化配置:
Redis会将数据集的快照dump到 dump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息
save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。
AOF持久化配置:
在Redis的配置文件中存在三种同步方式,它们分别是:
appendfsync always #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync no #从不同步。高效但是数据不会被持久化。
AOF 持久化开启
事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。 例如:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。
Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
三特性: 一次性、顺序性、排他性
隔离级别:
批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的更新,事务外查询不能看到。
Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。
命令 | 解释 |
---|---|
MULTI | 开启事务,redis会将后续的命令逐个放入队列中,然后使用EXEC命令来原子化执行这个命令系列 |
EXEC | 执行事务中的所有操作命令 |
DISCARD | 取消事务,放弃执行事务块中的所有命令 |
WATCH | 监视一个或多个key,如果事务在执行前,这个key(或多个key)被其他命令修改,则事务被中断,不会执行事务中的任何命令 |
UNWATCH | 取消WATCH对所有key的监视 |
正常执行
放弃事务
事务队列中存在命令性错误(类似于java编译期错误),则执行EXEC命令时,所有命令都不会执行
若在事务队列中存在语法性错误(类似于java的0/0的运行期异常),则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常
使用watch
watch监听失败情况
一但执行 EXEC 开启事务的执行后,无论事务使用执行成功, WARCH 对变量的监控都将被取消。
故当事务执行失败后,需重新执行WATCH命令对变量进行监控,并开启新的事务进行操作。
watch指令类似于乐观锁,在事务提交时,如果watch监控的多个KEY中任何KEY的值已经被其他客户端更改,则使用EXEC执行事务时,事务队列将不会被执行,同时返回Nullmulti-bulk应答以通知调用者事务执行失败。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。