1、什么是NOSQL?
NoSQL(Not Only SQL),是一项全新的数据库理念,泛指非关系型的数据库。
2、为什么要用NOSQL
随着互联网的高速发展,网站的用户量的增加和访问量的上升,传统数据库开始出现了性能的瓶颈,web程序不再仅仅专注在功能,同时也在追求性能。所以NOSQL数据库应运而上,具体表现为对如下三高问题的解决:
1)High performance - 对数据库高并发读写的需求
例如网站的实时统计在线用户状态,记录热门帖子的点击次数,投票计数等需求。
2)Huge Storage - 对海量数据的高效率存储和访问的需求
例如大型web网站的用户登录系统,腾讯,盛大,动辄数以亿计的帐号,或者Facebook,twitter,微博每天用户产生海量的动态,关系数据库也很难应付。
3)High Scalability && High Availability- 对数据库的高可扩展性和高可用性的需求
3、主流的NOSQL
1)键值(Key-Value)存储数据库
相关产品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
典型应用: 内容缓存,主要用于处理大量数据的高访问负载。
数据模型: 一系列键值对
优势: 快速查询
劣势: 存储的数据缺少结构化
2)列存储数据库
相关产品:Cassandra, HBase, Riak
典型应用:分布式的文件系统
数据模型:以列簇式存储,将同一列数据存在一起
优势:查找速度快,可扩展性强,更容易进行分布式扩展
劣势:功能相对局限
3)文档型数据库
相关产品:CouchDB、MongoDB
典型应用:Web应用(与Key-Value类似,Value是结构化的)
数据模型: 一系列键值对
优势:数据结构要求不严格
劣势: 查询性能不高,而且缺乏统一的查询语法
4)图形(Graph)数据库
相关数据库:Neo4J、InfoGrid、Infinite Graph
典型应用:社交网络
数据模型:图结构
优势:利用图结构相关算法。
劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。
4、NOSQL的特点
1)易扩展
去掉关系数据库的关系型特性。数据之间无关系,非常容易扩展。
2)大数据量,高性能
NoSQL数据库具有非常高的读写性能,尤其在大数据量下。因为它的无关系性和数据库的结构简单。
3)灵活的数据模型
NoSQL不需要事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段非常繁琐。如果是大数据量的表,增加字段就更麻烦。
4)高可用
NoSQL在不太影响性能的情况下,就可以方便的实现高可用的架构。
1、什么是Redis
Redis是用C语言开发的一个开源,遵守BSD协议的高性能的可基于内存亦可持久化的日志型、键值对(key-value)数据库。
官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s。
2、Redis在Windows下的安装和使用
官网提供了Linux版的Redis,GitHub提供了Windows版的下载
官网地址:http://redis.io/download
GitHub地址:https://github.com/MSOpenTech/redis/tags
解压版大致文件如下:
redis-server.exe:服务端程序,提供redis服务
redis-cli.exe: 客户端程序,通过它连接redis服务并进行操作
redis-check-dump.exe:本地数据库检查
redis-check-aof.exe:更新日志检查
redis-benchmark.exe:性能测试,用以模拟同时由N个客户端发送M个 SETs/GETs 查询 (类似于 Apache 的ab 工具).
redis.windows.conf: 配置文件,将redis作为普通软件使用的配置,命令行关闭则redis关闭
redis.windows-service.conf:配置文件,将redis作为系统服务的配置,用以区别开两种不同的使用方式
启动方式:
打开cmd窗口使用cd命令切换到安装目录执行
redis-server.exe redis.windows.conf
这时候另启一个cmd窗口,原来的不要关闭,不然就无法访问服务端了。
执行:redis-cli.exe
设置密码
################################## SECURITY ###################################
# Require clients to issue AUTH before processing any other
# commands. This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#去掉下方的注释,行前不能有空格requirepass 后跟你设置的面
# requirepass foobared
客户端登录的时候需要输入密码在进行其他操作
127.0.0.1:6379> auth qyb123
OK
127.0.0.1:6379>
3、Redis的5种数据类型
1)字符串(String)及常用命令
string类型是二进制安全的。redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
string类型是Redis最基本的数据类型,一个键最大能存储512MB。
存值:
格式:set key value
例如:127.0.0.1:6379>set name answer
返回:OK
设定key持有指定的字符串value,如果该key存在则进行覆盖操作。总是返回”OK”
取值:
格式:get key
例如:127.0.0.1:6379>get name
返回:"answer"
获取key的value。如果与该key关联的value不是String类型,redis将返回错误信息,因为get命令只能用于获取String value;如果该key不存在,返回(nil)。
删除指定key
格式:del key
例如:127.0.0.1:6379>del name
返回:(integer) 1
将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)
格式:SETEX key seconds value
例如:127.0.0.1:6379> setex hello 10 world
返回:OK
将 key 中储存的数字值增一
格式:INCR key
例如:127.0.0.1:6379> set age 18
返回:OK
127.0.0.1:6379> incr age
返回:(integer) 19
2)哈希(hash)及常用命令
Redis中的Hash类型可以看成具有String Key和String Value的map容器。所以该类型非常适合于存储值对象的信息。如Username、Age等。如果Hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个Hash可以存储4294967295个键值对。
为指定的key设定field/value对(键值对)
格式:hset key field value
例如:127.0.0.1:6379>hset student username answer
返回:(integer) 1
返回指定的key中的field的值,如果没有对应的值
格式:hget key field
例如:127.0.0.1:6379>hget student username
返回:"answer"
例如:127.0.0.1:6379>hget student age
返回:(nil)
可以删除一个或多个字段,返回值是被删除的字段个数
格式:hdel key field [field … ]
例如:127.0.0.1:6379>hdel student username age
返回:(integer) 2
3)字符串列表(list)及常用命令
在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。如果链表中所有的元素都被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是4294967295
在指定的key所关联的list的头部插入所有的values,如果该key不存在,该命令在插入的之前创建一个与该key关联的空链表,之后再向该链表的头部插入数据。插入成功,返回元素的个数。
格式:lpush key values[value1 value2…]
例如:127.0.0.1:6379>lpush str a b c
返回:(integer) 3
获取列表指定范围内的元素(区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素)
格式:lrange key start stop
例如:127.0.0.1:6379> lrange str 0 2
返回:1) "c"
2) "b"
3) "a"
返回并弹出指定的key关联的链表中的第一个元素,即头部元素。如果该key不存在,返回nil;若key存在,则返回链表的头部元素。
格式:lpop key
例如:127.0.0.1:6379>lpop str
返回:"c"
从尾部弹出元素。
格式:rpop key
例如:127.0.0.1:6379>rpop str
返回:"a"
4)字符串集合(set)及常用命令
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的。它是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。集合中最大的成员数量是 4294967295。
向set中添加数据,如果该key的值已有则不会重复添加,并返回添加数量
格式:SADD KEY VALUE1..VALUEN
例如:127.0.0.1:6379>SADD student answer li zhang
返回:(integer) 3
获取set中所有的成员
格式:smembers key
例如:127.0.0.1:6379> SMEMBERS student
返回:1) "zhang"
2) "li"
3) "answer"
移除集合中一个或多个成员,返回移除数量
格式:SREM key member1 [member2]
例如:127.0.0.1:6379> srem student answer li
返回:(integer) 2
5)有序字符串集合(sorted set / zset)及常用命令
Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。
向有序集合添加一个或多个成员,或者更新已存在成员的分数,并返回添加数量
格式:ZADD key score1 member1 [score2 member2]
例如:127.0.0.1:6379> zadd player 1 T-Mac 3 AI
返回:(integer) 2
通过索引区间返回有序集合成指定区间内的成员
格式:ZRANGE key start stop [WITHSCORES]
例如:127.0.0.1:6379> zrange player 0 10 withscores
返回:1) "T-Mac"
2) "1"
3) "AI"
4) "3"
移除有序集合中的一个或多个成员并返回删除数量
格式:ZREM key member [member ...]
例如:127.0.0.1:6379> zrem player T-Mac AI
返回:(integer) 2
6)Redis通用命令
Redis Keys 命令用于查找所有符合给定模式 pattern 的 key 。
格式:keys pattern
例如:127.0.0.1:6379> keys *
返回:1) "player"
2) "student"
删除指定的key
格式:del key1 key2…
例如:127.0.0.1:6379> del player student
返回:(integer) 2
判断该key是否存在,1代表存在,0代表不存在
格式:exists key
例如:exists player
返回:(integer) 1
例如:exists student
返回:(integer) 0
4、Redis持久化
Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”);也可以把每一次数据变化都写入到一个append only file(aof)里面(这称为“全持久化模式”)。
Redis提供两种方式进行持久化,一种是RDB持久化(原理是将Redis在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Redis的操作日志以追加的方式写入文件)。可以单独使用其中一种或将二者结合使用。
1)、RDB持久化(默认支持,无需配置)
该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。
RDB优势
1)、一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
2)、对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
3)、性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork(分叉)出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
4)、相比于AOF机制,如果数据集很大,RDB的启动效率会更高。
RDB缺点
1)、如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
2)、由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
如何配置RDB持久化
################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
#
# save
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving completely by commenting out all "save" lines.
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save ""
save 900 1
save 300 10
save 60 10000
关键字 | 时间(秒) | 修改k的数量 | 解释 |
---|---|---|---|
save | 900 | 1 | 每900秒(15分钟)至少有1个key发生变化,则dump内存快照 |
save | 300 | 10 | 每300秒(5分钟)至少有10个key发生变化,则dump内存快照 |
save | 60 | 10000 | 每60秒(1分钟)至少有10000个key发生变化,则dump内存快照 |
2)、AOF持久化
该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。
AOF持久化优势
1)、该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3种同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。
2)、由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
3)、如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
4)、AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。我们也可以通过该文件完成数据的重建。
AOF持久化缺点
1)、对于相同数量的数据集而言,AOF文件通常要大于RDB文件。
2)、根据同步策略的不同,AOF在运行效率上往往会慢于RDB。
如何配置AOF持久化
############################## APPEND ONLY MODE ###############################
# By default Redis asynchronously dumps the dataset on disk. This mode is
# good enough in many applications, but an issue with the Redis process or
# a power outage may result into a few minutes of writes lost (depending on
# the configured save points).
#
# The Append Only File is an alternative persistence mode that provides
# much better durability. For instance using the default data fsync policy
# (see later in the config file) Redis can lose just one second of writes in a
# dramatic event like a server power outage, or a single write if something
# wrong with the Redis process itself happens, but the operating system is
# still running correctly.
#
# AOF and RDB persistence can be enabled at the same time without problems.
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
#
# Please check http://redis.io/topics/persistence for more information.
appendonly no
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"
# The fsync() call tells the Operating System to actually write data on disk
# instead of waiting for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log. Slow, Safest.
# everysec: fsync only one time every second. Compromise.
#
# The default is "everysec", as that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".
# appendfsync always
appendfsync everysec
# appendfsync no
将appendonly修改为yes,开启aof持久化机制,默认会在目录下产生一个appendonly.aof文件。
关键字 | 持久化时间 | 解释 |
---|---|---|
appendfsync | always | 每次有数据修改发生时都会写入AOF文件 |
appendfsync | everysec | 每秒钟同步一次,该策略为AOF的默认策略 |
appendfsync | no | 从不同步。高效但是数据不会被持久化 |
3)、无持久化
如何配置禁用Redis服务器的持久化功能?
将RDB配置全部注释掉,appendonly 仍旧为no,同时设置save “”,还要把持久化的本地文件干掉。
5、Redis 事务
Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
一个事务从开始到执行会经历以下三个阶段:
以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a aa
QUEUED
127.0.0.1:6379> set b bb
QUEUED
127.0.0.1:6379> set c cc
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) OK
tips:如果在 set b bbb 处失败,set a 已成功不会回滚,set c 还会继续执行。
6、Jedis
Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如java、C、C#、C++、php、Node.js、Go等。 在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis、等其中官方推荐使用Jedis和Redisson。 在企业中用的最多的就是Jedis。
Jedis官方文档地址:http://xetorthio.github.io/jedis/
1)、Jedis的基本操作
Java Redis String(字符串)
import redis.clients.jedis.Jedis;
public class Test {
public static void main(String[] args) {
1 设置ip地址和端口
Jedis jedis = new Jedis("localhost",6379);
System.out.println("连接成功");
//2 设置 redis 字符串数据
jedis.set("name", "oracle");
//3 获取存储的数据并输出
System.out.println("redis 存储的字符串为: "+ jedis.get("name"));
//4 释放资源
jedis.close();
}
Java Redis List(列表)
public static void main(String[] args) {
//连接本地的 Redis 服务
Jedis jedis = new Jedis("localhost",6379);
System.out.println("连接成功");
//存储数据到列表中
jedis.lpush("list", "B");
jedis.lpush("list", "A");
jedis.lpush("list", "T");
// 获取存储的数据并输出
List list = jedis.lrange("list", 0 ,2);
for(int i=0; i
2)、jedis连接池的基本操作
jedis连接的创建和销毁很消耗性能,所以jedis提供了jedis的池化技术,jedisPool在创建时初始化一些连接资源存储到连接池中,使用jedis连接资源时不需要创建,而是从连接池中获取一个资源进行redis的操作,使用完毕后,不需要销毁该jedis连接资源,而是将该资源归还给连接池,供其他请求使用。
public static void main(String[] args) {
// 获得连接池配置对象,设置配置项
JedisPoolConfig config = new JedisPoolConfig();
// 最大连接数
config.setMaxTotal(10);
//最大空闲连接数
config.setMaxIdle(5);
//获得连接池
JedisPool pool = new JedisPool("127.0.0.1", 6379);
Jedis jedis =null;
try {
jedis = pool.getResource();
jedis.set("name", "oracle");
System.out.println(jedis.get("name"));
} catch (Exception e) {
e.printStackTrace();
}finally {
if (jedis != null) {
jedis.close();
}
if (pool !=null) {
pool.close();
}
}
}