Redis
NoSQL (not only sql)
在现代计算系统中,网络每天都会产生大量的数据。
这些数据的很大一部分是关系数据库管理系统(RDBMS)来处理。 1970年 E.F.Codd’s关系模型论文 “A relational model of data for large shared data banks这使得数据建模和应用程序编程更加简单。
应用实践证明,关系模型非常适合客户服务器编程,远远超出预期利益。今天,它是网络和商业应用中结构化数据存储的主导技术。
NoSQL 这是一项全新的数据库革命性运动,早期有人提出,到2009年趋势越来越高。NoSQL支持者提倡使用非关系数据存储。与铺天盖地的关系数据库相比,这一概念无疑是一种新思维的注入。
什么是NoSQL?
NoSQL,指非关系数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。
NoSQL存储超大规模数据(如谷歌或Facebook每天为用户收集万亿比特的数据)。这些类型的数据存储可以横向扩展,无需固定模式和多余操作。
对于NoSQL没有明确的范围和定义,但它们都有以下共同特征:
易扩展
NoSQL数据库有很多种,但一个共同的特点是去除关系数据库的关系特征。数据之间没有关系,所以很容易扩展。实际上,它带来了可扩展的能力。
大数据量,高性能
NoSQL数据库具有非常高的读写性能,尤其是在大数据量下。由于其无关性,数据库结构简单。MySQL使用Query Cache。NoSQL的Cache是记录级,是细粒度Cache,所以NoSQL在这个层面上,性能要高得多。
数据模型灵活
NoSQL无需事先为要存储的数据建立字段,您可以随时存储自定义的数据格式。在关系数据库中,添加和删除字段是一件非常麻烦的事情。如果它是一个非常大的数据量表,那么添加字段就是一场噩梦。这是大数据量的Web 2.特别是0时代。
高可用
NoSQL在不影响性能的情况下,可以轻松实现高可用架构。Cassandra、HBase模型也可以通过复制模型实现高可用性。
NoSQL优缺点
优点:
- - 高可扩展性
- - 分布式计算
- - 低成本
- - 架构的灵活性、半结构化数据
- - 没有复杂的关系
缺点:
- - 没有标准化
- - 查询功能有限(到目前为止)
- - 最终一致性是不直观的程序
NoSQL 数据库分类
键值(Key-Value)存储数据库
这类数据库主要使用哈希表,其中有特定的键和指针指向特定的数据。Key/value模型对于IT系统的优点是简单易部署。但如果数据库管理员是如果(DBA)只查询或更新部分值,Key/value效率低下。举例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB。
存储数据库
这部分数据库通常用于处理分布式存储的大量数据。键仍然存在,但它们的特点是指向多列。这些列由列家族安排。Cassandra, HBase, Riak.
文档数据库
文档数据库的灵感来自Lotus Notes办公软件,类似于第一个键存储。这类数据模型是版本化文档,半结构化文档以特定格式存储,如JSON。文档数据库可以看作是键值数据库的升级版本,允许嵌套键值。文档数据库在处理网页等复杂数据时,查询效率高于传统键值数据库。如:CouchDB, MongoDb. 国内也有文档数据库SequoiaDB,已经开源。
图形(Graph)数据库
图形结构数据库与其他行列和刚性结构相同SQL不同的数据库使用灵活的图形模型,可以扩展到多个服务器。NoSQL数据库中没有标准的查询语言(SQL),因此,需要制定数据模型定数据模型。许多NoSQL数据库都有REST类型的数据接口或查询API。如:Neo4J, InfoGrid, Infinite Graph。
类型 | 部分代表 | 特点 |
---|---|---|
列存储 | HbaseCassandraHypertable | 顾名思义,数据是按列存储的。最大的特点是方便存储结构化和半结构化数据,方便数据压缩,查询一列或几列非常大IO优势。 |
文档存储 | MongoDBCouchDB | 类似的文档存储通常用于文档存储json格式存储,存储内容为文档类型。这样,就有机会对某些字段建立索引,实现与数据库相关的某些功能。 |
key-value存储 | Tokyo Cabinet / TyrantBerkeley DBMemcacheDBRedis | 可以通过key快速查询value。一般来说,无论存储如何value按单全收格式。(Redis包含其他功能) |
图存储 | Neo4JFlockDB | 图形关系的最佳存储。采用传统关系数据库解决,性能低,设计使用不方便。 |
对象存储 | db4oVersant | 通过类似于对象语言的语法操作数据库,通过对象访问数据。 |
xml数据库 | Berkeley DB XMLBaseX | 高效的存储XML并支持数据XML内部查询语法,如XQuery,Xpath。 |
Redis概述
REmote DIctionary Server(Redis) 也就是说,远程字典服务是由 Salvatore Sanfilippo 写的 key-value 存储系统是一个跨平台的非关系数据库,也被称为结构化数据库。
Redis 使用开源 ANSI C 语言编写,遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言 API。
Redis 由于值,通常称为数据结构服务器(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。
Redis 是一个开源(BSD内存中的数据结构存储系统可用作数据库、缓存和信息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 不同层次的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
特点
- 性能极高 – Redis能读1.1万次/s,写作速度为81000次/s 。
- 数据类型丰富 – Redis支持二进制案例 Strings, Lists, Hashes, Sets 及 Ordered Sets 操作数据类型。
- 原子 – Redis所有的操作都是原子的,这意味着要么成功执行,要么完全失败。单个操作是原子的。多个操作还支持事务,即原子,通过MULTI和EXEC包起指令。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等特点。
Redis能干嘛
1、内存存储、持久化,内存中时断电即失,所以说持久化很重要(rdb、aof)
2.高效率可用于高速缓存
3.发布订阅系统
4.地图信息分析
5.计时器、计数器(浏览量)
6、。。。
Windows安装redis
1、github下载压缩包https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100
2、直接解压
3、打开服务端
4、打开客户端测试
命令 redis-server.exe redis.windows.conf
解决双击闪退问题
Linux安装redis:
下载redis压缩包:
wget https://download.redis.io/releases/redis-6.2.6.tar.gz
解压到对应安装目录:
mkdir /usr/local/redis6
sudo tar -zxvf ~/redis-6.2.6.tar.gz -C /usr/local/redis6
cd到/usr/local/redis6目录,输入命令make执行编译命令,接下来控制台会输出各种编译过程中输出的内容。
make -version 查看make是否安装
如果没有安装make可以使用
sudo apt install -y make
进入安装目录:安装必要的依赖:
sudo apt install -y gcc
sudo apt install -y tcl
**注意:**如果其中下载失败并提示更新,使用:
sudo apt-get update
执行命令:
youxin@youxin-virtual-machine:/usr/local/redis6/redis-6.2.6$ sudo make MALLOC=libc
执行命令:
make test
如果测试全部通过,则证明上一步的make操作准确无误
执行安装命令:
sudo make PREFIX=/usr/local/redis6/redis6/ install
在redis的根目录下有一个配置文件redis.conf,把它考本到安装的redis目录,也就是上面指定的PREFIX文件夹:
sudo cp redis.conf …/redis6/
配置环境变量:
sudo vim /etc/profile
在文件最后加入:
export REDIS_HOME=/usr/local/redis6/redis6/
export PATH= P A T H : PATH: PATH:REDIS_HOME/bin
然后执行:source /etc/profile使之生效
启动redis服务:
redis-server /usr/local/redis6/redis6/redis.conf #如果没有指定配置文件,则会走默认的配置文件
启动redis客户端
redis-cli -p 6379 --raw
关闭redis服务:
shutdown
查看redis端口:
ps -ef |grep redis
强行关闭端口:
kill -9 PID
性能测试
redis-benchmark是一个官方自带的压力测试工具
redis-benchmark测试命令参数:
redis 性能测试工具可选参数如下所示:
序号 | 选项 | 描述 | 默认值 |
---|---|---|---|
1 | 指定服务器主机名 | 127.0.0.1 | |
2 | 指定服务器端口 | 6379 | |
3 | 指定服务器 socket | ||
4 | 指定并发连接数 | 50 | |
5 | 指定请求数 | 10000 | |
6 | 以字节的形式指定 SET/GET 值的数据大小 | 2 | |
7 | 1=keep alive 0=reconnect | 1 | |
8 | SET/GET/INCR 使用随机 key, SADD 使用随机值 | ||
9 | 通过管道传输 请求 | 1 | |
10 | 强制退出 redis。仅显示 query/sec 值 | ||
11 | 以 CSV 格式输出 | ||
12 | * | 生成循环,永久执行测试 | |
13 | 仅运行以逗号分隔的测试命令列表。 | ||
14 | * | Idle 模式。仅打开 N 个 idle 连接并等待。 |
简单测试:
redis-benchmark -h localhost -p 6379 -c 100 -n 100000 本地测试,端口6379,100个并发连接,100000个请求总共
基础知识
redis默认有16个数据库
默认使用的是第0个
可以使用select进行切换数据库
dbsize 查看数据库大小
keys * 查看数据库中所有的key
flushall 清除全部数据库
flushdb 清除当前数据库
redis是c语言写的,官方的数据为10W+的QPS,这个不比Memcache差!
五大数据类型
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial)索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions)和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
Redis-Key
exists key 判断是否存在该key
move key 1移除key,1代表移除的数据库
EXPIRE name 10 设置过期时间为10秒
ttl name 查看剩余时间
type key 查看key的类型
String(字符串类型)
############################################################# 127.0.0.1:6379> set key1 "hello" # 设置值 OK 127.0.0.1:6379> get key1 #获取值 "hello" 127.0.0.1:6379> append key1 " world" # 追加值,如果该key不存在则新建一个字符串相当于set key (integer) 11 127.0.0.1:6379> get key1 "hello world" 127.0.0.1:6379> strlen key1 # 获取值的长度 (integer) 11 ############################################################## 127.0.0.1:6379> set views 0 #设置views初始值为0 OK 127.0.0.1:6379> get views "0" 127.0.0.1:6379> INCR views # 设置自增1 (integer) 1 127.0.0.1:6379> get views "1" 127.0.0.1:6379> incr views (integer) 2 127.0.0.1:6379> get views "2" 127.0.0.1:6379> decr views # 自减1 (integer) 1 127.0.0.1:6379> DECR views (integer) 0 127.0.0.1:6379> get views "0" # 步长 i+= 127.0.0.1:6379> incrby views 10 #设置步长为10并增加 (integer) 10 127.0.0.1:6379> get views "10" ############################################################## # 字符串范围range 127.0.0.1:6379> getrange key1 1 4 #截取字符串1-4 "ello" 127.0.0.1:6379> getrange key1 0 -1 # 截取全部的字符串 "hello world" # 替换setrange 127.0.0.1:6379> setrange key1 0 nihao #从0位置开始替换 (integer) 11 127.0.0.1:6379> get key1 "nihao world“ ############################################################## #setex(set with expire) # 设置过期时间 #setnx(set if not exist) # 不存在再设置(在分布式
锁中会常常使用) 127.0.0.1:6379> setex key2 30 youxin #设置key2并在30秒后过期 OK 127.0.0.1:6379> ttl key2 (integer) 26 127.0.0.1:6379> ttl key2 #查看剩余时间 (integer) 21 127.0.0.1:6379> setnx key3 cloud # 如果key3不存在就创建,如果存在就创建失败 (integer) 1 127.0.0.1:6379> get key3 "cloud" 127.0.0.1:6379> setnx key3 rain (integer) 0 # 再次创建失败 127.0.0.1:6379> keys * 1) "key3" 2) "views" 3) "key1" 127.0.0.1:6379> get key3 # 值没有改变 "cloud" ############################################################## # mset 同时设置多个值 # mget 同时获取多个值 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值 OK 127.0.0.1:6379> keys * 1) "k2" 2) "k3" 3) "k1" 127.0.0.1:6379> mget k1 k2 k3 # 同时获取多个值 1) "v1" 2) "v2" 3) "v3" 127.0.0.1:6379> msetnx k3 v3 k5 v5 #如果都不存在就设置多个值, msetnx是一个原子性的操作,要么一起成功,要么一起失败 (integer) 0 127.0.0.1:6379> keys * 1) "k2" 2) "k3" 3) "k1" ############################################################## # 对象 set user:1 {name:zhangsan,age=20} # 设置一个user:1对象,值为json字符来保存一个对象 # 这里的key是一个巧妙的设计:user:{id}:{filed} 127.0.0.1:6379> mset user:1:name zhangsan user:1:age 22 OK 127.0.0.1:6379> mget user:1:name user:1:age 1) "zhangsan" 2) "22" ############################################################## getset #先get再set 127.0.0.1:6379> getset db mysql #如果不存在,则返回nil (nil) 127.0.0.1:6379> get db "mysql" 127.0.0.1:6379> getset db oracle #如果已经存在,返回原来的值并更新新的值 "mysql" 127.0.0.1:6379> get db "oracle" ##############################################################
String类似的使用场景:value除了是字符串还可以是数字
- 计数器
- 统计多单位数量
- 粉丝数
- 对象缓存存储!
List
在redis可以把list变成栈,队列,阻塞队列
所有的List命令都是以l
开头的
##############################################################
127.0.0.1:6379> lpush list1 one # 放置值,并从头部插入
(integer) 1
127.0.0.1:6379> lpush list1 two
(integer) 2
127.0.0.1:6379> lpush list1 three
(integer) 3
127.0.0.1:6379> lrange list1 0 -1 # 遍历所有
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list1 0 1 # 通过具体的区间得到值
1) "three"
2) "two"
127.0.0.1:6379> rpush list1 four #从队列的尾部插入
(integer) 4
127.0.0.1:6379> lrange list1 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
##############################################################
#LPOP
#RPOP
127.0.0.1:6379> lpop list1 1 #弹出List1的第一个元素
1) "three"
127.0.0.1:6379> rpop list1 #弹出list1的最后一个元素
"four"
127.0.0.1:6379> lrange list1 0 -1
1) "two"
2) "one"
##############################################################
# Lindex
127.0.0.1:6379> lindex list1 0 #获取下标为0的值
"two"
127.0.0.1:6379> lindex list1 1
"one"
127.0.0.1:6379> lpop list1
"two"
127.0.0.1:6379> lpop list1
"one"
127.0.0.1:6379> lindex list1 0 #当队列为空时返回nil
(nil)
##############################################################
#Llen获取队列长度
127.0.0.1:6379> lpush list2 one
(integer) 1
127.0.0.1:6379> lpush list2 two
(integer) 2
127.0.0.1:6379> lpush list2 three
(integer) 3
127.0.0.1:6379> llen list2 #返回列表长度
(integer) 3
##############################################################
#Lrem 移除指定的值,精确匹配
127.0.0.1:6379> lpush list2 three
(integer) 4
127.0.0.1:6379> lrem list2 1 one #移除1个one
(integer) 1
127.0.0.1:6379> lrem list2 2 three #移除两个three
(integer) 2
127.0.0.1:6379> lrange list2 0 -1
1) "two"
##############################################################
# trim 修剪:list 截断
127.0.0.1:6379> lpush list3 value1
(integer) 1
127.0.0.1:6379> lpush list3 value2
(integer) 2
127.0.0.1:6379> lpush list3 value3
(integer) 3
127.0.0.1:6379> lpush list3 value4
(integer) 4
127.0.0.1:6379> ltrim list3 1 2 # 截取下标为1到2的值
OK
127.0.0.1:6379> LRANGE list3 0 -1 #输出list3
1) "value3"
2) "value2"
##############################################################
#rpoplpush 移除列表最后一个元素并添加到另一个元素
127.0.0.1:6379> RPOPLPUSH list3 list4
"value2"
127.0.0.1:6379> lrange list3 0 -1 #查看原来的列表
1) "value3"
127.0.0.1:6379> lrange list4 0 -1 #查看新的列表确实存在弹出来的值
1) "value2"
##############################################################
#lset 指定下标替换值,如果下标不存在则会报错
127.0.0.1:6379> exists list3 #判断是否存在list3
(integer) 1
127.0.0.1:6379> lset list3 0 value4 #替换list3中下标为0的值为value4
OK
127.0.0.1:6379> lrange list3 0 -1
1) "value4"
##############################################################
# Linsert key after|before pivot value在指定位置之前或之后插入
127.0.0.1:6379> lrange list3 0 -1
1) "value4"
127.0.0.1:6379> LINSERT list3 before value4 value5 #在value4前面插入
(integer) 2
127.0.0.1:6379> lrange list3 0 -1
1) "value5"
2) "value4"
127.0.0.1:6379> LINSERT list3 after value4 value6 #在value4后面插入
(integer) 3
127.0.0.1:6379> lrange list3 0 -1
1) "value5"
2) "value4"
3) "value6"
##############################################################
- 它实际上是一个链表,before node after,left ,right都可以插入值
- 如果key不存在,则创建新的链表
- 如果key存在,新增内容
- 如果移除了所有值,空链表,也代表不存在
- 在两边插入或者改动值,效率最高!中间元素改动,相对来说效率会低一点
消息队列:(LPUSH RPOP)栈:(LPUSH LPOP)
Set(集合)
set中的值是不能重复的,且是无序的
##############################################################
# sadd添加元素
# smember获取所有元素
# sismember判断是否存在元素
127.0.0.1:6379> sadd set1 hello #set集合中添加元素
(integer) 1
127.0.0.1:6379> sadd set1 " world"
(integer) 1
127.0.0.1:6379> SMEMBERS set1
1) "hello"
2) " world"
127.0.0.1:6379> SISMEMBER set1 "hello" #判断元素是否在set中,存在返回1,不存在返回0
(integer) 1
127.0.0.1:6379> sismember set1 "he"
(integer) 0
##############################################################
#scard获取set集合中元素个数
127.0.0.1:6379> scard set1
(integer) 2
127.0.0.1:6379> sadd set1 nihao
(integer) 1
127.0.0.1:6379> scard set1
(integer) 3
##############################################################
#srem移除指定元素
127.0.0.1:6379> srem set1 nihao
(integer) 1
127.0.0.1:6379> scard set1
(integer) 2
127.0.0.1:6379> SMEMBERS set1
1) "hello"
2) " world"
127.0.0.1:6379> sadd set1 nihao
(integer) 1
127.0.0.1:6379> sadd set1 shijie
(integer) 1
127.0.0.1:6379> srem set1 nihao shijie #可以一次移除多个元素
(integer) 2
127.0.0.1:6379> SMEMBERS set1
1) "hello"
2) " world"
##############################################################
#srandmember 随机获取指定个元素
127.0.0.1:6379> SRANDMEMBER set1
"hello"
127.0.0.1:6379> SRANDMEMBER set1
" world"
127.0.0.1:6379> SRANDMEMBER set1
" world"
127.0.0.1:6379> SRANDMEMBER set1 2
1) "hello"
2) " world"
##############################################################
#spop随机删除Key
127.0.0.1:6379> sadd set1 youxin
(integer) 1
127.0.0.1:6379> spop set1
"youxin"
127.0.0.1:6379> SMEMBERS set1
1) "hello"
2) " world"
##############################################################
#smove将一个指定的值移动到另外一个集合中
127.0.0.1:6379> smove set1 set2 hello
(integer) 1
127.0.0.1:6379> SMEMBERS set1
1) " world"
127.0.0.1:6379> SMEMBERS set2
1) "youxin"
2) "hello"
##############################################################
#sdiff 差集
#sinter 交集
#sunion 并集
127.0.0.1:6379> sadd set3 a
(integer) 1
127.0.0.1:6379> sadd set3 b
(integer) 1
127.0.0.1:6379> sadd set3 c
(integer) 1
127.0.0.1:6379> sadd set4 c
(integer) 1
127.0.0.1:6379> sadd set4 d
(integer) 1
127.0.0.1:6379> sadd set4 f\
(integer) 1
127.0.0.1:6379> sdiff set3 set4
1) "b"
2) "a"
127.0.0.1:6379> SINTER set3 set4
1) "c"
127.0.0.1:6379> sunion set3 set4
1) "b"
2) "a"
3) "c"
4) "d"
5) "f\\"
应用场景:共同关注等
##############################################################
Hash(Map集合)
Map集合,key-map! 这时候的值是一个map集合!本质和string类型没有太大的区别,还是一个简单的key-value
set hash field value
############################################################## 127.0.0.1:6379> hset hash1 field1 youxin (integer) 1 127.0.0.1:6379> hget hash1 field1 "youxin" ############################################################## #hmset设置多个值 #hmget获取多个值 #hgetall获取所有的值 127.0.0.1:6379> hmset hash1 field1 hello field2 world #如果已经存在则覆盖原来的值 OK 127.0.0.1:6379> hmget hash1 field1 field2 1) "hello" 2) "world" 127.0.0.1:6379> HGETALL hash1 1) "field1" 2) "hello" 3) "field2" 4) "world" ############################################################## #hdel删除某一个值,对应的value值也删除了 127.0.0.1:6379> hdel hash1 field1 (integer) 1 127.0.0.1:6379> HGETALL hash1 1) "field2" 2) "world" ############################################################## # hlen 获取当前hash的长度 127.0.0.1:6379> hlen hash1 (integer) 1 127.0.0.1:6379> hset hash1 field3 value3 (integer) 1 127.0.0.1:6379> hlen hash1 (integer) 2 ############################################################## #hexists判断对应的field和value是否存在 127.0.0.1:6379> HEXISTS hash1 field1 (integer) 0 #0代表不存在 127.0.0.1:6379> HEXISTS hash1 field3 (integer) 1 #1代表存在 ############################################################## #hkeys 只获得所有的field #hvals 只获得所有的value 127.0.0.1:6379> hkeys hash1 1) "field2" 2) "field3" 127.0.0.1:6379> hvals hash1 1) "world" 2) "value3" ############################################################## # huncrby 增加相应的步长,步长可以为负数(即减) 127.0.0.1:6379> HINCRBY hash1 field4 10 (integer) 16 127.0.0.1:6379> hget hash1 field4 "16" 127.0.0.1:6379> HINCRBY hash1 field4 -5 (integer) 11 127.0.0.1:6379> hget hash1 field4 "11" ############################################################## # hsetnx 如果不存在则新增,如果存在则新增失败 127.0.0.1:6379> hsetnx hash1 field5 nihao (integer) 1 127.0.0.1:637 标签:
k5连接器1x8p连接器ba附带连接器0123连接器