目录

Redis

Redis

Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。

Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

Nosql概述

为什么要用nosql

单机mysql的年代

一般情况下一个基本网站的访问量不会太大,单个数据库完全足够,那个时候更多的是去使用静态网页,服务器根本没有太大压力

思考一下,这种情况下:整个网站的瓶颈是什么?

  • 数据量太大一个机器放不下
  • 数据的索引(mysql一般是B+树),如果索引太大,也放不下
  • 访问量(读写结合),一个服务器根本承受不了

只要开始出现以上的情况之一,就必须晋级

缓存

memcached缓存(比较早期)+ MySql + 垂直拆分(读写分离)

网站80%的情况都是在读

有时候会出现多个用户读取同一个数据的情况,因此需要缓存来保存数据,用来减少服务器的压力

![image-20201201204307916](/Users/cjp/Library/Application Support/typora-user-images/image-20201201204307916.png)

缓存主要解决读的问题

发展过程

优化数据结构和索引 –>文件缓存(IO)–> Memcached(当时最热门的技术)–>

当今企业架构演变

读写分离

分库分表 + 水平拆分 + MySQL集群

![image-20201201205313273](/Users/cjp/Library/Application Support/typora-user-images/image-20201201205313273.png)

技术在发展的时候对人的要求也越来越高

本质:数据库(读,写)

数据库引擎

早些年MylSAM 表锁()

myisam:表锁(100w数据,查询张三的密码,会把整个表锁起来,高并发下会出现严重的问题)

早些年innodb 行锁

每次只锁一行

满满的就开始使用分库,分表来解决写的压力,MySql在那个年代提出了表分区!这个并没有多少公司使用,MySql的集群,很好的满足了那个年代的所有需求

如今最近的年代

技术爆炸:2010年-2020年,世界已经发生了翻天覆地的变化。(定位也是一种数据,一些音乐,一些热榜)

MySql的关系型数据库已经不够用了,数据量很多,变化很快!

  • 现在有一些新的数据库

    ​ 图型数据库

    ​ json也可以用来存到数据库里面BSON(mongodb使用这个)

MySQL有的人还用来存放一些比较大的文件,博客、图片!数据库表很大,效率就很低,如果有一种专门的数据库用来处理这种数据,mysql压力就会十分小(研究如何处理这些问题)大数据IO下,表几乎没法更改,假设有1亿条数据

目前一个基本的互联网项目!

阿里巴巴的演进分析

案例:阿里巴巴批发网

点击一个页面会出现很多图片,评论,视频等各种信息,这么多的东西不可能全部都用tomcat,也不可能都用一个数据库

![image-20201208233731886](/Users/cjp/Library/Application Support/typora-user-images/image-20201208233731886.png)

![image-20201208234126966](/Users/cjp/Library/Application Support/typora-user-images/image-20201208234126966.png)

公司有敏捷开发、极限编程

大量的公司都是做的相同的业务,因此要好好学习

数据层

  • 挑战
  • 解决方案,统一数据服务平台

![image-20201208235246088](/Users/cjp/Library/Application Support/typora-user-images/image-20201208235246088.png)

如果未来想当一个架构师:没有什么事加一层解决不了的

# 1、商品的基本信息,
  名称、价格、商家信息;
  关系型数据库可以解决了:MySQL/Oracle(淘宝早年去IOE了 —— 王坚)
	淘宝的MySQL不是大家用的MySQL
# 商品的描述、评论(文字比较多)
	mongodb
# 图片
	分布式文件系统FastDFS
	- 淘宝自己的TFS
	- google的GFS
	- Hadoop HDFS
	- 阿里云 oss云存储
# 商品的关键字(搜索)
	- 搜索引擎 solr elasticsearch
	- Isearch: 淘宝用的 多隆 开发的
# 商品的热门波段信息
	- 内存数据库
	- Redis Tair Memache
# 商品交易、外部交易接口
	- 三方应用

一个简单的网页技术的背后一定不是大家所想的那么简单,大型互联网公司应用问题

  • 数据类型太多了
  • 数据源太多了,经常重构
  • 数据要改造,大面积改造

解决方案:统一的数据服务层UDSL

在应用集群和底层数据源之间建立一个中间件

![image-20201209000627929](/Users/cjp/Library/Application Support/typora-user-images/image-20201209000627929.png)

类似于jdbc屏蔽了数据库之间的差异

![image-20201209000808255](/Users/cjp/Library/Application Support/typora-user-images/image-20201209000808255.png)

![image-20201209000910759](/Users/cjp/Library/Application Support/typora-user-images/image-20201209000910759.png)

这里以上都是nosql概述,不仅能够提高大家的知识,还能够帮助大家了解大厂的工作内容

NoSQL的四大分类

KV键值对

  • 新浪:Redis
  • 美团:Redis+Tair
  • 阿里、百度:Redis + memecache

文档型数据库

bson格式和json一样

  • MongoDB(一般必须掌握)
    • MongoDB是一个基于分布式文件存储的数据库,C++编写,主要用来处理大量的文档!
    • MongoDB是一个基于关型数据库和非关系型数据库中中间的产品,MongoDB是非关系型数据库中功能最丰富,最像关系型数据库的!

列存储数据库

  • HBase
  • 分布式文件系统

图关系数据库

它不是存图型的,它是放的关系,比如朋友圈社交网络,广告推荐,专注于构建关系图

  • Neo4J
  • InfoGrid

![image-20201209001709784](/Users/cjp/Library/Application Support/typora-user-images/image-20201209001709784.png)

敬畏之心可以使人进步!

Redis入门

Redis(Remote Dictionary Server),即远程字典服务,

用c语言编写,支持网络,基于内存亦可持久化的日志型,Key-Value数据库,并且提供多种语言的API

免费喝开源,是当下最热门的NoSQL技术之一,也被人们称为结构化数据库

Redis能干嘛

![image-20201209004320302](/Users/cjp/Library/Application Support/typora-user-images/image-20201209004320302.png)

1、内存存储、持久化、内存是断电即失去,所以说持久化很重要(rdb,aof)

2、效率高,可以用于高速缓存

3、发布订阅系统

4、地图信息分析

5、计数器、计数器(浏览量!访问量)

6、……

特性

1、多样的数据类型

2、持久化

3、集群

4、事务

……

学习中需要的东西

1、redis官网

2、中文网 http://redis.cn

注意:windows在Github上下载(停更很久了)

redis推荐在linux服务器上搭建,不建议使用windows

安装redis

docker安装

docker pull redis

linux安装

yum install gcc-c++

make

make install

redis的安装路径 usr/local/bin

  1. 将redis配置文件复制到当前目录

7、redis默认不是后台启动的

8、在配置文件里运行

redis-server kconfig/redis.conf

查看redis进程

ps -ef|grep redis

Redis-benchmark性能测试工具

# 测试100个并发请求,1000个请求
redis-benchmark -h localhost -p 6379 -c 100 -n 1000

![image-20201209151513359](/Users/cjp/Library/Application Support/typora-user-images/image-20201209151513359.png)

Redis基础知识

redis默认有16个数据库(0-15),默认的是第0个。用select切换数据库

root@d1f23439dd59:/data# redis-cli
127.0.0.1:6379> select 3 # 选择第三个数据库
OK
127.0.0.1:6379[3]> DBSIZE# 查看大小
(integer) 0
127.0.0.1:6379[3]> keys * # 查看所有的key
1) "name"
127.0.0.1:6379[3]> flushdb # 清空数据库
OK
127.0.0.1:6379[3]> keys *
(empty array)
127.0.0.1:6379[3]> FLUSHALL #清空全部数据库的内容

Redis是单线程的

Redis是基于内存操作的,cpu不是Redis的性能瓶颈,Redis的性能瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用了单线程,6.0版本之后有了多线程

Redis是C语言写的,官方提供的数据是没秒10w+ 的QPS,这个不比Memecache差

单线程为什么还这么快?

1、误区1:高性能的服务器一定是多线程的?

2、误区2:多小城一定比单线程效率高?

CPU、内存、硬盘速度要有所理解!

核心

Redis是将所有的数据全部放在内存中的,所以说使用单线程去操作,效率就是最高的,多线程会发生cpu上下文切换,耗时的操作,对于内存系统来说,如果没有上下文切换,效率就是最高的,多次读写都是在一个CPU中的

Redis Key基本命令

redis可以做缓存,消息中间件MQ,数据库

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings)散列(hashes)列表(lists)集合(sets)有序集合(sorted sets) 与范围查询, bitmapshyperloglogs地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication)LUA脚本(Lua scripting)LRU驱动事件(LRU eviction)事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

redis的五大数据类型

String

List

Set

Hash

Zset

Redis-Key

move name 1		# 从1数据库中移除name
127.0.0.1:6379> set name cjp 		# 设置name为cjp
OK
127.0.0.1:6379> EXPIRE name 10	# 设置name的过期时间为10秒
(integer) 1
127.0.0.1:6379> ttl name				# 查看过期时间
(integer) 6

key的一些常用的命令

EXISTS name	# 判断当前的key是否存在
EXPIRE key time	# 设置过期时间
ttl name				# 查看name的剩余时间
type name				# 查看name的类型
127.0.0.1:6379> set name cjp
OK
127.0.0.1:6379> type name
string

EXPIRE可以用来做单点登陆

String(字符串)

127.0.0.1:6379> set key2 v1						# 设置值
OK
127.0.0.1:6379> get key2							# 获取值
"v1"
127.0.0.1:6379> APPEND key2 "hahah"		# 追加字符串
(integer) 7
127.0.0.1:6379> STRLEN key1						# 获取长度
(integer) 10
# 加一操作,可以用来统计访问量
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views		# views加一
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views			# 获取views
"2"
127.0.0.1:6379> decr views		# 减一
(integer) 1

# 设置步长
127.0.0.1:6379> INCRBY views 10	# 增加十
(integer) 12
127.0.0.1:6379> DECRBY views 12 # 减十二
(integer) 0

# 字符串的范围
127.0.0.1:6379> set key "hello,cjp"	#设置值
OK
127.0.0.1:6379> GETRANGE key 0 3		#设置区间 0,1,2,3
"hell"
127.0.0.1:6379> GETRANGE key 0 -1		# 获取全部字符串
"hello,cjp"

#  替换字符串
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> get key2
"abcdefg"
127.0.0.1:6379> SETRANGE  key2 1 xx
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
# setex	设置过期时间
127.0.0.1:6379> setex key3 30 "hello"
OK
127.0.0.1:6379> get key3
"hello"
# setnx	不存在再设置,如果存在就不设置
127.0.0.1:6379> setnx mykey "redis"	# 这个时候mykey不存在,所以可以设置
(integer) 1
127.0.0.1:6379> get mykey
"redis"
127.0.0.1:6379> setnx mykey "rediss"	# 这个时候mykey已经设置好了,再设置的话就会出错了
(integer) 

# mget mset 这两个是原子操作,要么成功,要么失败
127.0.0.1:6379> msetnx k1 v1 k2 v2
(integer) 1
127.0.0.1:6379> mget k2 k2
1) "v2"
2) "v2"

# 对象
set user:1 {name:cjp,age:2} # 设置一个user:1对象,值为json字符来保存一个对象
# 这里的key是一个巧妙的设计 user:{id}:{filed}
mset user:1:name zhangsan user:1:age 2

127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"
127.0.0.1:6379> 


# getset 先get再set
127.0.0.1:6379> getset db redis	# 这个时候数据库中还没有db
(nil)
127.0.0.1:6379> get db					# getset组合命令把db的值设置为了db
"redis"

jedis是java中用来操作redis的一个工具

  • 计数器
  • 统计单位数量 uid:cjphah:follow 0 incr
  • 粉丝数量
  • 对象存储

List

基本数据类型,列表

![image-20201209182428581](/Users/cjp/Library/Application Support/typora-user-images/image-20201209182428581.png)

十分强大,可以吧list玩成栈,队列

所有的list相关的都是用l开头的

127.0.0.1:6379> LPUSH list one	# 将一个值或者多个值放在列表头部
(integer) 1
127.0.0.1:6379> LPUSH list two
integer) 2
127.0.0.1:6379> LPUSH list three
integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> LRANGE list 0 1
1) "three"
2) "two"

# RPUSH 向尾部添加
127.0.0.1:6379> RPUSH list four
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
# LPOP左移除
127.0.0.1:6379> LPOP list	# 移除第一个
"three"
127.0.0.1:6379> RPOP list	# 移除最后一个
"four"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"

# 通过下标获取某一个值
127.0.0.1:6379> lindex list 0
"two"

# 获取长度
127.0.0.1:6379> llen list
(integer) 2


# 移除指定的值(下面这个把one给移除了)

127.0.0.1:6379> lrem list 1 two
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "one"

# trim修剪
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> ltrim mylist 0 2	# 这个时候mylist已经被修剪了
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"


# 组合命令
127.0.0.1:6379> rpush mylist "a"
(integer) 1
127.0.0.1:6379> rpush mylist "b"
(integer) 2
127.0.0.1:6379> rpush mylist "c"
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> rpoplpush mylist myotherlist
"c"
127.0.0.1:6379> lrange myotherlist 0 -1
1) "c"
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"


# lset 将列表中的指定值替换为掉
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
127.0.0.1:6379> lset mylist 0 d	# 把0下标的换成d,如果下面不存在,就会报错
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "d"
2) "b"

# linsert 插入
# 下面这个例子在指定的值前面插入一个
127.0.0.1:6379> rpush mylist a
(integer) 1
127.0.0.1:6379> rpush mylist b
(integer) 2
127.0.0.1:6379> rpush mylist c
(integer) 3
127.0.0.1:6379> linsert mylist before a other
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "other"
2) "a"
3) "b"
4) "c"
#  在后面插入
127.0.0.1:6379> linsert mylist after a other1
(integer) 5
127.0.0.1:6379> lrange mylist 0 -1
1) "other"
2) "a"
3) "other1"
4) "b"
5) "c"

小结

  • 它其实是一个链表,before node after,left,right都可以插入值
  • 如果key不窜爱,创建新的链表
  • 如果key存在,新增内容
  • 如果移除的所有值,空链表,也代表不存在
  • 在两边插入或者改动值,效率最高,中间元素,相对效率会低一些

可以做消息排队,消息队列,在用MQ的时候很有用。

既可以作为队列,又可以作为栈

set

set是一种集合类型。set中的值不能重复

set是一个无序集合

set里面的基本命令

sadd myset "hello"
asdd myset "cjp"
sadd myset "love"
127.0.0.1:6379> SMEMBERS myset	# 查看set中所有的值
1) "hello"
2) "love"
3) "cjp"
127.0.0.1:6379> SISMEMBER myset hello	# 判断这个值是否在一个set中
(integer) 1
127.0.0.1:6379> scard myset			# 查看集合中的元素个数
(integer) 3
127.0.0.1:6379> SRANDMEMBER myset # 抽取一个随机的
"cjp"
127.0.0.1:6379> SRANDMEMBER myset
"love"
127.0.0.1:6379> SRANDMEMBER myset 2 #抽选两个随机的
1) "hello"
2) "cjp"
127.0.0.1:6379> SRANDMEMBER myset 2
1) "hello"
2) "love"

# 将一个指定的值移动到另外一个set中
127.0.0.1:6379> sadd myset2 "set2"
(integer) 1
127.0.0.1:6379> smove myset myset2 "hello"
(integer) 1
127.0.0.1:6379> SMEMBERS myset2
1) "hello"
2) "set2"

# 微博,B站,共同关注!(并集)
# 数字集合
127.0.0.1:6379> SDIFF myset myset2	# 以第一个为参照,找差集
1) "cjp"
2) "love"
127.0.0.1:6379> SINTER myset myset2	# 找交集
1) "hello"
127.0.0.1:6379> SUNION myset myset2	# 找并集
1) "set2"
2) "hello"
3) "cjp"
4) "love"

共同关注,共同爱好,二度好友,推荐好友(六度分割理论)

Hash

Map集合,key-map集合,这个时候值是一个map集合

Hash本质和string没有太大区别还是一个简单的key-value

# 先上例子
127.0.0.1:6379> hset myhash dield1 cjp
(integer) 1
127.0.0.1:6379> hget myhash dield1			# 获取一个字段值
"cjp"

127.0.0.1:6379> hmset myhash filed1 hello field2 world	# 同时设置多个key-value 
OK
127.0.0.1:6379> hmget myhash field1 field2 # 同时获取
1) (nil)
2) "world"
127.0.0.1:6379> hgetall myhash			# 获取全部值
1) "dield1"
2) "cjp"
3) "filed1"
4) "hello"
5) "field2"
6) "world"
127.0.0.1:6379> hdel myhash field2	# 删除指定的字段,删除之后对应的value也没有了

(integer) 1
127.0.0.1:6379> hgetall myhash
1) "dield1"
2) "cjp"
3) "filed1"
4) "hello"


# 查看hash的长度
127.0.0.1:6379> hlen myhash
(integer) 2
# 判读hash中某个field存不存在
127.0.0.1:6379> hexists myhash dield1
(integer) 1

127.0.0.1:6379> hkeys myhash	# 只获得所有的field
1) "dield1"
2) "filed1"
127.0.0.1:6379> hvals myhash	# 只获得所有的value
1) "cjp"
2) "hello"

# incr decr

127.0.0.1:6379> hset myhash f3 5		# 设置f3
(integer) 1
127.0.0.1:6379> HINCRBY myhash f3 2	# 让f3增加2
(integer) 7

127.0.0.1:6379> hsetnx myhash f3 4	# 如果不存在才会被创建
(integer) 0
127.0.0.1:6379> hsetnx myhash f4 4	# 如果存在就会被创建
(integer) 1

hash的应用,可以存一些变更的数据user,name age

127.0.0.1:6379> hset user:1 name chenjiapeng
(integer) 1
127.0.0.1:6379> hget user:1 name
"chenjiapeng"

可以存一些用户信息,经常变动的信息,hash更加适合对象的存储,string更加适合字符串存储。

Zset(有序集合)

在set的基础上增加了一个值,set k1 v1 k2

127.0.0.1:6379> zadd myset 1 one				# 添加多个值
(integer) 1
127.0.0.1:6379> zadd myset 2 two 3 three
(integer) 2
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
3) "three"

# 排序如何实现
# 从小到大排序
127.0.0.1:6379> zadd salary 2500 xiaoming
(integer) 1
127.0.0.1:6379> zadd salary 3000 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 300000 cjp
(integer) 1
# -inf +inf 是最小和最大的意思
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf # 按照从小到大排序输出名字
1) "xiaoming"
2) "zhangsan"
3) "cjp"
# 输出名字和score
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores 
1) "xiaoming"
2) "2500"
3) "zhangsan"
4) "3000"
5) "cjp"
6) "300000"
# 移除元素
127.0.0.1:6379> zrange salary 0 -1
1) "xiaoming"
2) "zhangsan"
3) "cjp"
127.0.0.1:6379> zrem salary xiaoming
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "zhangsan"
2) "cjp"
# 获取有序集合中的个数
127.0.0.1:6379> zcard salary
(integer) 2
# 计算区间变量
127.0.0.1:6379> ZREVRANGE salary 0 -1	# 从高到低
1) "cjp"
2) "zhangsan"
# 获取指定区间的成员数量
127.0.0.1:6379> zadd myset 1 hello 2 world 3 cjp
(integer) 3
127.0.0.1:6379> ZCOUNT myset 1 3
(integer) 3
127.0.0.1:6379> ZCOUNT myset 1 2
(integer) 2

set中有的,zset都可以

应用

  • 班级表成绩
  • 工资表排序
  • 普通消息
  • 重要消息
  • 排行榜应用实现

三种特殊数据类型

goospatial

地理位置

朋友定位,附近的人,打车距离计算?

都是通过Refis的Geo来实现的,在redis 3.2版本推出了,两地之间的距离,房源几公里之内的人

可以查询一些地理数据

getadd

# getadd 添加地理位置
# 规则:两级无法直接添加,一般会下载城市数据,直接通过程序直接倒入
# 参数 key 值(纬度、精度、名称)
geoadd china:city 116.40 39.90 beijing
geoadd china:city 121.47 31.23 shanghai
geoadd china:city 106.50 29.53 chongqing
geoadd china:city 114.01 22.52 shenzhen
geoadd china:city 12.16 30.24 hangzhou 108.69 34.26 xian

从key里返回所有给定位置元素的位置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 beijing chongqing
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
2) 1) "106.49999767541885376"
   2) "29.52999957900659211"

GEODIST

两人之间的距离

单位

  • m表示单位为米
  • km表示单位为千米
# 计算北京到上海的直线距离
127.0.0.1:6379> GEODIST china:city beijing shanghai km
"1067.3788"

georadius以给定的经度为中心,找出某一半径内的元素

我附近的人?

  • 第一步:获取所有附近的人的地址,定位!! 通过半径来查询
# 以经度110,纬度30为中心,1000km为半径,找坐标
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km
1) "chongqing"
2) "xian"
3) "shenzhen"
# 找到城市坐标之后再算出距离
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist
1) 1) "chongqing"
   2) "341.9374"
2) 1) "xian"
   2) "489.6110"
3) 1) "shenzhen"
   2) "922.9093"
# 再展示经纬度
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withcoord
1) 1) "chongqing"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) 1) "108.68999987840652466"
      2) "34.25999964418929977"
3) 1) "shenzhen"
   2) 1) "114.01000052690505981"
      2) "22.5200000879503861"
# 获取指定数量的人
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withcoord count 1
1) 1) "chongqing"
   2) 1) "106.49999767541885376"
      2) "29.52999957900659211"
# 中心点由指定元素(找出指定元素周围的元素)
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km
1) "beijing"
2) "xian"

GEOHASH 返回一个或多个位置元素的Geohash表示

# 将二维的经纬度转换为一维的字符串,如果两个长得信的话,代表这两个狠相近
127.0.0.1:6379> GEOHASH china:city beijing chongqing
1) "wx4fbxxfke0"
2) "wm5xzrybty0"

GEO底层的实现原理其实就是Zset!我们可以使用zset命令来操作deo

# 用zrange可以查看所有的元素
127.0.0.1:6379> zrange china:city 0 -1
1) "hangzhou"
2) "chongqing"
3) "xian"
4) "shenzhen"
5) "shanghai"
6) "beijing"
# zrem可以删除元素
127.0.0.1:6379> zrem china:city beijing
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "hangzhou"
2) "chongqing"
3) "xian"
4) "shenzhen"
5) "shanghai"

Hyperloglog

什么是基数?

A{1,3,5,7,8,9} B{1,3,5,7,8}

基数:不重复的元素 = 5,可以接受误差

简介

Redis 2.8.9版本更新了Hyperloglog数据结构

Redis Hyperlogog基数统计的算法

网页的UV(访问量,一个人访问多次但是还是算作一个人)

传统的方式,set保存用户的id,然后就可以统计set中的元素数量,作为标准判断。这个方式如果保存大量用户id就会比较麻烦,我们的目的就为了基数,而不是保存用户id

Hyperloglog优点

2^64不同的元素的技术,只需要费12kb内存,如果从内存角度来看,Hyperloglog是首选

0.81%的错误率

127.0.0.1:6379> PFADD mykey a b c d e f g h i j	# 设置mykey
(integer) 1
127.0.0.1:6379> PFCOUNT mykey	# 统计mykey数量
(integer) 10
127.0.0.1:6379> PFADD mykey2 i j k z x c v b n m	# 设置mykey2
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2	# 统计mykey2
(integer) 10
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2	# 求mykey和mykey2的并集,然后将其合并到mykey3
OK
127.0.0.1:6379> PFCOUNT mykey3 # 统计mykey3的数量
(integer) 16

Bitmaps

位存储

统计疫情感染人数:0 0 10 0

统计用户信息,活跃、不活跃!登陆、未登陆、打卡。userid status day,365大卡,两个状态的,都可以使用Bitmaps。

Bitmaps位图,数据结构,都是操作二进制位来进行记录,只有0和1两个状态!

365天=365bit 1字节=8bit

![image-20201213162824279](/Users/cjp/Library/Application Support/typora-user-images/image-20201213162824279.png)