文章大纲:
1.官方中文文档
2.linux下安装
- 官网下载安装包 redis-6.0.6.tar.gz
- 放到服务器的usr/local/redis目录下
- 解压:
tar -zxvf redis-6.06.tar.gz
- 在redis目录下进行基本的环境安装:
yum install gcc-c++
- 检查gcc的版本:
gcc -v
- 在redis目录下执行
make
(若报错可能是gcc的版本问题)
- 执行
make install
- 进入/usr/local/bin目录,这是redis的默认安装目录。在这个目录创建一个myredisconfig的文件夹。然后将/usr/local/redis/redis-6.0.6下的redis.conf拷贝到这个文件夹下
- 设置为后台自动启动:修改myredisconfig目录下的redis.conf
daemonize no
改为daemonize yes
,然后:wq!
保存退出
- 通过配置文件启动redis(在/usr/local/bin目录下)
redis-server myredisconfig/redis.conf
- redis客户端测试连接
redis-cli -p 6379
ping
- 退出redis
shutdown
exit
- 查看redis进程
ps -ef|grep redis
3.安装出现的问题
- 在安装redis6以上的版本时make命令会出现错误,原因是gcc版本太低(centos默认版本为4),可以选择安装低版本redis5或者升级gcc到8版本,通过gcc -v命令查看版本.
- 升级gcc版本的方法
- 压力测试工具
redis-benchmark是官方自带的性能测试工具,可以有效的测试redis服务的性能。在bin目录下。
测试demo:
测试100个并发连接,10000个请求,检测host为localhost 端口为6379的redis服务器性能。
redis-benchmark -h localhost -p 6379 -c 100 -n 10000
相关参数说明:
- 基本的数据库命令
- redis命令手册:redis.com.cn/commands.ht…
- redis默认有16个数据库 0~15,默认使用第0个。
查看redis.conf可以得知:
- 进入redis:
redis-server myredisconfig/redis.conf
redis-cli -p 6379
- 退出redis:
shutdown
exit
- 输入密码:
auth 311046
- 切换数据库:
select n
n表示第几个数据库 - 查看当前数据库的key的数量:
dbsize
- 查看具体的key:
key *
- 清空当前库:
flushdb
- 清空全部的库:
flushall
- 设置key值:
set name coderchen
- 获取key值:
get name
- 查看 key是否存在:
exists keyname
例如 exists name - 设置key生存时间当key过期会被自动删除:
expire key 秒数
- 查看还有多少秒过期:
ttl name
-1表示永不过期,-2表示已经过期。 - 查看key的类型:
type key
- 删除key:
del key
注意:redis命令不区分大小写,但是记录的数据区分大小写
- 为什么redis默认端口是6379?
- redis单线程快?
- 为什么redis是单线程?
redis是基于内存的操作,cpu不是redis的瓶颈,redis的瓶颈是机器内存大小或者网络带宽。既然单线程容易实现而且cpu不会成为瓶颈,那么就顺理成章的采用单线程的方案了。redis是C语言编写的,官方数据可以达到100000+QPS(每秒查询次数)
- redis为什么这么快?
并不是多线程一定比单线程快,效率高。这与cpu,内存,硬盘的速度有关。
redis单线程快是因为redis是基于内存的操作。单线程效率最高,因为多线程的本质就是cpu模拟多个线程的情况,这其中有一个大的开销就是cpu上下文的切换。而redis单线程对内存中的数据进行读写时,速度比较快。举个例子就是读取1MB的数据时,可能多个进程cpu上下文的切换时间就大于单个进程读取数据的时间
key值加引号和不加的区别?
7.字符串String(单值单value)
- string是redis 的基本类型,一个key对应一个value。string类型是二进制安全的,即redis的string可以包含任何数据,比如jpg图片或者序列化的对象,string类型redis最基本的数据类型,一个redis中字符串value最多可以是512M
常用命令说明:
官方命令手册:redis.com.cn/commands.ht…
string数据结构是简单的key-value类型,value不仅可以是string,也可以是数字。
append key1 "hello"
:对不存在的key进行append,等同于set key1 "hello"
append key1 ",world"
:对已经存在的key append就是在后面追加。strlen key1
:获取字符串长度
set views 0
:要设置为数字才能用incr,decr命令 ,本质上这是一个字符串操作,因为Redis没有专门的整数类型。存储在 key 中的字符串被转换为十进制有符号整数incr views
:执行一次就将key中存储 的数字值增一decr views
:执行一次就将key中存储的数字值减一incrby views 10
:执行一次key中存储的值+10decrby views 10
:执行一次key中存储的值-10
getrange key2 m n
:获取[m,n]区间范围内的字符串。n可以为负数,表示偏移,-1 表示最后一个字符, -2 表示倒数第二个字符,以此类推。setrange key2 n value
:将key2的值从第n个开始替换为指定的valuesetex key2 10 "hello"
:将key2的值设置为hello,并且key2的生存时间设置为10s。这个命令等价于set key2 "hello"
expire key2 10
但区别是setex 命令是一个原子操作,在同一时间内完成设置值和设置过期时间这两个操作。setnx key3 "redis"
:在指定的key不存在时,为key设置指定的值,这种情况下等同于set,当key存在时,什么也不做。返回值:0 被设置了 1 没有被设置。
mset key1 value1 key2 value2 ......keyn valuen
:设置多个key和value,如果这其中已经存在key,则会覆盖掉。mget key1 key2 ...keyn
:返回所有给定的key的值msetnx key1 value1 key2 value2 ...keyn valuen
:设置多个 key value,当且仅当所有给定的健都不存在时,即使有一个健存在值,msetnx也会拒绝执行操作。
getset key value
:将key的值修改为value,并返回在修改之前的值。如果key在执行这个命令前不存在,则返回nil。
- 可以用来缓存对象
mset user:1:name zhangsan user:1:age 2
mget user:1:name user:1:age
应用
- 微博数,粉丝数等
- 列表List(单值多value)
- redis的列表是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边)
- 它的底层就是一个链表
常用命令说明
官方命令手册:redis.com.cn/commands.ht…
lpush list "one"
:将值插入到列表的头部(左边)rpush list "two"
:将值插入到列表的尾部(右边)lrange list n m
:返回指定区间的元素 [n,m] m为-1表示返回n后面所有的元素。
lpop list
:移除并返回列表的第一个元素,左边的第一个rpop list
:移除并返回列表的最后一个元素,右边第一个。
lindex list n
:按照索引下标n获得元素(-1代表最后一个,0表示第一个,以此类推)
llen list
:返回列表的长度
lrem list n value
:移除列表中与value相等的元素,移除n个,顺序是从前往后。n>0 从头到尾删除值为value的元素, n<0,从尾到头删除值为value的元素, n=0,移除所有值为value的元素
ltrim list n m
:对一个列表进行修剪,只保留区间[n,m]内的元素。其他全部删除。
rpoplpush list1 list2
:移除列表list1的最后一个元素,并将该元素添加到list2的前边。这个操作是原子性的。从6.2.0起被废除了。
lset list n value
:将list中第n个元素的值设置为value
linsert list before|after value value1
:将value1插入到value的前边或者后边。
性能总结
- 它是一个字符串列表,left,right都可以插入添加
- 如果键不存在,创建新的链表。
- 如果已经存在,新增内容
- 如果值全部移除,对应的键也就消失了
- 链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就比较低。
应用
- 最新消息排行功能
- 消息对列
- 集合Set(单值多value)
- redis的集合set是string类型的无序集合,是通过HashTable实现的。
常用命令说明
sadd key member[...]
:将一个或者多个成员元素加入到集合中。smembers key
:返回存储在key中的所有成员sismember key member
:判断元素member是否是集合key中的成员。返回1表示是,0表示不是。
scrad key
:返回集合中元素的数量。
srem key value
:移除集合key中的一个或者多个元素value
srandmember key [count]
:返回集合key中的随机元素,count表示返回几个元素。
spop key [count]
:从集合key中删除一个或者多个元素,并返回删除的元素。(删除是随机的)
smove key1 key2 member
:将指定的元素从集合key1移动到key2 。这是一个原子操作。
sdiff key [key...]
:返回第一个集合key与其他key之间的差异,即第一个集合key独有的元素。sinter key [key...]
:返回所有给定集合key的成员交集sunion key [key...]
:返回所有给定集合key的并集
应用
- 实现共同关注,共同好友等功能。
- 哈希Hash(单值多value,v是一个键值对)
- Hash是一个键值对集合,类似于java中的map,是一个String类型的field和value的映射表,特别适合存储对象。
常用命令
hset key field value [field value ....]
: 为哈希表key的field字段赋值hget key field
:返回哈希表key中的field字段的值hgetall key
:返回哈希表key中所有的域和值hdel key field [field...]
:删除哈希表key中的一个或者多个指定字段。
hlen key
:获取哈希表key中的字段fields的数量
hexists key field
:查看哈希表的指定字段field是否存在。0表示不存在,1表示存在hkeys key
:返回哈希表key中所有的域fieldhvals key
:返回哈希表中所有域的值
hincrby key field increment
: 为哈希表key中的域field的值加上增量increment.增量为负数表示进行减法操作。
hsetnx key field value
:为哈希表中不存在的字段field赋值为value。0表示设置失败,1表示设置成功。
应用
- Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。 存储部分变更的数据,如用户信息等。
- 有序集合Zset
- 在set基础上,加上一个score。之前set是sadd set1 v1 v2 v3…,现在Zset是zadd zset1 score1 v1 score2 v2。
常用命令
zadd key score1 member1[score2 member2...]
:将一个或者多个member元素及其score值加入到有序集合key中。其中score可以是整数值或者双精度浮点数。可以为正或者负数zrange key n m
:返回有序集合key中的[n,m]区间内的元素。下标从0开始。如果m超出范围也不会报错,只会返回包含的。
zrangebyscore key n m
:返回有序集合key中的成员,按照score的从小到大排序,范围是[n,m],n,m可以为-inf,+inf,这样在不知道有序集合数量的时候获取所有的成员。注意[n,m]这个范围是score的范围,不是成员的下标
zrem key member1[member2...]
:从有序集合key中删除指定的成员member
zcard key
:返回有序集合key中的成员个数
zcount key n m
:返回有序集key中,score在[n,m]之间的成员数量。
zrank key member
:返回有序集key中成员的排名,按照score从低到高排名,从0开始
zrevrank key member
:返回有序集key中成员的排名,按照score从高到低排名,从0开始
应用
- 排行榜应用,取top n操作。
- 三种特殊的数据类型
12.1 GEO地理位置
简介:
redis的GEO特性在redis3.2版本中推出,这个功能可以将用户给定的地理位置信息存储起来,并对这些信息进行操作。来实现诸如附近位置,摇一摇这类依赖于地理位置信息的功能。GEO的数据类型为Zset。
GEO的数据结构总共有六个常用命令:geoadd ,geopos ,geodist , georadius, georadiusbymember , gethash
官方文档:www.redis.net.cn/order/3685.…
命令:
geoadd
将指定的地理空间位置(经度,纬度,名称)添加到指定的key中。这些数据会存储到有序集合Zset中,目的是为了方便使用georadius,或者georadiusbymember命令对数据进行半径查询等操作。
geoadd china:city 121.48 31.40 shanghai 113.88 22.55 shenzhen 120.21 30.20 hangzhou
注意点:该命令采用标准格式的参数xy,所以经度必须在纬度之前。有效的经度 -180~180度,有效的纬度 -85.05~85.05
geopos
从key里面返回所有给定位置元素的位置(经度和纬度)
geopos key member[member...]
geopos china:city shanghai hangzhou
geodist
返回两个给定位置之间的距离,指定的参数unit必须是以下中的一种。m 米 ,km 千米, mi 英里,ft 英尺,默认是m。
geodist key member1 member2 [unit]
geodist china:city shanghai hangzhou km
georadius
以给定的经纬度为中心,找出某一半径内的元素。
范围的单位:m米,km千米 ,mi英里 ,ft英尺
georadius key longitude(经度) latitude(纬度) radius m|km|ft|mi [withcoord] [withdist][withhash][asc|desc][count count]
withdist:返回位置元素的同时,将位置元素与中心之间的距离也一并返回。距离的单位与用户给定范围单位保持一致。
withcoord:将位置元素的经纬度也返回。
withhash:以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大
asc: 根据中心的位置, 按照从近到远的方式返回位置元素。
desc:根据中心的位置, 按照从远到近的方式返回位置元素。
count:获取前n个匹配的元素,可以减少带宽当数据量大时。
举例:
georadius china:city 120 30 1500 km withdist
georadiusbymember
找出位于指定范围内的元素,中心点是由给定的位置元素决定的。
georadiusbymember key member radius m|km|ft|mi [withcoord][withdist][withhash][asc|desc][count count]
举例:
georadiusbymember china:city shanghai 1500 km
geohash
返回一个或者多个位置元素的geohash表示。
redis使用geohash将二维经纬度转换为一维字符串,字符串越长表示位置更精确,两个字符串越相似表示距离越近。
geohash key member[member...]
举例:
geohash china:city shanghai hangzhou
zrem
geo没有提供删除成员的方法,但是因为geo的底层是zset,所有可以用zrem命令实现对地理位置信息的删除。
zrem china:city shanghai
:移除元素
zrange china:city 0 -1
:查看所有元素
命令演示
12.2 HyperLogLog
简介
redis在2.8.9版本添加了HyperLogLog结构。
redis HyperLogLog是用来做基数统计的算法。HyperLogLog的优点是在输入元素的数量和体积非常大时,计算基数所需的空间总是固定的,并且很小。
基数:比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。
在redis里面,每个HyperLogLog键只需要花费12kb内存,就可以计算接近2^64个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
HyperLogLog则是一种算法,提供了不精确的去重基数方案。
举个栗子:假如我要统计网页的UV(浏览用户数量,一天内同一个用户多次访问只能算一次),传统的 解决方案是使用Set来保存用户id,然后统计Set中的元素数量来获取页面UV。但这种方案只能承载少量 用户,一旦用户数量大起来就需要消耗大量的空间来存储用户id。我的目的是统计用户数量而不是保存 用户,这简直是个吃力不讨好的方案!而使用Redis的HyperLogLog最多需要12k就可以统计大量的用户 数,尽管它大概有0.81%的错误率,但对于统计UV这种不需要很精确的数据是可以忽略不计的
基本命令
pfadd key element[element...]
:添加指定元素到HyperLogLog
pfcount key[key...]
:返回给定HyperLogLog的基数估计值。
pfmerge destkey sourcekey [sourcekey...]
:将多个HyperLogLog合并为一个HyperLogLog,并集计算。
12.3 BitMap
简介
在开发中,可能会遇到这种情况:需要统计用户的某些信息,如活跃或不活跃,登录或者不登录;又如 需要记录用户一年的打卡情况,打卡了是1, 没有打卡是0,如果使用普通的 key/value存储,则要记录 365条记录,如果用户量很大,需要的空间也会很大,所以 Redis 提供了 Bitmap 位图这种数据结构, Bitmap 就是通过操作二进制位来进行记录,即为 0 和 1;如果要记录 365 天的打卡情况,使用 Bitmap 表示的形式大概如下:0101000111000111………………………,这样有什么好处呢?当然就是节约内存 了,365 天相当于 365 bit,又 1 字节 = 8 bit , 所以相当于使用 46 个字节即可。
BitMap 就是通过一个 bit 位来表示某个元素对应的值或者状态, 其中的 key 就是对应元素本身,实际上 底层也是通过对字符串的操作来实现。Redis 从 2.2 版本之后新增了setbit, getbit, bitcount 等几个 bitmap 相关命令。
基本命令
setbit key n value
:设置key的第n位的值value是0或1,n是从0开始的。getbit key n
:获取第n位的值。如果没有设置返回0bitcount key[start,end]
:统计key上值为1的个数。
- redis事务
理论
redis事务的概念:
redis事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有的命令都会被序列化。在事务执行过程中,会按照顺序串行化执行对列中 的命令,其他客户端提交的命令请求不会插入到事务执行的命令序列中。
总结的说:redis事务就是一次性,顺序性,排他性的执行一个对列中的一系列命令。
redis事务没有隔离级别的概念:
批量操作在发送exec命令前被放入对列缓存,并不会被实际执行。
redis不保证原子性:
redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。
redis事务的三个阶段:
开始事务
命令入队
执行事务
redis事务的相关命令
watch key1 key2...
:监视一个或者多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断(类似乐观锁)unwatch
:取消watch对所有key的监控。multi
:标记一个事务块的开始(queued)exec
:执行所有事务块的命令(一旦执行exec后,之前加的监控锁都会被取消掉)discard
:取消事务,放弃事务块中所有 的命令
乐观锁和悲观锁?
- 悲观锁(Pessimistic Lock),顾名思义就是很悲观,每次拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿到这个数据就会block知道它拿到锁。传统的关系型数据库里面就用到了很多这种锁机制,比如行锁,表锁等,读锁写锁等,都是在操作之前先上锁。
- 乐观锁(Optimistic Lock)顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制,乐观锁适用于多读的应用类型,这样可以提高吞吐量,乐观锁策略:提交版本必须大于记录当前版本才能执行更新。
实践
- 正常执行
- 放弃事务
- 如果事务对列中存在命令性错误(类似java编译性错误),执行exec命令时,所有命令都不会执行。
- 如果在事务对列中存在语法性错误(类似于java的1/0运行时异常),则执行exec命令时,其他正确命令会被执行,错误命令抛出异常。
- watch命令的演示(watch 用来监控key在事务执行的前后是否变化)–事务成功执行
- 使用watch–事务执行失败
由于在事务执行过程中,watch监视的值出现了变化,因此导致了错误,这时要放弃监视,然后重来。
**注意:**一旦exec执行事务后,无论事务执行成功还是失败,watch对变量的监控都被取消。因此当事务执行失败后,需要重新执行watch对变量进行监控,并开启新的事务进行操作。
watch指令类似于乐观锁,事务提交时,如果watch监控的多个key中任何key的值被其他客户端更改,则使用exec执行事务时,事务对列不会被执行,同时返回Nullmulti-bulk 通知调用者事务执行失败。
- springboot整合redis
步骤:
- 导入依赖
1 | xml复制代码<dependency> |
- 在application.properties中配置
1 | properties复制代码spring.redis.host=115.29.232.195 |
- 测试
1 | java复制代码@SpringBootTest |
redis要做的配置
- 阿里云设置redis的安全组:端口6379
- 修改redis.conf
(在/usr/local/bin/myredisconfig/redis.conf)
bind 127.0.0.1 改为 bind 0.0.0.0(注释掉也行)
protected-mode yes 改为 protected-mode no: (即该配置项表示是否开启保护模式,默认是开启,开启后Redis只会本地进行访问,拒绝外部访问)
daemonize no 改为 daemonize yes
注意:修改后要重新登录redis
- 关于防火墙的设置
rpm -qa|grep firewalld;rpm -qa|grep firewall-config
:检查系统是否安装了firewalld和firewall-config.CentOS中系统默认安装firewalld, firewall-config要自己安装
yum -y update firewalld
:将firewalld更新为最新版
yum -y install firewall-config
:安装firewall-config
systemctl start firewalld
:启动firewalld服务
systemctl status firewalld
:查看firewalld的状态
systemctl stop firewalld
:停止firewalld服务
systemctl enable firewalld
:恢复开机自动启动firewalld服务
推荐参考文章:CentOS7中firewalld的安装与使用详解 blog.csdn.net/solaraceboy…
- 检查阿里云的防火墙是否开放端口号
firewall-cmd --query-port=6379/tcp
如果是 yes,则就是开放的。
如果是no
则永久开放6379端口:firewall-cmd --zone=public --add-port=6379/tcp --permanent
重新加载:firewall-cmd --reload
然后再查看端口是否开启:firewall-cmd --query-port=6379/tcp
- 查看redis服务进程
1 | perl复制代码 ps -ef | grep redis |
- 如果上面的方法都试过了但还是不行,试试重启服务器
推荐一个好用的redis客户端工具
Another Redis Desktop Manager
可以用它来测试和管理redis
redis的序列化配置
- 通过源码可知,springboot自动帮我们在容器中生成了一个redisTemplate和一个StringRedisTemplate,但是这个redisTemplate的泛型是<ooject,object>,写代码不方便,需要类型转换的代码,并且没有设置数据存在redis时,key及value的序列化方式。因此要自定义一个配置类。
- 为什么要序列化:www.jianshu.com/p/cc5a29b06…
1 | java复制代码package com.kuang.config; |
redis的工具类
- 直接使用redisTemplate操作redis时,需要很多代码,因此直接封装一个redisUtils,这样写代码方便一点。这个redisUtils交给spring容器实例化,使用时直接注解注入。
1 | java复制代码package com.kuang.utils; |
测试代码
1 | kotlin复制代码package com.kuang; |
本文转载自: 掘金