用户的个人信息,社交网络,地理位置。用户自己产生的数据,用户的日志数据等等爆发式增长。我们就需要使用NoSQL非关系型数据库。
什么是NoSQL?NoSQL=Not Only SQL(不仅仅是SQL),泛指非关系型数据库,超大规模的高并发社区暴露出很多难以克服的问题,NoSQL就诞生了。
NoSQL特点:
一般系统中都是使用 NoSQL + RDBMS,非关系型数据库和关系型数据库一起使用。
Redis,(Remote Dictionary Server),即远程字典服务,支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并且提供多种语言的API。
redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis能做什么:
Redis特性:
Redis可以用作数据库
、缓存
、消息中间件
,支持多类型数据结构。
redis默认有16个数据库,在配置文件redis.conf
中,默认是使用索引为0
的数据库,如果要显式选择数据库可以使用select index
命令来选择数据库,如select 3
,是选择第四个数据库使用。
常用命令
redis-cli -h 127.0.0.1 -p 6379 # 连接客户端
select 3 # 选择数据库
dbsize # 数据库key的数量
keys * # 查看素有key
flushdb # 清空当前数据库
fluashall # 清空所有数据库
Redis是单线程的,Redis是基于内存操作,CPU并不是Redis的性能瓶颈,Redis的性能瓶颈是机器的内存
和网络带宽
决定的。
假如一个机器只有一个CPU,那么如果使用多线程,CPU需要进行上下文切换,比较耗时。Redis是将数据放入到了内存中的,比放在磁盘上读写速度快太多了。对于内存系统来讲,没有上下文切换是效率最高的,多读写都是在一个CPU上,CPU不需要进行切换上下文,这个是最佳方案。
set key value # 设置string字符串
exists key # 此key是否存在,存在返回1 ,否返回0
move key 2 # 将某个key移动到其他的数据库中
expire name 10 # 名为name的key,10s后过期
type name # 查看名为name的key的数据类型
set name abc # 设置key
get name # 获取key
exist name # 存在key
move name 2 # 移动key到索引2的数据库
expire name 10 # 设置key10秒过期
ttl name # 还有多久过期
del key # 删除key
type name # key数据类型
append name def # 拼接key的值, "abcdef",返回字符串的总长度,如果key不存在,那么创建这个key,把值拼接
strlen name # 获取字符串长度
-----------------------------------------------------------------------------------
set name 5
incr name # 自增1
decr name # 自减1
incrby name 10 # 自增10
decrby name 10 # 自减10
-----------------------------------------------------------------------------------
# 值截取
# [0-3] 闭区间
getrange key 0 3 # 截取key的值
getrange key 0 -1 # 截取所有
setrange key 1 xx # 替换索引1后的值
-----------------------------------------------------------------------------------
setex (set with expire) #设置过期
# 分布式锁常用
setnx (set if not exist)# 不存在时设置key,如果key已经存在设置key失败(返回0),不存在则成功(返回1)
# 批量设置/获取
mset k1 v1 k2m v2 k3 v3
mget k1 k2 k3
# 此命令将失败,由于原子性,k1已经存在,
# 所以k4无法创建(分布式锁常用)
msetnx k1 v1 k4 v4
# 简单应用
mset user:1:name wlh user:1:age 21
mget user:1name user:1:age
-----------------------------------------------------------------------------------
getset db redis # 先get后set,如果key不存在返回nill,然后再去设置新的值
list可以从左或者右插入,读取只能从左读
没有rrange命令
# 向list中左侧插入元素
lpush list 1
# 向list中右侧插入元素
rpush list 2
# 从list左侧开始读取区间内的元素[]
lrange list 0 -1
# 获取list中从左数第一个元素
lindex list 0
# 同理,从右数第一个
rindex list 0
# 列表长度
llen list
---------------------------------------------------------------------------------------
# 左侧开始删除一个元素
lpop list
# 同理,右侧删除一个元素
rpop list
---------------------------------------------------------------------------------------
# 删除list中1个为one的值
lrem list 1 one
# 删除2个为three的值
lrem list 2 three
# 截取list
# 截取0到1之间的元素,其他元素被舍弃
ltrim list 0 1
# 组合
# 把list1最后元素删掉放入list2
# 最前面
rpoplpush list1 list2
# 更新元素
# 设置list第一个元素为item
# lset只能用于更新,元素不存在则报错
lset list 0 item
---------------------------------------------------------------------------------------
# 插入元素,可指定向元素前面还是后面插入 before/after
linsert list before v1 v2 # 在list中的v1元素前面插入一个v2元素
sadd set1 abc # 向 set1中添加一个abc元素
smembers set1 # 查看所有元素
sismember set1 abc # 是否包含abc
srem set1 abc # 移除abc元素
srandmember set1 # 随机抽取一个元素
srandmember set1 2 # 抽取2个
spop set1 # 随机移除元素
scard set1 # 查看集合中的数量
-----------------------------------------------------------------------------------------
# abc元素从set1移动到set2
smove set1 set2 abc
# 差集
sdiff set1 set2
# 交集
sinter set1 set2
# 并集
sunion set1 set2
# 存值
hset map name wlh
# 取值
hget map name
# 存入多个
hmset map name wlh age 20
hmget map name age
# 获取所有
hgetall map
# 删除某个key
hdel map name
-----------------------------------------------------------------------------------------
# 某个hash表字段数量
hlen map
# 所有key
hkeys map
# 所有value
hvals map
# map中的age设置自增
hincr map age
# map中的age设置自减
hdecr map age
# map中的age设置自增5
hincrby map age 5
# map中的age设置自减5
hdecrby map age -5
# 不存在时创建,创建后返回值1,未创建成功返回0
hsetnx map name wlh
往集合中添加元素,可以设置排序(score)
# 添加一个
zadd zs 1 one
# 添加多个
zadd zs 2 two 3 three
# 遍历所有
zrange zs 0 -1
# 根据score排序,读取所有
zrangebyscore zs -inf +inf
# score在0-2500之间按照score升序排序
zrangebyscore zs 0 2500 withscores
-----------------------------------------------------------------------------------------
# 移除集合中的元素
zrem zs one
# 查看集合元素个数
zcard zs
# 降序
zrevrange zs 0 -1
# 获取指定区间数量score在1-2
zcount zs 1 2
有效经度-180—180
有效纬度-85—85
# 添加城市经度纬度
geoadd china:city 172 80 bj
geoadd china:city 171 79 sh
geoadd china:city 173 78 cq 166 40 sz
# 获取城市经纬度(坐标)
geopos china:city bj
# 两地之间距直线离(km单位) bj到sh距离
geodist china:city bj sh km
# 附近的人,通过半径来筛选
# 查询经度100纬度30半径200km的地点
# withcoord 返回坐标
# withdist 返回直线距离
# count 只查询一个
georadius china:city 100 30 200 km withcoord withdist count 1
# 查询某城市附近的地点
# 找北京附近1000km的地点
georadiusbymember china:city bj 1000 km withcoord withdist count 2
# geohash获取11位geohash字符串
# 将二维经纬度转为一维字符串
geohash china:city bj cq
#geo底层是zset,可以用zset操作geo
zrange china:city 0 -1
# 删除bj的geo地址
zrem china:city bj
基数:一个集合中不重复的元素个数
网页的UV(浏览量)
传统方式:使用set集合 存储用户id×
使用hyperloglog
# 添加元素
pfadd mykey a b c d e
pfadd mykey2 b d n h k
# 集合中元素基数数量
pfcount mykey
# 集合合并,生成新集合
pfmerge key3 mykey mykey2
pfcount key3
bitmaps位图,数据结构,都是操作二进制来进行记录,只有0和1两个状态
# 设置存储位
# 0 1 2是偏移量
# 0 1 是存储的值
setbit sign 0 1
setbit sign 1 1
setbit sign 2 0
# 获取偏移量的值
getbit sign 0
getbit sign 2
# 查值是1的数量
bitcount sign
# 查偏移量在0-2之间值为1的数量
bitcount sign 0 2
Redis6.0版本之前的单线程是指网络I/O和键值对读写是由一个线程完成的。Redis6.0之后引入的多线程指的是网络请求过程采用了多线程,但是键值对的读写命令仍然是单线程处理,所以Redis是并发安全的。
也就是6.0前只有网络请求模块和数据操作模块是单线程的,而其他的持久化、集群数据同步等,是由额外的线程执行的。
可以说Redis涉及到数据读写时是单线程的,但是其他的持久化、集群数据同步等都是多线程完成的。