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%的情况都是在读
有时候会出现多个用户读取同一个数据的情况,因此需要缓存来保存数据,用来减少服务器的压力

缓存主要解决读的问题
发展过程
优化数据结构和索引 –>文件缓存(IO)–> Memcached(当时最热门的技术)–>
当今企业架构演变
读写分离
分库分表 + 水平拆分 + MySQL集群

技术在发展的时候对人的要求也越来越高
本质:数据库(读,写)
数据库引擎
早些年MylSAM 表锁()
myisam:表锁(100w数据,查询张三的密码,会把整个表锁起来,高并发下会出现严重的问题)
早些年innodb 行锁
每次只锁一行
满满的就开始使用分库,分表来解决写的压力,MySql在那个年代提出了表分区!这个并没有多少公司使用,MySql的集群,很好的满足了那个年代的所有需求
如今最近的年代
技术爆炸:2010年-2020年,世界已经发生了翻天覆地的变化。(定位也是一种数据,一些音乐,一些热榜)
MySql的关系型数据库已经不够用了,数据量很多,变化很快!
-
现在有一些新的数据库
图型数据库
json也可以用来存到数据库里面BSON(mongodb使用这个)
MySQL有的人还用来存放一些比较大的文件,博客、图片!数据库表很大,效率就很低,如果有一种专门的数据库用来处理这种数据,mysql压力就会十分小(研究如何处理这些问题)大数据IO下,表几乎没法更改,假设有1亿条数据
目前一个基本的互联网项目!
阿里巴巴的演进分析
案例:阿里巴巴批发网
点击一个页面会出现很多图片,评论,视频等各种信息,这么多的东西不可能全部都用tomcat,也不可能都用一个数据库


公司有敏捷开发、极限编程
大量的公司都是做的相同的业务,因此要好好学习
数据层
- 挑战
- 解决方案,统一数据服务平台

如果未来想当一个架构师:没有什么事加一层解决不了的
# 1、商品的基本信息,
名称、价格、商家信息;
关系型数据库可以解决了:MySQL/Oracle(淘宝早年去IOE了 —— 王坚)
淘宝的MySQL不是大家用的MySQL
# 商品的描述、评论(文字比较多)
mongodb
# 图片
分布式文件系统FastDFS
- 淘宝自己的TFS
- google的GFS
- Hadoop HDFS
- 阿里云 oss云存储
# 商品的关键字(搜索)
- 搜索引擎 solr elasticsearch
- Isearch: 淘宝用的 多隆 开发的
# 商品的热门波段信息
- 内存数据库
- Redis Tair Memache
# 商品交易、外部交易接口
- 三方应用
一个简单的网页技术的背后一定不是大家所想的那么简单,大型互联网公司应用问题
- 数据类型太多了
- 数据源太多了,经常重构
- 数据要改造,大面积改造
解决方案:统一的数据服务层UDSL
在应用集群和底层数据源之间建立一个中间件

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


这里以上都是nosql概述,不仅能够提高大家的知识,还能够帮助大家了解大厂的工作内容
NoSQL的四大分类
KV键值对
- 新浪:Redis
- 美团:Redis+Tair
- 阿里、百度:Redis + memecache
文档型数据库
bson格式和json一样
- MongoDB(一般必须掌握)
- MongoDB是一个基于分布式文件存储的数据库,C++编写,主要用来处理大量的文档!
- MongoDB是一个基于关型数据库和非关系型数据库中中间的产品,MongoDB是非关系型数据库中功能最丰富,最像关系型数据库的!
列存储数据库
- HBase
- 分布式文件系统
图关系数据库
它不是存图型的,它是放的关系,比如朋友圈社交网络,广告推荐,专注于构建关系图
- Neo4J
- InfoGrid

敬畏之心可以使人进步!
Redis入门
Redis(Remote Dictionary Server),即远程字典服务,
用c语言编写,支持网络,基于内存亦可持久化的日志型,Key-Value数据库,并且提供多种语言的API
免费喝开源,是当下最热门的NoSQL技术之一,也被人们称为结构化数据库
Redis能干嘛

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
- 将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

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) 与范围查询, bitmaps, hyperloglogs 和 地理空间(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
基本数据类型,列表

十分强大,可以吧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
