1 redis简介与安装
1.1 redis简介
Redis 是完全开源免费的,遵守BSD协议,是一个高性能(NOSQL)的key-value数据库,Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
redis在4.0之前采用单线程,主要是因为维护更简单并且对比redis性能来说拼接在于内存和带宽不在cpu,在4.0之后引入惰性删除,不使用主线程操作,而是使用异步的方式,有效避免删除大数据对象时主线程出现卡顿情况。
1.2 redis应用场景
1.2.1 配合关系型数据库做高速缓存
- 高频次,热门访问的数据,降低数据库IO
-
1.2.2 多样数据结构存储持久化数据
使用List的数据类型 可以实现自然排序的场景
- 利用zset 实现排行榜功能
- 利用过期时间 存储时效性数据 例如手机验证码
- 利用原子性 可以实现秒杀 分布式锁
- 利用set集合去重
- 利用list集合构建简单队列
- pub/sub模式 实现发布订阅系统
1.3 docker 安装 redis 并且设置密码
docker run --name redis -id -p 16379:6379 redis:latest --requirepass "123456"
1.4 安装包安装 redis
1.4.1 官网下载安装包
1.4.2 解压到一个目录下
tar -zxvf redis-6.2.6.tar.gz
1.4.3 进入目录中 执行make命令 在 /user/local/bin 目录下就可以看见安装的内容
redis-benchmark:性能测试工具 redis-check-aof:修复有问题的AOF文件 redis-check-dump:修复有问题的dump.rdb文件 redis-sentinel:Redis集群使用 redis-server:Redis服务器启动命令 redis-cli:客户端,操作入口
1.4.4 前台启动 不推荐
1.4.5 后台启动 推荐
使用配置文件启动 拷贝一份配置文件redis.conf 到其他目录 修改
设置reids密码 阿里云服务器一定要设置密码 不然服务暴露会被挖矿盯住
默认绑定127.0.0.1 放开后就可以使用可视化工具管理
2 redis五大基本类型与三个新数据类型
2.1 redis 键(key)操作
#查看当前库所有keykeys *#判断某个key是否存在exists <key>#查看key的类型type <key>#删除指定keydel <key>#根据value选择非阻塞三次 仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作unlink <key>#给key设置过期时间 time是时间 单位秒expire <key> <time>#查看还有多少秒过期,-1表示永不过期,-2表示已过期ttl <key>#切换数据库select 0~15#查看当前数据库的key的数量dbsize#清空当前库flushdb#清除全部库flushall
2.2 Redis 字符串(String)
String字符串是redis最基本的类型。String类型是二进制安全的,意味着Redis可以包含任何数据或者序列化的对象,一个字符串最大是512M。
redis中 setnx 的原子操作
所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何context switch (切换到另一个线程)。
- 在单线程中,能够在单条指令中完成的操作都可以认为是”原子操作”,因为中断只能发生于指令之间。
- 在多线程中,不能被其它进程(线程)打断的操作就叫原子操作。Redis单命令的原子性主要得益于Redis的单线程。
#添加键值对set <key> <value>#当数据库key不存在时 可以添加setnx <key> <value>#添加键值对 并设置过期时间 单位秒setex <key> <time> <value>#查询key对应的valueget <key>#将给定的<value> 追加到原值的末尾append <key> <value>#查询值的长度strlen <key>#将key中存储的value (integer 类型)加1incr <key>#将key中存储的value (integer 类型)减1decr <key>#将key增加指定的数字incrby <key> <num>#将key减少指定的数字decrby <key> <num>#同时设置一个或多个 key-value对mset <k1> <v1> <k2> <v2> <k3> <v3> ...#同时设置一个或多个 key-value对 当且仅当key不存在时(原子性操作)msetnx <k1> <v1> <k2> <v2> <k3> <v3> ...#同时获取一个或多个valuemget <k1> <k2> <k3> ...#以旧换新 设置新值的同时拿出旧值getset <key> <value>
2.3 Redis 列表(List)
redis列表是一个单键多值的格式。一个简单的字符串列表。按照插入顺序排序。可以从头部(左边)或者尾部(右边)插入数据。
它的底层是个双向链表,对两端的操作性能很高,通过索引下标操作中间的节点性能会比较差。数据结构
List的数据结构为快速链表quickList。
在列表元素较少的情况下会使用一块连续内存存储也就是ziplist 压缩列表。它将所有元素紧挨着一起存储,分配的是一块连续的内存,当数据量比较多的时候才会改成quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。
Redis将链表和ziplist结合起来组成了quicklist,也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
#从左边添加一个或多个值lpush <key> <v1> <v2> <v3> ...#从右边添加一个或多个值 (尽量不要用 常用lpush)rpush <key> <v1> <v2> <v3>...#从左边拿出一个值lpop <key>#从右边拿出一个值rpop <key>#从第一个列表右边取第一个值到第二个列表左边rpoplpush <k1> <k2>#按索引下标从左边查询列表的值 lrange key 0 -1 查询所有值lrange <key> <start> <end>#按照索引下标拿出值(左到右)lindex <key> <index>#获得列表长度llen <key>在列表中值value后面插入newvalue的值linset <key> before <value> <newvalue>从左边删除n个value(从左到右) 列表中允许多个相同的valuelrem <key> <n> <value>将列表中下标为index的值替换成value (下标从0开始)lset <key> <index> <value>
2.4 Redis 集合(Set)
redis set 是类似于redis list的一个列表功能。特殊之处在于set可以自动去重 ,功能类似java中的set集合。redis中的set是string类型的无需集合,底层是一个value为null的hash表,所以增删查复杂的都是O(1)。#将数据添加到set集合sadd <key> <v1> <v2> <v3> ...#读取集合中的值smembers <key>#判断集合key中是否含有v的值 有1无0sismember <key> <v>#返回集合中元素的个数scard <key>#删除集合中某个或多个元素srem <key> <v1> <v2> ...#从集合中随机拿出一个值(会删除)spop <key>#随机从集合中查询n个值 不会从集合中删除srandmember <key> <n>#将集合中一个值移动到另一个集合中smove <k1> <k2> <value>#返回两个集合的交集sinter <k1> <k2>#返回两个集合的并集sunion <k1> <k2>#返回两个集合的差集 谁在前包含谁(包含k1 不包含k2)sdiff <k1> <k2>
2.5 Redis 哈希(Hash)
Redis hash 是一个键值对集合。redis hash是一个string类型的field -value映射表 特别适合存储对象,类似于java中map结构。数据结构
Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。#给哈希集合赋值hset <key> <field1> <value1> <field2> <value2> <field3> <value3> ...#取出哈希集合中field中的valuehget <key> <field>#查看哈希集合中域field对应的value是否存在hexists <key> <field>#列出该哈希集合中所有的fieldhkeys <key>#列出该哈希集合中所有的valuehvals <key>#给哈希表中域field对应的value 加减指定的numhincrby <key> <field> <num>#给哈希表中field设置为对应的value 当且仅当field不存在时hsetnx <key> <field> <value>
2.6 Redis 有序集合(Zset)
Zset有序集合和set普通集合非常相似,是一个没有重复元素的字符串集合。不同之处在于每个成员都关联了一个评分(score) ,这个评分用于成员中的排序(低到高)。集合中成员是惟一的,但是评分是可以重复的。
因为成员是有序的 所以可以根据评分或者次序来获取一个范围内的元素。数据结构
SortedSet(zset)是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构Map,可以给每一个元素value赋予一个权重score,另一方面它又类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。
zset底层使用了两个数据结构
(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。
(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。#给有序集合赋值zadd <key> <score1> <v1> <score2> <v2> <score3> <v3> ...#返回有序集合下标(分数)在 start->stop中的元素 如果要显示分数可以加withscoreszrange <key> <start> <stop> [withscores]#返回有序集合中 score介于 min到max(都包含) 的值 返回结果按照score递增 如果要显示分数可以加withscores 可以截取需要返回从哪个下标开始 多少个zrangebyscore <key> <min> <max> [withscores] [limit offset count]#翻转 返回有序集合中 score介于 max到min(都包含) 的值 返回结果按照score递增 如果要显示分数可以加withscores 可以截取需要返回从哪个下标开始 多少个zrevrangebyscore <key> <max> <min> [withscores] [limit offset count]#为有序列表中元素增加分值zincrby <key> <score> <value>#删除该集合下,指定的元素zrem <key> <value>#统计集合中分数区间内元素个数zcount <key> <min> <max>#返回该值在集合中的排名 从0开始zrank <key> <value>
2.7 Redis Bitmaps
Bitmaps是一种特殊的“数据结构”,实质上是一个字符串,操作单元是位。
Bitmaps单独提供了一套命令,所以在Redis中使用Bitmaps和使用字符串的方法不太相同。可以把Bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在Bitmaps中叫做偏移量。
应用场景:
- 用于统计访问量
- 应用于布隆过滤器
Bitmaps与set对比
假设一亿数据量,假设每天独立访问有5千万
| 数据类型 | 存储量 | 需要存储的用户量 | 一天 |
|---|---|---|---|
| set | 64位 | 五千万 | 64位*50000000 = 400MB |
| Bitmaps | 1位 | 一亿 | 1位*100000000= 12.5MB |
当访问用户很少的情况下 bitmap就不适用了 ,bitmap大部分都是0,反而使内存增高。
#设置或修改 bitmaps offset:偏移量,从0开始setbit <key> <offset> <value>#获取bitmaps 中某个偏移量的值getbit <key> <offset>#统计 被设置为1 的bit数 可选从 start 字节 到 end 字节bitcount <key> [start end]#多个bitmap的复合操作(交集/并集/非/异或)并将结果报错到destkey中bitop <key> (and/or/not/xor) <destkey> key [key2 ...]
2.8 HyperLogLog 基数统计
基数统计简单来说就是去重复元素的统计
解决基数统计可以用 mysql的 distinct count;redis的hash、set、bitmaps等数据结构来处理。但是随着数据量不断增加,占用空间越来越大,对于非常大的数据是不切实际的。
HyperLogLog : 能够降低一定的精度来平衡存储空间。在输入元素数量或者统计非常大时,计算基数所需要的空间总是固定的,并且是很小的。在redis中每个HyperLogLog占用12kb可以存2^64个不同的基数。 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以HyperLogLog不能像集合那样返回元素本身,只能计算基数个数。
#添加指定元素到HyperLogLog中pfadd <key> <element>[element ...]#统计基数个数 可以多个key合并统计基数pfcount <key> [key2 key3 ...]#将一个或多个HLL 合并到一个新的HLL中pfmerge <destkey> <sourcekey>[sourcekey ...]
2.9 Geospatial 地理信息
redis3.2开始增加了元素二位坐标列类,也就是经纬度。提供了经纬度设置、查询、范围查询、距离查询、经纬度hash操作等。
有效的经度从 -180 度到 180 度。有效的纬度从 -85.05112878 度到 85.05112878 度。当坐标位置超出指定范围时,该命令将会返回一个错误
已经添加的数据,是无法再次往里面添加的。
#添加一个或多个坐标 (key 经度,纬度,地点名称)geoadd <key> <longitude> <latitude> <member> [<longitude> <latitude> <member> ...]#获得指定地区的坐标值geopos <key> <member> [member...]#获取两个位置之间的直线距离 m 表示单位为米[默认值], km:千米, mi:英里, ft:英尺geodist <key> <member1> <member2> <m|km|mi>#给定的经纬度为中心,找出某一半径内的元素georadius <key> <longitude> <latitude> <radius> <m|km|mi>
3 redis配置文件
部分设置
# ##存储 当要为某个配置指定大小的时候,必须带上单位 不区分大小写 最小单位 bytes# 1k => 1000 bytes# 1kb => 1024 bytes# 1m => 1000000 bytes# 1mb => 1024*1024 bytes# 1g => 1000000000 bytes# 1gb => 1024*1024*1024 bytes################################## 引入外部配置文件 ##################################### include /path/to/local.conf# include /path/to/other.conf################################## 模块加载 ###################################### 启动时加载模块## loadmodule /path/to/my_module.so# loadmodule /path/to/other_module.so################################## 网络配置 ####################################### 如果开启了protected-mode,那么在没有设定bind ip且没有设密码的情况下,Redis只允许接受本机的响应bind 127.0.0.1 -::1# 端口port 6379#本机访问保护模式设置 设置为no 允许外面访问protected-mode no# 设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接。默认值为0,表示不关闭。timeout 0# 设置tcp的backlog, backlog其实是一个连接队列,backlog队列总和=未完成三次握手队列 + 已经完成三次握手队列#在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。#注意Linux内核会将这个值减小到/proc/sys/net/core/somaxconn的值(128),#所以需要确认增大/proc/sys/net/core/somaxconn和/proc/sys/net/ipv4/tcp_max_syn_backlog(128)两个值来达到想要的效果tcp-backlog 511# 单位是秒,表示将周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态,#避免服务器一直阻塞,官方给出的建议值是300s,如果设置为0,则不会周期性的检测。tcp-keepalive 300################################# 通用配置 ###################################### 设置为yes表示指定Redis以守护进程的方式启动(后台启动)。默认值为 nodaemonize no# 配置PID文件路径,当redis作为守护进程运行的时候,它会把 pid 默认写到 /var/redis/run/redis_6379.pid 文件里面pidfile /var/run/redis_6379.pid# 定义日志级别。默认值为notice,有如下4种取值:# debug(记录大量日志信息,适用于开发、测试阶段)# verbose(较多日志信息)# notice(适量日志信息,使用于生产环境)# warning(仅有部分重要、关键信息才会被记录)loglevel notice# 配置log文件地址,默认打印在命令行终端的窗口上logfile ""#是否打开记录syslog功能# syslog-enabled no# syslog的标识符。# syslog-ident redis# 日志的来源、设备# syslog-facility local0# 设置数据库的数目。默认的数据库是DB 0 ,可以在每个连接上使用select <dbid> 命令选择一个不同的数据库,# dbid是一个介于0到databases - 1 之间的数值。默认值是 16,也就是说默认Redis有16个数据库databases 16################################ 数据持久化RDB ################################# #RDB核心规则配置 save <指定时间间隔> <执行指定次数更新操作>,满足条件就将内存中的数据同步到硬盘# 中。官方出厂配置默认是 900秒内有1个更改,300秒内有10个更改以及60秒内有10000个更改,则将内存中的# 数据快照写入磁盘。# 若不想用RDB方案,可以把 save "" 的注释打开,下面三个注释## save ""# save 3600 1# save 300 100# save 60 10000# #当RDB持久化出现错误后,是否依然进行继续进行工作,yes:不能进行工作,no:可以继续进行工作,可以通# 过info中的rdb_last_bgsave_status了解RDB持久化是否有错误stop-writes-on-bgsave-error yes# 配置存储至本地数据库时是否压缩数据,默认为yes。Redis采用LZF压缩方式,但占用了一点CPU的时间。若关闭该选项,# 但会导致数据库文件变的巨大。建议开启。rdbcompression yes# 是否校验rdb文件;从rdb格式的第五个版本开始,在rdb文件的末尾会带上CRC64的校验和。这跟有利于文件的# 容错性,但是在保存rdb文件的时候,会有大概10%的性能损耗,所以如果你追求高性能,可以关闭该配置rdbchecksum yes#指定本地数据库文件名,一般采用默认的 dump.rdbdbfilename dump.rdb# 数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目dir ./################################# 复制选项 ##################################主-副本复制。使用replicaof使Redis实例成为另一个Redis服务器。#关于Redis复制,有几件事需要尽快了解。## +------------------+ +---------------+# | 主 | ---> | 副本 |# | (接收写入) | | (精确复制) |# +------------------+ +---------------+## 1) Redis复制是异步的,但是您可以配置一个master to# 如果写看起来至少没有连接,那么停止接受写给定数量的副本。# 2) Redis副本能够执行与master如果复制链接丢失的次数相对较少# 时间。您可能需要配置复制待办事项列表的大小(参见下一节)根据您的需要,使用一个合理的值。# 3) 复制是自动的,不需要用户干预。网络分区副本自动尝试重新连接到主机后并与它们重新同步。## replicaof <masterip> <masterport># master的密码# masterauth <master-password>## master的用户名# masteruser <username>## 配置从是否为只读,开启后从则不能写入数据,旧版本是:slave-read-only yesreplica-serve-stale-data yes## 配置从是否为只读,开启后从则不能写入数据,旧版本是:slave-read-only yesreplica-read-only yes## 同步策略: 磁盘或socket,默认磁盘方式repl-diskless-sync no#如果非磁盘同步方式开启,可以配置同步延迟时间,以等待master产生子进程通过socket传输RDB数据给slave。#默认值为5秒,设置为0秒则每次传输无延迟。repl-diskless-sync-delay 5#同步的超时时间#slave在与master SYNC期间有大量数据传输,造成超时#在slave角度,master超时,包括数据、ping等#在master角度,slave超时,当master发送REPLCONF ACK pings#确保这个值大于指定的repl-ping-slave-period,否则在主从间流量不高时每次都会检测到超时#repl-timeout 60#是否在slave套接字发送SYNC之后禁用 TCP_NODELAY#如果选择yes,Redis将使用更少的TCP包和带宽来向slaves发送数据。但是这将使数据传输到slave上有延迟,Linux内核的默认配置会达到40毫秒。#如果选择no,数据传输到salve的延迟将会减少但要使用更多的带宽。#默认我们会为低延迟做优化,但高流量情况或主从之间的跳数过多时,可以设置为“yes”。repl-disable-tcp-nodelay no#设置数据备份的backlog大小#repl-backlog-size 1mb#从最后一个slave断开开始计时多少秒后,backlog缓冲将会释放。#repl-backlog-ttl 3600#优先级replica-priority 100#如果master少于N个延时小于等于M秒的已连接slave,就可以停止接收写操作。#N个slave需要是“oneline”状态。#延时是以秒为单位,并且必须小于等于指定值,是从最后一个从slave接收到的ping(通常每秒发送)开始计数。#该选项不保证N个slave正确同步写操作,但是限制数据丢失的窗口期。#例如至少需要3个延时小于等于10秒的slave用下面的指令:#min-replicas-to-write 3#min-replicas-max-lag 10################################## SECURITY #################################### 设置密码# requirepass foobared#命令重命名#设置命令为空时禁用命令#rename-command CONFIG ""################################### CLIENTS ##################################### 设置redis同时可以与多少个客户端进行连接# maxclients 10000############################## MEMORY MANAGEMENT ################################# 建议必须设置,否则,将内存占满,造成服务器宕机## maxmemory 128M# 设置redis可以使用的内存量。一旦到达内存使用上限,redis将会试图移除内部数据,移除规则可以通过maxmemory-policy来指定。# volatile-lru:使用LRU算法移除key,只对设置了过期时间的键;(最近最少使用)# allkeys-lru:在所有集合key中,使用LRU算法移除key# volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键# allkeys-random:在所有集合key中,移除随机的key# volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key# noeviction:不进行移除。针对写操作,只是返回错误信息# maxmemory-policy noeviction# 设置样本数量,LRU算法和最小TTL算法都并非是精确的算法,而是估算值,所以你可以设置样本的大小,redis默认会检查这么多个key并选择其中LRU的那个。# 一般设置3到7的数字,数值越小样本越不准确,但性能消耗越小。# maxmemory-samples 5############################# LAZY FREEING #####################################内存满逐出lazyfree-lazy-eviction no#过期key删除lazyfree-lazy-expire no#内部删除,比如rename oldkey newkey时,如果newkey存在需要删除newkeylazyfree-lazy-server-del no#接收完RDB文件后清空数据选项replica-lazy-flush no################################ 多线程设置 THREADED I/O ################################## 设置redis 多线程 默认情况下是禁止的# 如果是4核 设置2/3个线程 如果是8个线程 设置6个线程# io-threads 4# io-threads-do-reads no############################## APPEND ONLY MODE ################################ AOF文件名称appendfilename "appendonly.aof"#fsync() 系统调用告诉操作系统把数据写到磁盘上,而不是等更多的数据进入输出缓冲区。#有些操作系统会真的把数据马上刷到磁盘上;有些则会尽快去尝试这么做。#Redis支持三种不同的模式:#no:不要立刻刷,只有在操作系统需要刷的时候再刷。比较快。#always:每次写操作都立刻写入到aof文件。慢,但是最安全。#everysec:每秒写一次。折中方案。#默认的 “everysec” 通常来说能在速度和数据安全性之间取得比较好的平衡。# appendfsync alwaysappendfsync everysec# appendfsync no#如果AOF的同步策略设置成 “always” 或者 “everysec”,并且后台的存储进程(后台存储或写入AOF 日志)会产生很多磁盘I/O开销。某些Linux的配置下会使Redis因为 fsync()系统调用而阻塞很久。#注意,目前对这个情况还没有完美修正,甚至不同线程的 fsync() 会阻塞我们同步的write(2)调用。#为了缓解这个问题,可以用下面这个选项。它可以在 BGSAVE 或 BGREWRITEAOF 处理时阻止fsync()。#这就意味着如果有子进程在进行保存操作,那么Redis就处于"不可同步"的状态。#这实际上是说,在最差的情况下可能会丢掉30秒钟的日志数据。(默认Linux设定)#如果把这个设置成"yes"带来了延迟问题,就保持"no",这是保存持久数据的最安全的方式。no-appendfsync-on-rewrite no#自动重写AOF文件。如果AOF日志文件增大到指定百分比,Redis能够通过 BGREWRITEAOF 自动重写AOF日志文件。#工作原理:Redis记住上次重写时AOF文件的大小(如果重启后还没有写操作,就直接用启动时的AOF大小)#这个基准大小和当前大小做比较。如果当前大小超过指定比例,就会触发重写操作。#你还需要指定被重写日志的最小尺寸,这样避免了达到指定百分比但尺寸仍然很小的情况还要重写。#指定百分比为0会禁用AOF自动重写特性。auto-aof-rewrite-percentage 100#文件达到大小阈值的时候进行重写auto-aof-rewrite-min-size 64mb#如果设置为yes,如果一个因异常被截断的AOF文件被redis启动时加载进内存,redis将会发送日志通知用户#如果设置为no,erdis将会拒绝启动。此时需要用"redis-check-aof"工具修复文件aof-load-truncated yes#加载时Redis识别出AOF文件以“REDIS”开头字符串,#并加载带此前缀的RDB文件,然后继续加载AOFaof-use-rdb-preamble yes################################ LUA SCRIPTING ################################ Lua 脚本的最大执行毫秒数lua-time-limit 5000################################ REDIS CLUSTER ################################开启redis集群# cluster-enabled yes#配置redis自动生成的集群配置文件名。确保同一系统中运行的各redis实例该配置文件不要重名。# cluster-config-file nodes-6379.conf#集群节点超时毫秒数# cluster-node-timeout 15000#如果数据太旧,集群中的不可用master的slave节点会避免成为备用master。如果slave和master失联时间超过:(node-timeout * slave-validity-factor) + repl-ping-slave-period则不会被提升为master。#如node-timeout为30秒,slave-validity-factor为10, 默认default repl-ping-slave-period为10秒,失联时间超过310秒slave就不会成为master。#较大的slave-validity-factor值可能允许包含过旧数据的slave成为master,同时较小的值可能会阻止集群选举出新master。#为了达到最大限度的高可用性,可以设置为0,即slave不管和master失联多久都可以提升为master# cluster-replica-validity-factor 10#只有在之前master有其它指定数量的工作状态下的slave节点时,slave节点才能提升为master。默认为1(即该集群至少有3个节点,1 master+2 slaves,master宕机,仍有另外1个slave的情况下其中1个slave可以提升)#测试环境可设置为0,生成环境中至少设置为1# cluster-migration-barrier 1#默认情况下如果redis集群如果检测到至少有1个hash slot不可用,集群将停止查询数据。#如果所有slot恢复则集群自动恢复。#如果需要集群部分可用情况下仍可提供查询服务,设置为no。# cluster-require-full-coverage yes#选项设置为yes时,会阻止replicas尝试对其master在主故障期间进行故障转移#然而,master仍然可以执行手动故障转移,如果强制这样做的话。#cluster-replica-no-failover no########################## CLUSTER DOCKER/NAT support #########################默认情况下,Redis会自动检测自己的IP和从配置中获取绑定的PORT,告诉客户端或者是其他节点。#而在Docker环境中,如果使用的不是host网络模式,在容器内部的IP和PORT都是隔离的,那么客户端和其他节点无法通过节点公布的IP和PORT建立连接。#如果开启以下配置,Redis节点会将配置中的这些IP和PORT告知客户端或其他节点。而这些IP和PORT是通过Docker转发到容器内的临时IP和PORT的。#cluster-announce-ip#cluster-announce-port#集群总线端口#cluster-announce-bus-port# Example:## cluster-announce-ip 10.1.1.5# cluster-announce-tls-port 6379# cluster-announce-port 0# cluster-announce-bus-port 6380################################## SLOW LOG ####################################记录超过多少微秒的查询命令#1000000等于1秒,设置为0则记录所有命令slowlog-log-slower-than 10000#记录大小,可通过SLOWLOG RESET命令重置slowlog-max-len 128################################ LATENCY MONITOR ###############################记录执行时间大于或等于预定时间(毫秒)的操作,为0时不记录latency-monitor-threshold 0############################# EVENT NOTIFICATION ###############################Redis能通知 Pub/Sub 客户端关于键空间发生的事件,默认关闭notify-keyspace-events ""############################### ADVANCED CONFIG ################################当hash只有少量的entry时,并且最大的entry所占空间没有超过指定的限制时,会用一种节省内存的#数据结构来编码。可以通过下面的指令来设定限制hash-max-ziplist-entries 512hash-max-ziplist-value 64#当取正值的时候,表示按照数据项个数来限定每个quicklist节点上的ziplist长度。比如,当这个参数配置#成5的时候,表示每个quicklist节点的ziplist最多包含5个数据项。#当取负值的时候,表示按照占用字节数来限定每个quicklist节点上的ziplist长度。这时,它只能取-1到-5#这五个值,每个值含义如下:#-5: 每个quicklist节点上的ziplist大小不能超过64 Kb。(注:1kb => 1024 bytes)#-4: 每个quicklist节点上的ziplist大小不能超过32 Kb。#-3: 每个quicklist节点上的ziplist大小不能超过16 Kb。#-2: 每个quicklist节点上的ziplist大小不能超过8 Kb。(-2是Redis给出的默认值)#-1: 每个quicklist节点上的ziplist大小不能超过4 Kb。list-max-ziplist-size -2#这个参数表示一个quicklist两端不被压缩的节点个数。#注:这里的节点个数是指quicklist双向链表的节点个数,而不是指ziplist里面的数据项个数。#实际上,一个quicklist节点上的ziplist,如果被压缩,就是整体被压缩的。#参数list-compress-depth的取值含义如下:#0: 是个特殊值,表示都不压缩。这是Redis的默认值。#1: 表示quicklist两端各有1个节点不压缩,中间的节点压缩。#2: 表示quicklist两端各有2个节点不压缩,中间的节点压缩。#3: 表示quicklist两端各有3个节点不压缩,中间的节点压缩。#依此类推…#由于0是个特殊值,很容易看出quicklist的头节点和尾节点总是不被压缩的,以便于在表的两端进行快速存取。list-compress-depth 0#set有一种特殊编码的情况:当set数据全是十进制64位有符号整型数字构成的字符串时。#下面这个配置项就是用来设置set使用这种编码来节省内存的最大长度。set-max-intset-entries 512#与hash和list相似,有序集合也可以用一种特别的编码方式来节省大量空间。#这种编码只适合长度和元素都小于下面限制的有序集合zset-max-ziplist-entries 128zset-max-ziplist-value 64#HyperLogLog稀疏结构表示字节的限制。该限制包括#16个字节的头。当HyperLogLog使用稀疏结构表示#这些限制,它会被转换成密度表示。#值大于16000是完全没用的,因为在该点#密集的表示是更多的内存效率。#建议值是3000左右,以便具有的内存好处, 减少内存的消耗hll-sparse-max-bytes 3000#Streams宏节点最大大小/项目。流数据结构是基数编码内部多个项目的大节点树。使用此配置#可以配置单个节点的字节数,以及切换到新节点之前可能包含的最大项目数#追加新的流条目。如果以下任何设置设置为0,忽略限制,因此例如可以设置一个#大入口限制将max-bytes设置为0,将max-entries设置为所需的值stream-node-max-bytes 4096stream-node-max-entries 100#启用哈希刷新,每100个CPU毫秒会拿出1个毫秒来刷新Redis的主哈希表(顶级键值映射表)activerehashing yes#客户端的输出缓冲区的限制,可用于强制断开那些因为某种原因从服务器读取数据的速度不够快的客户端client-output-buffer-limit normal 0 0 0client-output-buffer-limit slave 256mb 64mb 60client-output-buffer-limit pubsub 32mb 8mb 60#默认情况下,“hz”的被设定为10。提高该值将在Redis空闲时使用更多的CPU时,但同时当有多个key#同时到期会使Redis的反应更灵敏,以及超时可以更精确地处理hz 10#开启动态hzdynamic-hz yes#当一个子进程重写AOF文件时,如果启用下面的选项,则文件每生成32M数据会被同步aof-rewrite-incremental-fsync yes#当redis保存RDB文件时,如果启用了以下选项,每生成32 MB数据,文件将被fsync-ed。#这很有用,以便以递增方式将文件提交到磁盘并避免大延迟峰值。rdb-save-incremental-fsync yes########################### ACTIVE DEFRAGMENTATION ########################启用主动碎片整理#activedefrag yes#启动活动碎片整理的最小碎片浪费量#active-defrag-ignore-bytes 100mb#启动碎片整理的最小碎片百分比#active-defrag-threshold-lower 10#使用最大消耗时的最大碎片百分比#active-defrag-threshold-upper 100#在CPU百分比中进行碎片整理的最小消耗#active-defrag-cycle-min 5#磁盘碎片整理的最大消耗#active-defrag-cycle-max 75#将从主字典扫描处理的最大set / hash / zset / list字段数#active-defrag-max-scan-fields 1000
4 redis发布订阅
打开一个或多个客户端订阅某个频道
然后再打开另外一个客户端给频道发送消息 看消费者能否收到消息
#订阅频道 channel 频道名称可以自定义subscribe channel#给频道为channel的发送一条hello的消息 返回接收的客户端个数publish channel hello

5 springboot整合redis
5.1 redis config 配置
@EnableCaching@Configurationpublic class RedisConfig<K, V> {/*** redis的序列化* * GenericToStringSerializer 可以将任何对象泛化为字符串并序列化* * JdkSerializationRedisSerializer 默认序列化对象 序列化java对象 存到redis中会存在乱码* * Jackson2JsonRedisSerializer 序列化object对象为json字符串 被序列化的对象如果带有泛型 反序列化会报错* * GenericJackson2JsonRedisSerializer 和Jackson2JsonRedisSerializer对比 效率低,占用内存高 会保存序列化的对象的包名和类名,反序列化时以这个作为标示就可以反序列化成指定的对象* * FastJsonRedisSerializer ali出的序列化对象 和Jackson2JsonRedisSerializer类似* * GenericFastJsonRedisSerializer ali出的序列化对象 和GenericJackson2JsonRedisSerializer* * OxmSerializer xml格式存储* * ByteArrayRedisSerializer* * StringRedisSerializer** @param factory* @return*/@Beanpublic RedisTemplate<K, V> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<K, V> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(factory);/*** String序列号配置 设置key hashkey*/StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();redisTemplate.setKeySerializer(stringRedisSerializer);redisTemplate.setHashKeySerializer(stringRedisSerializer);/*** Jackson2Json序列化配置 设置 value hash value*/Jackson2JsonRedisSerializer<V> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>((Class<V>) Object.class);/*** GenericJackson2JsonRedisSerializer 设置 value hash value*/GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);GenericFastJsonRedisSerializer genericFastJsonRedisSerializer = new GenericFastJsonRedisSerializer();OxmSerializer oxmSerializer = new OxmSerializer(new Jaxb2Marshaller(),new Jaxb2Marshaller());//value和hash的value采用Json的序列化配置redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);return redisTemplate;}}
5.2 key操作
@SpringBootTestclass Redis2KeysTests {@AutowiredRedisTemplate redisTemplate;/*** 获取key*/@Testvoid getkeyTest() {/*** 获取所有key*/Set keys = redisTemplate.keys("*");System.out.println(keys);/*** 获取user开头的key*/Set keys1 = redisTemplate.keys("user*");System.err.println(keys1);}/*** 删除key*/@Testvoid delkeyTest() {Boolean user = redisTemplate.delete("user");}/*** 设置key过期时间*/@Testvoid expirekeyTest() {/*** 方式1:设置10分钟过期时间*/redisTemplate.expire("user", 10, TimeUnit.SECONDS);/*** 方式2:设置3小时过期时间*/redisTemplate.expire("user", Duration.ofHours(3));/*** 设置指定过期时间*/redisTemplate.expireAt("user", DateUtil.beginOfDay(DateUtil.tomorrow()));}/*** 判断key是否存在*/@Testvoid expirekeyTest2() {Boolean user = redisTemplate.hasKey("user");}}
5.3 string操作
@SpringBootTestclass Redis3StringTests {@AutowiredRedisTemplate redisTemplate;/*** 根据key获取value*/@Testvoid getValueTest() {Object user = redisTemplate.opsForValue().get("user");}/*** 设置值*/@Testvoid setValueTest() {redisTemplate.opsForValue().set("user", new User(1, "jack"));/*** 设置值的同时,设置过期时间*/redisTemplate.opsForValue().set("user", new User(1, "jack"), Duration.ofDays(1));}/*** 自增长 自减*/@Testvoid incrementTest() {redisTemplate.opsForValue().set("testinc", 1);/*** 自增1*/redisTemplate.opsForValue().increment("testinc");/*** 自增指定值 可以为负数 可以为小数*/redisTemplate.opsForValue().increment("testinc", -5);/*** 自减*/redisTemplate.opsForValue().decrement("testinc", 1);}/*** 当redis不存在值时 设置* redis中存在值时 不设置*/@Testvoid setIfAbsentTest() {Boolean setIfAbsent = redisTemplate.opsForValue().setIfAbsent("user", new User(1, "jack"));System.err.println(setIfAbsent);}/*** 将指定值追加到某个key上*/@Testvoid appendTest() {redisTemplate.opsForValue().append("key", "v2");}/*** 批量获取值*/@Testvoid multiGetTest() {List list = redisTemplate.opsForValue().multiGet(Arrays.asList("user1", "user2"));}/*** 批量设置值*/@Testvoid multiSet() {Map<String, String> map = new HashMap<>();map.put("a", "v1");map.put("b", "v2");map.put("c", "v3");redisTemplate.opsForValue().multiSet(map);}}
5.4 List操作
@SpringBootTestclass Redis4ListTests {@AutowiredRedisTemplate redisTemplate;/*** 设置值*/@Testvoid pushTest() {/*** 从左插入一条*/redisTemplate.opsForList().leftPush("listKey", "a");redisTemplate.opsForList().leftPush("listKey", "b");/***从右插入一条*/redisTemplate.opsForList().rightPush("listKey", "e");/*** 以a为坐标 在a的左边插入一条c*/redisTemplate.opsForList().leftPush("listKey", "a", "c");}/*** 取出值(会删除)*/@Testvoid popTest() {Object value1 = redisTemplate.opsForList().leftPop("listKey");System.out.println(value1);Object value2 = redisTemplate.opsForList().rightPop("listKey");System.out.println(value2);}/*** 从第一个列表右边取第一个值到第二个列表左边*/@Testvoid rightPopAndLeftPushTest() {redisTemplate.opsForList().rightPopAndLeftPush("listKey", "listKey2");}/*** 按索引下标从左边查询列表的值 lrange key 0 -1 查询所有值*/@Testvoid rangeTest() {List listKey = redisTemplate.opsForList().range("listKey", 0, -1);System.out.println(Arrays.toString(listKey.toArray()));}/*** 查找指定值*/@Testvoid appendTest() {/*** 查找指定下标的值 从0开始*/Object value = redisTemplate.opsForList().index("listKey", 1);System.out.println(value);/*** 查找指定值的下标 存在相同的值 拿出第一个值的下标*/Long index = redisTemplate.opsForList().indexOf("listKey", "c");System.out.println(index);}/*** 获取列表长度*/@Testvoid sizeTest() {Long size = redisTemplate.opsForList().size("listKey");System.out.println(size);}}
5.5 Set操作
@SpringBootTestclass Redis5SetTests {@AutowiredRedisTemplate redisTemplate;/*** 设置值*/@Testvoid setValueTests() {/*** 设置值 集合自动去重*/redisTemplate.opsForSet().add("s1", "v1", "v2", "v1");redisTemplate.opsForSet().add("s2", new User(1, "jack"), new User(1, "jack"));}/*** 读取值*/@Testvoid membersTest() {Set<String> s1 = redisTemplate.opsForSet().members("s2");assert s1 != null;System.out.println(Arrays.toString(s1.toArray()));}/*** 判断集合中是否有值*/@Testvoid isMemberTest() {Boolean member = redisTemplate.opsForSet().isMember("s1", "v1");System.out.println(member);}/*** 集合的大小*/@Testvoid sizeTest() {Long size = redisTemplate.opsForSet().size("s1");System.out.println(size);/*** key不存在时 返回0*/Long size2 = redisTemplate.opsForSet().size("s3");System.out.println(size2);}/*** 删除集合中的元素* 返回删除的个数*/@Testvoid removeTest() {Long remove = redisTemplate.opsForSet().remove("s1", "v1", "v2");System.out.println(remove);}/*** 随机删除值*/@Testvoid popTest() {/*** 随机删除一个值*/redisTemplate.opsForSet().add("s1", "v1", "v2", "v3");Object s1 = redisTemplate.opsForSet().pop("s1");System.out.println(s1);/*** 设置随机删除值的个数*/redisTemplate.opsForSet().add("s3", "v1", "v2", "v3");List<String> s5 = redisTemplate.opsForSet().pop("s3", 2);assert s5 != null;System.out.println(Arrays.toString(s5.toArray()));}/*** 随机取值 (不会删除值)*/@Testvoid randomMemberTest() {redisTemplate.opsForSet().add("s4", "v1", "v2", "v3", "v4", "v5", "v6");Object s4 = redisTemplate.opsForSet().randomMember("s4");System.out.println(s4);List s4List = redisTemplate.opsForSet().randomMembers("s4", 2);assert s4List != null;s4List.forEach(System.out::println);}/*** 从一个集合中移动到另外一个集合*/@Testvoid moveTest() {redisTemplate.opsForSet().add("s5", "r1", "r2", "r3", "r4", "v5", "v6");Boolean move = redisTemplate.opsForSet().move("s4", "v1", "s5");System.out.println(move);}/*** 返回两个集合的交集*/@Testvoid intersectTest() {/*** 返回两个集合的交集*/Set intersect = redisTemplate.opsForSet().intersect("s4", "s5");assert intersect != null;intersect.forEach(System.out::println);/*** 将两个集合的交集存到另外一个集合中 返回存入的个数*/Long storeCount = redisTemplate.opsForSet().intersectAndStore("s4", "s5", "s6");System.out.println(storeCount);}/*** 返回两个集合的并集*/@Testvoid unionTest() {Set union = redisTemplate.opsForSet().union("s4", "s5");assert union != null;union.forEach(System.out::println);}/*** 返回两个集合的差集*/@Testvoid differenceTest() {Set difference = redisTemplate.opsForSet().difference("s4", "s5");assert difference != null;difference.forEach(System.out::println);}}
5.6 Hash操作
@SpringBootTestclass Redis6HashTests {@AutowiredRedisTemplate redisTemplate;/*** 设置值*/@Testvoid setValueTests() {/*** 设置一对值*/redisTemplate.opsForHash().put("h1", "name", "zhangsan");/*** 一个key 同时设置多对*/HashMap<String, Object> map = new HashMap<>();map.put("id", 1);map.put("name", "李四");map.put("age", 18);redisTemplate.opsForHash().putAll("user", map);/*** 给哈希表中field设置为对应的value 当且仅当field不存在时*/Boolean aBoolean = redisTemplate.opsForHash().putIfAbsent("h1", "name", "zhaoliu");System.out.println(aBoolean);}/*** 获取值*/@Testvoid getTests() {Object o = redisTemplate.opsForHash().get("h1", "name");System.out.println(o);}/*** 查看哈希集合中域field对应的value是否存在*/@Testvoid existsTests() {Boolean hasKey = redisTemplate.opsForHash().hasKey("h1", "name");System.out.println(hasKey);}/*** 列出该哈希集合中所有的field*/@Testvoid keysTests() {Set user = redisTemplate.opsForHash().keys("user");System.out.println(Arrays.toString(user.toArray()));}/*** 列出该哈希集合中所有的value*/@Testvoid valuesTests() {List user = redisTemplate.opsForHash().values("user");System.out.println(Arrays.toString(user.toArray()));}/*** 给哈希表中域field对应的value 加减指定的num* 返回加减后得到的值*/@Testvoid incrementTests() {Long increment = redisTemplate.opsForHash().increment("user", "age", 2);System.out.println(increment);}/*** 给哈希表中所有的键值对*/@Testvoid entriesTests() {Map user = redisTemplate.opsForHash().entries("user");user.forEach((k, v) -> System.out.println(k + ":" + v));}}
5.7 Zset操作
@SpringBootTestclass Redis7ZsetTests {@AutowiredRedisTemplate redisTemplate;/*** 设置值 score可以一样 value 必须唯一*/@Testvoid setValueTests() {/*** 设置一个值*/redisTemplate.opsForZSet().add("z1", "v1", 1);/*** 设置多个值*/Set<DefaultTypedTuple<String>> typedTuples = new HashSet<>();typedTuples.add(new DefaultTypedTuple<>("r1", 1.0));typedTuples.add(new DefaultTypedTuple<>("r2", 2.0));typedTuples.add(new DefaultTypedTuple<>("r3", 3.0));typedTuples.add(new DefaultTypedTuple<>("r4", 4.0));redisTemplate.opsForZSet().add("z2", typedTuples);}/*** 查询元素*/@Testvoid rangeTests() {/*** 返回有序集合下标(分数)在 start->stop中的元素 分数从小到大*/Set r1 = redisTemplate.opsForZSet().range("z2", 0, -1);System.out.println(Arrays.toString(r1.toArray()));/*** 返回有序集合中 score介于 min到max(都包含) 的值 返回结果按照score递增 如果要显示分数可以加withscores 可以截取需要返回从哪个下标开始 多少个*/Set<ZSetOperations.TypedTuple<String>> z2 = redisTemplate.opsForZSet().rangeWithScores("z2", 0, -1);z2.stream().forEach(v -> System.out.println(v.getScore() + " " + v.getValue()));/*** 按照分数查询*/Set r3 = redisTemplate.opsForZSet().rangeByScore("z2", 1, 3);System.out.println(Arrays.toString(r3.toArray()));/*** 翻转查询*/Set r4 = redisTemplate.opsForZSet().reverseRangeByScore("z2", 1, 2);System.out.println(Arrays.toString(r4.toArray()));/***查询当score 一样值的value* range().gt() 查询该value的score 并且需要大于该score*** offset 起始位置 下标从0开始* count 查询个数**/Set<DefaultTypedTuple<String>> typedTuples = new HashSet<>();typedTuples.add(new DefaultTypedTuple<>("l1", 1.0));typedTuples.add(new DefaultTypedTuple<>("l2", 2.0));typedTuples.add(new DefaultTypedTuple<>("l3", 2.0));typedTuples.add(new DefaultTypedTuple<>("l4", 2.0));redisTemplate.opsForZSet().add("lex", typedTuples);RedisZSetCommands.Range range = RedisZSetCommands.Range.range().gte("l3");RedisZSetCommands.Limit offset = RedisZSetCommands.Limit.limit().offset(0).count(5);Set lex = redisTemplate.opsForZSet().rangeByLex("lex", range, offset);System.out.println(Arrays.toString(lex.toArray()));}/*** zset中值增加*/@Testvoid existsTests() {redisTemplate.opsForZSet().incrementScore("z3", 1, 3);}/*** 删除值*/@Testvoid keysTests() {redisTemplate.opsForZSet().add("z3", 2, 3);redisTemplate.opsForZSet().remove("z3", 2);}/*** 统计集合中分数区间内元素个数*/@Testvoid valuesTests() {Long count = redisTemplate.opsForZSet().count("z2", 0, 2);System.out.println(count);}/*** 返回该值在集合中的排名 从0开始*/@Testvoid incrementTests() {Long ranking = redisTemplate.opsForZSet().rank("z2", "r4");System.out.println(ranking);}}
5.8 BitMaps操作
@SpringBootTestclass Redis8BitMapsTests {@AutowiredRedisTemplate redisTemplate;/*** 设置值 只能设置 0 或者 1*/@Testvoid setBitTests() {redisTemplate.opsForValue().setBit("bit0", 1, true);redisTemplate.opsForValue().setBit("bit0", 2, true);redisTemplate.opsForValue().setBit("bit1", 14, true);}/*** 查询元素在某个偏移量上是否存在*/@Testvoid getBitTests() {Boolean b0 = redisTemplate.opsForValue().getBit("bit0", 1);Boolean b1 = redisTemplate.opsForValue().getBit("bit1", 14);System.out.println(b0);System.out.println(b1);}}
5.9 HyperLogLog操作
@SpringBootTestclass Redis9HyperLogLogTests {@AutowiredRedisTemplate redisTemplate;/*** 添加指定元素到HyperLogLog中 会自动去重*/@Testvoid addTests() {redisTemplate.opsForHyperLogLog().add("pf1", "a", "b", "b", "c");redisTemplate.opsForHyperLogLog().add("pf2", "c", "e", "f");}/*** 查询HyperLogLog 元素个数*/@Testvoid sizeTests() {Long size = redisTemplate.opsForHyperLogLog().size("pf1");System.out.println(size);}/*** 将多个HyperLogLog集合 合并到一个 并且去重*/@Testvoid unionTests() {redisTemplate.opsForHyperLogLog().union("pfu1", "pf1", "pf2");}/*** 删除*/@Testvoid deleteTests() {redisTemplate.opsForHyperLogLog().delete("pf1");}}
5.10 Geo操作
@SpringBootTestclass Redis10GeoTests {@AutowiredRedisTemplate redisTemplate;/*** 添加指定元素到HyperLogLog中 会自动去重*/@Testvoid addTests() {Point point = new Point(121.47, 31.23);RedisGeoCommands.GeoLocation<String> stringGeoLocation = new RedisGeoCommands.GeoLocation<>("上海", point);redisTemplate.opsForGeo().add("geo1", stringGeoLocation);Map<String, Point> map = new HashMap<>();map.put("北京", new Point(116.38, 39.90));map.put("重庆", new Point(106.50, 29.53));redisTemplate.opsForGeo().add("geo1", map);}/*** 查询一个或多个城市的经纬度*/@Testvoid positionTests() {List<Point> position = redisTemplate.opsForGeo().position("geo1", "上海");position.stream().forEach(System.out::println);}/*** 获取两个位置之间的直线距离 m 表示单位为米[默认值], km:千米, mi:英里, ft:英尺*/@Testvoid distanceTests() {Distance distance = redisTemplate.opsForGeo().distance("geo1", "北京", "上海", Metrics.KILOMETERS);System.out.println(distance);}/*** 查看以某点做为坐标 距离多少公里的范围目标有多少个* <p>* 距离上海1400公里的城市有哪些*/@Testvoid radiusTests() {Distance distance = new Distance(1400, Metrics.KILOMETERS);GeoResults radius = redisTemplate.opsForGeo().radius("geo1", "上海", distance);System.out.println(radius);}}
