开启redis的学习之路

前言

掌握noSql

linux系统安装

  1. 下载安装包 ! redis-5.0.8.tar.gz

  2. 解压redis的安装包 ! 程序放在 /opt 目录下
    在这里插入图片描述

  3. 进入解压后的文件,并执行命令:

yum install gcc-c++
make
make install
  1. redis的默认安装路径
/usr/local/bin

在这里插入图片描述

  1. 将redis的配置文件放到/usr/local/bin 目录下 我们之后使用redis.conf进行启动

在这里插入图片描述

  1. redis默认不是后台启动的,修改配置文件! redis.conf
    daemonize no ->yes 改为yes 后台启动
    在这里插入图片描述

  2. 启动redis服务 redis-server kconfig/redis.conf
    在这里插入图片描述

  3. 启动redis客户端 redis-cli -p 6379

`在这里插入图片描述

  1. 如何关闭redis服务
    在这里插入图片描述

redis-benchmark性能测试

它是redis官方自带的性能测试工具(压力测试工具)

命令参数如下:

  1. -h 指定服务主机名 默认值127.0.0.1
  2. -p 指定服务器端口 6379
  3. -s 指定服务器 socket
  4. -c 指定并发连接数 50
  5. -n 指定请求数 100000
  6. -d 以字节的形式指定SET/GET值的数据大小
  7. -k 1=keep alive 0=reconnect
  8. -r SET/GET/INCR 使用随机key SADD 使用随机值
  9. -p 通过管道传输请求
  10. -q 强制退出redis 仅显示query/sec值
  11. –csv 以CSV格式输出
  12. -I 生成循环,永久执行测试
  13. -t 仅运行以逗号分隔的测试命令列表
# 测试并发连接  100个并发连接  100000个请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000

在这里插入图片描述

在这里插入图片描述

redis的基本知识说明

  • redis默认有16个数据库,配置文件redis.conf中有说明,默认使用第0个数据库,可以使用select 进行切换数据库

  • dbsize 命令查看数据的大小
    在这里插入图片描述

  • 清除数据库内容命令 flushdb,清除所有数据库的内容命令flushall

  • 思考redis是单线程的!
    明白redis是很快的,官方表示,redis是基于内存操作,CPU不是redis的性能瓶颈,redis的性能瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了!所以就使用了单线程了!
    redis 是C语言写的,官方提供的数据为100000+的QPS,完全不比同样是使用key-value 的Memecache差!

  • Redis 为什么单线程还这么快?
    误区1: 高性能的服务器一定是多线程的?
    误区2: 多线程(CPU上下文会切换)一定比单线程效率高?
    核心: redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文会切换:耗时的操作!!!),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况下,这个就是最佳的方案.

redis的基本命令

  • keys * 查看所有的key

  • flushdb 清空当前数据库

  • flushall 清空所有的数据库

  • select 0 切换redis为0的数据库(有16个数据库)

  • dbsize 查看当前数据库的key的数量

  • exists key 查看key是否存在 存在返回1不存在返回0

  • move key 把这个key 移除当前redis数据库

  • expire key 10 设置key的过期时间为10秒

  • ttl key 查看key还有多久过期

  • type key 查看key是什么类型的

  • 后面遇到不懂的命令可以去redis中文官方文档中查看

  • redis英文网站

在这里插入图片描述

  • redis中文网站

在这里插入图片描述

String字符串类型详解

  • append key 在原有的key上追加字符串,若存在就追加,不存在就相当于set key

  • strlen key 查看key值得长度返回Integer类型

  • incr key 自动加一每执行一次就加一

  • decr key 自动减一每执行一次就减一

  • incrby key increment 自动加increment值,每执行一次就加increment值(步长)

  • decrby key increment 自动减increment值,每执行一次就自动减increment值

  • getrange key start end 截取字符串的长度 start开始位置,end结束位置
    区间是从第零个字符串开始的 闭区间 【1,3】

  • getrange key 0 -1 获取字符串 相当于get key

  • setex (set with expire) 设置过期时间

  • setnx (set if not exists) 不存在再设置(在分布式锁中会常常使用!)

  • setex key 30 value #设置key值30秒后过期

  • ttl key 查看过期时间

  • setnx key value 设置key如果不存在则设置成功并返回1如果存在则设置不成功并返回0

  • mset k1 v1 k2 v2 k3 v3 批量设置值

  • mget k1 k2 k3 批量获取值

  • msetnx k1 v1 k4 v4(批量set if not exists)
    注意!由于msetnx redis命令是原子操作的,上面msetnx k1 v1 k4 v4这个命令返回值为0设置失败,由于当前的k1已经存在k4不存在,redis的原子性操作导致k4 设置失败

  • set user:1 {name:zhangsan,age:3} 设置用户id=1的值

  • mset user:1:name zhangsan user:1:age 4 也可以批量设置用户为1的值实战中基本上使用这个设置方式

  • getset 先get后set getset db redis 如果不存在,则返回nil
    get db 返回redis , getset db mongodb 如果存在值,获取原来的值,并设置新的值

  • String数据结构使用的场景:value除了是字符串还可以是数字

  • 计数器 incr

  • 统计多单位的数量 mget

  • 粉丝数

  • 对象缓存存储 uid:name ly uid:age 28

List列表类型

在redis里面,我们可以把list玩成,栈、队列、阻塞队列!
所有的命令都是用“L” 开头。
常用命令如下:

  • lpush k v 将一个值或者多个值,插入到列表头部(左)
  • lrange k 0 -1 遍历list列表的值
  • rpush k v 将一个值或者多个值,插入到列表的尾部(右)
  • lpop k 从左边移除列表的第一个元素
  • rpop k 从右边移除列表的第一个元素
  • lindex k index 通过下标获得list中的某一个值
  • llen k 返回列表的长度
  • lrem k count v 移除list集合中指定个数的value,精确匹配
  • ltrim 修剪列表 ltrim k index1 index2 表示只要list集合中 下表index1 到index2的元素,这个list已经被改变了,截断了只剩下截取的元素!
  • rpoplpush 移除列表的最后一个元素,并将移除的元素添加到新指定的集合中(rpoplpush mylist myotherlist)
  • lset list index v 更新集合中指定的值(若不存在,则报错,只是更新原有的值为新值,若不存在则并不能添加新的),将列表中指定下标的值替换为另一个值,更新操作。
  • exists list 判断 list集合列表是否存在 不存在返回0 存在返回1
  • lset list 0 item 如果存在,更新当前下标的值
  • lset list 1 other 如果不存在,则会报错
  • linsert k [before|after] pivot value
    linsert mylist before “word” “hello” 在集合中‘word’ 元素前插入‘hello’ 元素
    将某个具体的value插入到列表中某个元素的前面或者后面。

小结:
list集合他实际上是一个链表,before node after ,left ,right 都可以插入值;
如果key不存在,创建新的列表;
如果key存在,新增内容;
如果移除了所有值,空链表,也代表不存在;
在两边插入或者改动值,效率最高,中间元素,相对来说效率会低一点;
消息队列(lpush rpop),栈(lpush lpop)

set集合

set中的值是不能重复的,set集合的命令都是s开头的

  • sadd key value 往set集合中添加值
  • smembers key 遍历set集合元素
  • sismember key value 判断该值是否存在在key集合中,存在返回1不存在返回0
  • scard key 获取key集合中的元素的个数
  • srem key v1 移除set集合中某一个元素
  • set 无序不重复集合,抽随机数
  • srandmember key 随机抽集合中的元素
  • srandmember key count 随机抽集合中的count个数元素
  • 删除指定的key,随机删除指定的key
  • spop key 随机删除key集合中的某个元素
  • smove key1 value key2 将一个指定集合中的元素移动到另一个key2集合中
  • sdiff key1 key2 取两个集合中的差集
  • sunion key1 key2 取两个集合中并集
  • sinter key1 key2 取两个集合中的交集
    微博,A用户将所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!共同关注,共同爱好,二度好友(六度分隔理论)

hash(哈希)

Map集合,key-<key,value> key-Map ! 值是map集合
set myhash field1 value1 field2 value2
hash 变更的数据 user name age 尤其是用户信息之类的,经常变动的信息!hash更适合于对象的存储,string更适合于字符串的存储。

  • hset k field1 value1 set一个具体的key-value
  • hget k field1 获取一个字段的值
  • hmset k field1 value1 field2 value2 set多个key-value
  • hmget k field1 field2 获取多个字段值
  • hgetall k 获取全部的数据
  • hdel k field1 删除hash指定的key字段,对应的value值也就消失了
  • hlen k 获取hash表的字段数量
  • hexists k field1 判断hash中指定字段是否存在
  • hkeys k 查看k中所有的key值
  • hvals k 查看k中所有的values值
  • hincrby k field 1 设置k中某个field自增1
  • hincrby k field -1 设置k中某个field自减1
  • hsetnx k field value 如果不存在则可以设置,若存在则不能设置

zset(有序集合)

在set的基础上增加一个值 set k1 v1 zset k1 score v1

  • zadd key score value

  • zrangebyscore key min max 显示全部的用户从小到大
    zrangebyscore key -inf +inf

  • zrevrange key 0 -1 从大到小进行降序

  • zrangebyscore key -inf +inf withscores 显示全部用户并且附带成绩

  • zrangebyscore key -inf 2500 显示成绩小于2500的升序排序

  • zrem key value 移除有序集合中的指定元素

  • zrange key 0 -1 遍历集合中的元素

  • zcard key 获取有序集合中的个数

  • zcount key 1 3 获取指定空间的成员数量
    案例思路:
    set排序 存储班级成绩表,工资排序表
    普通消息 1 重要消息2 带权重进行判断,排行榜应用实现取Top N

geospatial 地理位置

朋友的定位,附近的人,打车距离计算?
redis的geo在redis3.2版本就推出了这个功能可以推算地理位置的信息,两地之间的距离,方圆几里的人
可以查询一些测试数据:
http://www.json.cn/lngcodeinfo/0706D99C19A781A3/
只有六个命令

在这里插入图片描述

#geoadd 
#添加地理位置
#规则:两极无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入!
#参数key值(经度、纬度、名称)
#有效的经度从-180度到180度,有效的纬度从-85.05112878度到85.05112878度
#当坐标位置超出上述指定范围时,该命令将会返回一个错误。

127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing  #添加城市坐标
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing 114.05 22.52  shenzhen
(integer) 2
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou
(integer) 1
127.0.0.1:6379> geoadd china:city 108.96 34.26 xian
(integer) 1
127.0.0.1:6379>
#geopos
#获取指定的城市的经度和纬度
#获取当前定位一定是一个坐标值!
127.0.0.1:6379> geopos china:city beijing
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
127.0.0.1:6379> geopos china:city shanghai
1) 1) "121.47000163793563843"
   2) "31.22999903975783553"
127.0.0.1:6379>

#getdist
#两人之间的距离
#单位:m=米  km=千米  mi=英里  ft=英尺
# 查看两地之间的距离默认是米
127.0.0.1:6379> geodist china:city beijing shanghai
"1067378.7564"
#查看两地之间的距离可以指定单位 km
127.0.0.1:6379> geodist china:city beijing shanghai km
"1067.3788"

#georadius 以给定的经纬度为中心,找出某一半径内的元素
#例如:我附近的人?(获得所有附近的人的地址,定位!)通过半径来查询!
#获得指定数量的人如 200 所有城市数据都应该录入,才会让结果更加清楚
#以100 30 这个经纬度为中心,寻找方圆1000km内的城市
127.0.0.1:6379> georadius china:city 110 30 1000 km
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"

127.0.0.1:6379> georadius china:city 110 30 500 km
1) "chongqing"
2) "xian"
#显示到中间直线距离的位置
127.0.0.1:6379> georadius china:city 110 30 500 km withdist
1) 1) "chongqing"
   2) "341.9374"
2) 1) "xian"
   2) "483.8340"
#显示他人的定位信息
127.0.0.1:6379> georadius china:city 110 30 500 km withcoord
1) 1) "chongqing"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) 1) "108.96000176668167114"
      2) "34.25999964418929977"
#帅选出指定的结果   
127.0.0.1:6379> georadius chian:city 110 30 500 km withdist withcoord count 1
(empty list or set)
127.0.0.1:6379>

#georadiusbymember
#找出位于指定元素周围的其他元素
127.0.0.1:6379> georadiusbymember china:city beijing 1000 km
1) "beijing"
2) "xian"
127.0.0.1:6379> georadiusbymember china:city shanghai 400 km
1) "hangzhou"
2) "shanghai"
127.0.0.1:6379>

#geohash  命令返回一个或多个位置元素的geohash
#该命令将返回11个字符串的geohash字符串
#将二维的经纬度转换为一维的字符串,如果两个字符串越近,那么则距离越近
127.0.0.1:6379> geohash china:city beijing shanghai
1) "wx4fbxxfke0"
2) "wtw3sj5zbj0"
127.0.0.1:6379>

#geo底层实现原理其实就是zset!我们可以使用zset命令来操作geo!
#使用zrange 遍历地图中的全部元素
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
#使用zrem 删除key中的一个成员
127.0.0.1:6379> zrem china:city chongqing
(integer) 1
127.0.0.1:6379>

Hyperloglog

  • 简介
    redis在2.8.9版本添加了Hyperloglog结构,是用来做基数统计的算法,在redis里面,每个Hyperloglog 键只需要花费12kb内存,就可以计算接近2的64次方个不同的基数。因为Hyperloglog 只会根据输入元素来计算基数,而不会存储输入元素本身,所以Hyperloglog不能像集合那样,返回输入的值。
    小知识:什么是基数?
    比如数据集{1,3,5,7,7,8},那么这个数据集的基数集为{1,3,5,7,8 },基数(不重复元素)为5,基数估计是误差可节省的范围内。
    为什么需要Hyperloglog?
    如果要统计1亿个数据的基数值,大约需要内存 1亿/8/1024/1024 约12m,内存减少占用的效果显著。
  • 应用场景
    统计注册ip数
    统计每日访问ip数
    统计页面实时UV数(一个人访问一个网站多次,但还是算作一个人!)
    统计在线用户数
    统计每天搜索不同词条的个数
    统计真实文章阅读数
    传统的方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断!
    这个方式如果保存大量的用户id,就会比较麻烦!我们的目的是为了计数,而不是保存用户id;
    0.81%错误率!统计UV任务,可以忽略不计的!
    优点:占用的内存是固定的,2^64不同的元素的技术,只需要废12kb内存!如果要从内存角度来比较的话Hyperloglog首选!
  • 命令如下:
#创建第一组元素mykey
127.0.0.1:6379> pfadd mykey a b c d e f g h i j 
(integer) 1
#统计mykey元素的基数数量
127.0.0.1:6379> pfcount mykey
(integer) 10
#创建第二组元素mykey2
127.0.0.1:6379> pfadd mykey i j
(integer) 0
127.0.0.1:6379> pfcount
(error) ERR wrong number of arguments for 'pfcount' command
127.0.0.1:6379> pfcount mykey
(integer) 10
127.0.0.1:6379> pfadd mykey2 i j i j a b n f v g k
(integer) 1
127.0.0.1:6379> pfcount mykey2
(integer) 9
# 合并两组mykey mykey2 =>mykey3并集
127.0.0.1:6379> pfmerge mykey3 mykey myke2
OK
#查看并集的数量
127.0.0.1:6379> pfcount mykey3
(integer) 10

  • 总结
    Hyperloglog 是一种算法,并非redis独有,目的是做基数统计,故不是集合,不会保存元数据,知识记录数量而不是数值。
    耗费空间小,支持输入非常大体积的数据量。
    如果允许容错,那么一定可以使用Hyperloglog!
    如果不允许容错,就使用set或者自己的数据类型

Bitmaps

  • 简介
    位存储
    场景:
    1.统计疫情感染人数:0 1 0 1 0感染的是1 没有感染的是0
    2.统计用户信息,活跃,不活跃,登录,未登录 ,打卡 365天打卡
    两个状态的,都可以使用Bitmaps!
    Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0 和1 两个状态。
    365天 = 365bit 1字节=8bit 46个字节左右!

  • 使用场景
    使用bitmaps 来记录周一到周日的打卡!!!
    周一 :1 周二:0

127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 0
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 1
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0
#查看第五天是否打卡 1=打卡
127.0.0.1:6379> getbit sign 5
(integer) 1
#查看第六天是否打卡 0=未打卡
127.0.0.1:6379> getbit sign 6
(integer) 0
# 统计这周打卡的次数
127.0.0.1:6379> bitcount sign
(integer) 4

redis基本的事务操作

redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!
一次性、顺序性、排它性!执行一些列的命令

---------  队列    set    set    set   执行 ------------

redis事务没有隔离级别的概念!
所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行!
redis单条命令保证原子性,但是事务不保证原子性!

  • 开启事务(multi)
  • 命令入队(…)
  • 执行事务(exec)
正常执行事务!
#开启事务
127.0.0.1:6379> multi
OK
#命令入队
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
#执行事务
127.0.0.1:6379> exec
1) OK
2) OK
3) "v2"
4) OK

放弃事务!
#开启事务
127.0.0.1:6379> multi
OK
#命令入队
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
#取消事务
127.0.0.1:6379> discard
OK
#set k4 v4  命令失效
127.0.0.1:6379> get k4  #事务队列中的命令都不会被执行!
(nil)

编译性异常(代码有问题!命令有错!),事务中所有的命令都不会被执行!
127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> getv1 k1  #错误命令
(error) ERR unknown command `getv1`, with args beginning with: `k1`,
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2 v2  #错误命令
(error) ERR wrong number of arguments for 'get' command
127.0.0.1:6379> exec   #执行事务报错,所有命令都不会被执行
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1   #执行事务报错,所有命令都不会被执行
(nil)

运行时异常(1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!
127.0.0.1:6379> set k1 v1  #先设置一个key为字符串类型的
OK
127.0.0.1:6379> multi   #开启事务
OK
127.0.0.1:6379> incr k1   #对一个字符串进行加一操作
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec  #执行事务,
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
127.0.0.1:6379> get k2  #事务没有报错,正常执行
"v2"
127.0.0.1:6379> get k3 #虽然第一条命令报错了,但是依旧正常执行成功了!
"v3"

redis监视测试

 - 悲观锁:很悲观,认为什么时候都会出问题,无论做什么都会加锁
 - 乐观锁:很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据。

#正常执行成功
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money  #监视money对象
OK
127.0.0.1:6379> multi #事务正常结束,数据期间没有发生变动,这个时候就正常执行成功!
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> get money
QUEUED
127.0.0.1:6379> get out
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20
3) "80"
4) "20"

测试多线程修改值,监视失败!使用watch可以当作redis的乐观锁操作!
#第一个线程执行命令如下(当第二个线程正准备执行exec命令时,第一个线程执行)
127.0.0.1:6379> set money 1000
OK

#第二个线程执行命令如下
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money  #监视money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
#执行之前,另外一个线程,修改了我们的值,这个时候,就会导致事务执行失败!
127.0.0.1:6379> exec  
(nil)

127.0.0.1:6379> unwatch  #1.如果发现事务执行失败,就先解锁
OK
127.0.0.1:6379> watch money  #2.获取最新的值,再次监视, select version
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 10
QUEUED
127.0.0.1:6379> incrby out 10
QUEUED
#比对监视的值是否发生了变化,如果没有变化,那么可以执行成功,如果变了就执行失败
127.0.0.1:6379> exec 
1) (integer) 990
2) (integer) 10
127.0.0.1:6379>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值