学Java就到狂神说
Redis简介:
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。
Nosql
泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在处理web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,出现了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题
NoSQL特点:
1、数据之间没有关系,容易扩展
2、大数据量高性能
3、数据类型是多样型的!(不需要事先设计数据库!随取随用!如果是数据量十分大的表,很多人就无法设计了)
4、传统的关系型数据库(RDBMS)和NoSQL
传统的 RDBMS
- 结构化组织
- SQL
- 数据和关系都存在单独的表中
- 操作操作 , 数据定义语言
- 严格的一致性
- 基础的事务
- ...
Nosql(not only sql)
- 不仅仅是数据
- 没有固定的查询语言
- 键值对存储,列存储,文档存储,图形存储(社交关系)
- 最终一致性
- CAP定理 和 BASE (异地多活!) 初级架构师!
- 高性能,高可用,高可扩展性
- ...
KV键值对:
文档型数据库(bson格式 和 json一样):
MongoDB(掌握)
ConthDB
列存储数据库:
图关系数据库:
Redis是什么?
Redis( Remote Dictionary Server ) , 即远程字典服务!
Redis能干嘛?
1、内存存储、持久化,内存中是断电即失,所以说持久化很重要(rdb 、 aof)
2、效率高,可以用于高速缓存
3、发布订阅系统
…
特性
1、多样的数据类型
2、持久化
3、集群
4、事务
…
1 程序放在opt目录下
[root@iz8vb4nxo286g9mk6p8fnhz home]# mv redis-5.0.8.tar.gz /opt
2 然后进入opt目录
[root@iz8vb4nxo286g9mk6p8fnhz opt]# cd /opt
3 解压
[root@iz8vb4nxo286g9mk6p8fnhz opt]# tar -zxvf redis-5.0.8.tar.gz
4 进入解压后的文件
[root@iz8vb4nxo286g9mk6p8fnhz opt]# cd redis-5.0.8
1.进入解压后的文件 , 安装环境
yum install gcc-c++
2.执行make命令,会把所有需要的文件都配置上
make
make install
user/local/bin
1.进入bin目录
cd usr/local/bin
2.创建一个文件夹
mkdir myconfig
3.将redis的配置文件拷贝过来
cp /opt/redis-5.0.8/redis.conf myconfig
1 进入刚才放redis的配置的文件夹
cd myconfig
2 进入之后找到下图中的daemonize 后边的no改为yes
vim redis.conf
[root@iz8vb4nxo286g9mk6p8fnhz bin]# redis-cli -p 6379
127.0.0.1:6379> shutdown
not connected> exit
完毕!
redis-benchmark 是一个压力测试工具!
官方自带的性能测试工具
参数如下:
# 记得先连接redis 再测试
# 测试:100个并发连接 100000个请求
[root@iz8vb4nxo286g9mk6p8fnhz bin]# redis-benchmark -h localhost -p 6379 -c 100 -n 100000
redis默认有16个数据库
默认使用的是第0个
可以使用select进行切换数据库!
[root@iz8vb4nxo286g9mk6p8fnhz bin]# redis-cli -p 6379
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> DBSIZE #使用dbsize来查看数据
(integer) 0
127.0.0.1:6379[3]> set name qianyi #set设置数据
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 1
127.0.0.1:6379[3]> get name #get获取数据
"qianyi"
127.0.0.1:6379[3]> keys * #查看所有key
127.0.0.1:6379[3]> flushdb #清空当前数据库 , 也可以flushall清空所有
OK
127.0.0.1:6379[3]> get name
(nil)
Redis是很快的,官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了!
Redis 是C语言写的
Redis 为什么单线程还这么快?
1、误区1 :高性能的服务器一定是多线程的?
2、误区2 :多线程(CPU上下文会切换!)一定比单线程效率高
核心:redis 是将所有的数据全部放在内存中的,所以说使用单线程去操作效率是最高的。对于内存系统来说,如果没有上下文切换效率是最高的。
# 一些简单命令
127.0.0.1:6379> EXISTS name # 判断当前的key是否存在
127.0.0.1:6379> move name 1 # 将key值为name的移动到1号数据库
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> EXPIRE name 10 # 设置name的过期时间为10s
(integer) 1
127.0.0.1:6379> ttl name # 查看name的生命周期
(integer) 7
127.0.0.1:6379> ttl name
(integer) 3
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> type name # 查看key的类型
string
########################################################################
127.0.0.1:6379[1]> set key1 v1
OK
127.0.0.1:6379[1]> EXISTS key1
(integer) 1
127.0.0.1:6379[1]> get key1
"v1"
127.0.0.1:6379[1]> APPEND key1 "hello" # 在key1后边追加字符串
(integer) 7
127.0.0.1:6379[1]> get key1
"v1hello"
127.0.0.1:6379[1]> APPEND key1 ",qianyi"
(integer) 14
127.0.0.1:6379[1]> STRLEN key1 # 查看key1的长度,和java中的用法差不多 strlen
(integer) 14
127.0.0.1:6379[1]> get key1
"v1hello,qianyi"
########################################################################
# i++ i+=
127.0.0.1:6379[1]> set views 0 # 初始浏览量0
OK
127.0.0.1:6379[1]> get views
"0"
127.0.0.1:6379[1]> incr views # 自增1命令 incr
(integer) 1
127.0.0.1:6379[1]> incr views
(integer) 2
127.0.0.1:6379[1]> get views
"2"
127.0.0.1:6379[1]> decr views # 自减1命令 decr
(integer) 1
127.0.0.1:6379[1]> get views
"1"
127.0.0.1:6379[1]> incrby views 10 # incrby 指定增量10
(integer) 11
127.0.0.1:6379[1]> get views
"11"
127.0.0.1:6379[1]> decrby views 3 # decrby 指定减量10
(integer) 8
127.0.0.1:6379[1]> get views
"8"
########################################################################
# 获取字符串 指定范围 range
127.0.0.1:6379> set key1 "hello,qianyi"
OK
127.0.0.1:6379> get key1
"hello,qianyi"
127.0.0.1:6379> getrange key1 0 3 # 获取下标从0-3的字符串
"hell"
127.0.0.1:6379> getrange key1 0 -1 # 0 -1 代表获取全部
"hello,qianyi"
########################################################################
#替换 字符串!! setrange
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 # setrange 指定字符串 下标 要替换的内容
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
########################################################################
# setex : 设置过期时间
# setnx : 不存在 则 设置
127.0.0.1:6379> setex key3 30 "my time has 30 seconds" # 过期时间 30s
OK
127.0.0.1:6379> ttl key3
(integer) 24
127.0.0.1:6379> get key3
"my time has 30 seconds"
127.0.0.1:6379> setnx mykey "the first value" # 第一次设置不存在mykey
(integer) 1
127.0.0.1:6379> get mykey
"the first value"
127.0.0.1:6379> setnx mykey "the second value" # 第二次设置,已经存在mykey
(integer) 0 # 所以返回0 , 设置失败
127.0.0.1:6379> get mykey
"the first value"
########################################################################
# mset : 批量设置值
# mget : 批量获取值
# msetnx : 若不存在则设置
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 批量设置
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k1"
3) "k2"
127.0.0.1:6379> mget k1 k2 k3 #批量获取
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 # msetnx是原子性操作,要么都执行,要么都不执行
(integer) 0
127.0.0.1:6379> get k4
(nil)
########################################################################
# user:1:name 用户1的姓名
# user:1:age 用户1的年龄
127.0.0.1:6379> mset user:1:name qianyi user:1:age 15
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "qianyi"
2) "15"
127.0.0.1:6379> mset user:2:name zhangsan user:2:age 13
OK
127.0.0.1:6379> mget user:1:name user:1:age user:2:name user:2:age
1) "qianyi"
2) "15"
3) "zhangsan"
4) "13"
########################################################################
# getset 先获取再设置
127.0.0.1:6379> getset name abcde # 如果不存在值,则返回nil
(nil)
127.0.0.1:6379> get name
"abcde"
127.0.0.1:6379> getset name 123456 # 如果存在值,获取原来的值,并设置新的值
"abcde"
127.0.0.1:6379> get name
"123456"
########################################################################
在redis里面,我们可以把list玩成栈、队列、阻塞队列!
所有的list命令都是用l开头的
######e################################################################
# 操作list的基本命令
# lpush :将一个或多个值插入到队列头部 rpush : 将一个或多个值插入到队列尾部
# lpop : 弹出队列头部的一个元素 rpop : 弹出队列尾部的一个元素
# lrange : 查看
# lindex : 获取对应下标的值
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> lpush list one two three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lpop list
"three"
127.0.0.1:6379> rpush list four
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"d
3) "four"
######################################################################
# lindex
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lindex list 1
"one"
127.0.0.1:6379> lindex list 0
"two"
######################################################################
# llen : 查看list长度
127.0.0.1:6379> lpush list one two three four five
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"
127.0.0.1:6379> llen list
(integer) 5
######################################################################
# lrem : 移除指定的值
127.0.0.1:6379> lrange list 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"
127.0.0.1:6379> lpush list three
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "five"
3) "four"
4) "three"
5) "two"
6) "one"
127.0.0.1:6379> lrem list 2 three # 移除两个three (2 代表count 数量)
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "five"
2) "four"
3) "two"
4) "one"
######################################################################
# ltrim : 根据下标来截断list,同时返回截断的值,同时list被改变。
127.0.0.1:6379> lpush mylist "hello1"
(integer) 1
127.0.0.1:6379> lpush mylist "hello2"
(integer) 2
127.0.0.1:6379> lpush mylist "hello3"
(integer) 3
127.0.0.1:6379> lpush mylist "hello4"
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello4"
2) "hello3"
3) "hello2"
4) "hello1"
127.0.0.1:6379> ltrim mylist 1 2 # 截断mylist从1-2的值
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello3"
2) "hello2"
######################################################################
# rpoplpush : 移除指定列表的最后一个元素到另一个列表的头部
127.0.0.1:6379> rpush mylist "hello1"
(integer) 1
127.0.0.1:6379> rpush mylist "hello2"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpop mylist
"hello2"
127.0.0.1:6379> rpush mylist "hello3"
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
3) "hello3"
127.0.0.1:6379> rpoplpush mylist myotherlist # rpoplpush : 移除指定列表的最后一个元素到另一个列表的头部
"hello3"
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
127.0.0.1:6379> lrange myotherlist 0 -1
1) "hello3"
######################################################################
# lset : 将列表中指定下标的值改为另一个值
127.0.0.1:6379> lpush list value
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "value"
127.0.0.1:6379> lset list 0 item # lset : 将列表中指定下标的值改为另一个值
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
127.0.0.1:6379> exists list
(integer) 1
######################################################################
# linsert : 在指定值的前边或后边插入值
127.0.0.1:6379> rpush list hello
(integer) 1
127.0.0.1:6379> rpush list world
(integer) 2
127.0.0.1:6379> linsert list before world before
(integer) 3
127.0.0.1:6379> linsert list after world after
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "before"
3) "world"
4) "after"
set中的值不能重复
######################################################################
# sadd : 往myset 里边添加元素
# smembers : 查看myset 中的元素
# sismember : 查看某值是否存在myset 中,存在 返回1 ; 不存在 返回0
# scard : 获取set集合中元素的个数
127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset qianyi
(integer) 1
127.0.0.1:6379> sadd myset world
(integer) 1
127.0.0.1:6379> smembers myset
1) "world"
2) "qianyi"
3) "hello"
127.0.0.1:6379> sismember myset qianyi
(integer) 1
127.0.0.1:6379> scard myset
(integer) 3
######################################################################
# srem : 移除指定的值
127.0.0.1:6379> smembers myset
1) "world"
2) "qianyi"
3) "hello"
127.0.0.1:6379> srem myset hello
(integer) 1
127.0.0.1:6379> smembers myset
1) "world"
2) "qianyi"
######################################################################
# set : 无序不重复集合
# srandmember : 随机抽取指定个数元素
127.0.0.1:6379> sadd myset one two three four five six seven eight nine ten
(integer) 10
127.0.0.1:6379> smembers myset
1) "two"
2) "one"
3) "four"
4) "six"
5) "seven"
6) "five"
7) "eight"
8) "ten"
9) "three"
10) "nine"
127.0.0.1:6379> srandmember myset
"nine"
127.0.0.1:6379> srandmember myset
"ten"
127.0.0.1:6379> srandmember myset 2
1) "nine"
2) "four"
######################################################################
# spop : 随机弹出指定的值
127.0.0.1:6379> spop myset
"nine"
127.0.0.1:6379> spop myset
"eight"
127.0.0.1:6379> spop myset
"ten"
127.0.0.1:6379> spop myset
"one"
127.0.0.1:6379> spop myset
"three"
127.0.0.1:6379> spop myset
"five"
127.0.0.1:6379> smembers myset
1) "four"
2) "six"
3) "seven"
4) "two"
######################################################################
# smove : 将指定的元素移动到另一个集合中
127.0.0.1:6379> sadd myset "hello"
(integer) 1
127.0.0.1:6379> sadd myset world
(integer) 1
127.0.0.1:6379> sadd myset qianyi
(integer) 1
127.0.0.1:6379> smove myset myset2 qianyi
(integer) 1
127.0.0.1:6379> smembers myset
1) "world"
2) "hello"
127.0.0.1:6379> smembers myset2
1) "qianyi"
######################################################################
B站的共同关注。
# sdiff : 求两个集合的差集
# sinter : 求两个集合的交集
# sunion : 求两个集合的并集
127.0.0.1:6379> clear
127.0.0.1:6379> sadd myset1 a b c
(integer) 3
127.0.0.1:6379> sadd myset2 c d e
(integer) 3
127.0.0.1:6379> smembers myset1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> smembers myset2
1) "c"
2) "d"
3) "e"
127.0.0.1:6379> smembers myset1 myset2
(error) ERR wrong number of arguments for 'smembers' command
127.0.0.1:6379> sdiff myset1 myset2
1) "b"
2) "a"
127.0.0.1:6379> sinter myset1 myset2
1) "c"
127.0.0.1:6379> sunion myset1 myset2
1) "c"
2) "d"
3) "b"
4) "a"
5) "e"
Map集合 , key - map ! 这个值是一个map
#################################################
# hset : 添加值
# hget : 获取值
# hmset : 一次添加多个值 hmget : 一次获取多个值
# hgetall : 获取hash中的所有值
# hdel : 删除hash里的某个值
# hlen : 查看hash中的map的个数
127.0.0.1:6379> hset myhash field1 qianyi
(integer) 1
127.0.0.1:6379> hget myhash field1
"qianyi"
127.0.0.1:6379> hmset myhash field1 hello field2 world
OK
127.0.0.1:6379> hmget myhash field1 field2
1) "hello"
2) "world"
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hello"
3) "field2"
4) "world"
127.0.0.1:6379> hdel myhash field1
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
127.0.0.1:6379> hlen myhash
(integer) 1
#################################################
# hkeys : 获得所有的field
# hvals : 获得所有的value
127.0.0.1:6379> hmset myhash field1 hello field2 world
OK
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
3) "field1"
4) "hello"
127.0.0.1:6379> hkeys myhash
1) "field2"
2) "field1"
127.0.0.1:6379> hvals myhash
1) "world"
2) "hello"
#################################################
# hincrby 指定增量
# hsetnx 不存在则设置
127.0.0.1:6379> hset myhash field3 1
(integer) 1
127.0.0.1:6379> hincrby myhash field3 5
(integer) 6
127.0.0.1:6379> hsetnx myhash field3 1
(integer) 0
127.0.0.1:6379> hsetnx myhash field4 1
(integer) 1
在set的基础上增加了一个值 , set k1 v1 zset k1 score1 v1(根据score排序)
# zadd : 添加
127.0.0.1:6379> zadd myset 1 one
(integer) 1
127.0.0.1:6379> zadd myset 2 two
(integer) 1
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
######################################################################
# 可自己定义排序
# srangebyscore
127.0.0.1:6379> zadd salary 2500 xiaohong
(integer) 1
127.0.0.1:6379> zadd salary 1000 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 500 qianyi
(integer) 1
127.0.0.1:6379> ZREVRANGE salary 0 -1 withscores # 从大到小排序
1) "xiaohong"
2) "2500"
3) "zhangsan"
4) "1000"
5) "qianyi"
6) "500"
.1:6379> zrangebyscore salary -inf +inf withscores #-inf :负无穷 +inf:正无穷 从小到大排序
1) "qianyi"
2) "500"
3) "zhangsan"
4) "1000"
5) "xiaohong"
6) "2500"
127.0.0.1:6379> zrangebyscore salary -inf 1000 withscores # 只要负无穷-1000的
1) "qianyi"
2) "500"
3) "zhangsan"
4) "1000"
朋友的定位 附近的人 打车距离计算。
可以查询一些测试数据: 城市经度纬度查询 (百度)
##################################################
# geoadd : 添加地理位置
# 规则 : 北极南极无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入。
# 参数: key 值(纬度,经度,名称)
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
###################################################
# geodist : 查询两地之间的距离 后边可以添加单位
# m 表示单位为米。
# km 表示单位为千米。
# mi 表示单位为英里。
# ft 表示单位为英尺
# geopos : 查询某地的经纬度
# georadius : 查询指定经纬度附近指定距离的地区
# georadiusbymember : 查询指定地区附近指定距离的地区
# 用于 : 附近的人。
127.0.0.1:6379> geodist china:city beijing chongqing
"1464070.8051"
127.0.0.1:6379> geodist china:city beijing chongqing km
"1464.0708"
127.0.0.1:6379> geopos china:city chongqing
1) 1) "106.49999767541885376"
2) "29.52999957900659211"
127.0.0.1:6379> georadius china:city 110 50 1000 km
(empty list or set)
127.0.0.1:6379> georadius china:city 110 50 10000 km
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> georadius china:city 110 50 5000 km
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> georadius china:city 110 50 2000 km
1) "xian"
2) "beijing"
127.0.0.1:6379> georadiusbymember china:city chongqing 200 km
1) "chongqing"
127.0.0.1:6379> georadiusbymember china:city chongqing 500 km
1) "chongqing"
127.0.0.1:6379> georadiusbymember china:city chongqing 1000 km
1) "chongqing"
2) "xian"
#################################################
# zrange : 查看所有城市
# zrem : 移除指定元素
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> zrem china:city chongqing
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "xian"
2) "shenzhen"
3) "hangzhou"
4) "shanghai"
5) "beijing"
Hyperloglog:
是基数统计的算法!
优点:占用的内存是固定的,只需要 12KB的内存,如果从内存的角度来说的话,Hyperloglog是首选的!
网页的 UV (一个人访问一个网站多次,但是还是算作一个人)
传统的方式 , set 保存用户的id,然后统计set的元素个数即可。
但是这个方式如果保存大量的用户ID,就会比较麻烦!我们的目的是为了计数 ,而不是保存ID。
测试使用
# PFADD : 添加元素
# PFCOUNT : 统计有多少个元素
# PFMERGE : 合并两个key , 并生成新的key
# 统计不重复的 ! ! !
127.0.0.1:6379> PFADD mykey1 a b c d e f g h i j k l
(integer) 1
127.0.0.1:6379> PFCOUNT mykey1
(integer) 12
127.0.0.1:6379> PFADD mykey2 i j k l m n
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 6
127.0.0.1:6379> PFMERGE mykey3 mykey1 mykey2
OK
127.0.0.1:6379> PFCOUNT mykey3
(integer) 14
如果允许容错,那么一定可以使用 Hyperloglog
如果不允许容错,就是用set或者自己的数据类型即可!
位存储
统计疫情感染人数 : 0 1 0 1 0 0 0 1
统计用户信息 : 活跃,不活跃!登录 ,未登录!打卡,365打卡!
两个状态的都可以使用 Bitmaps,位图!
操作二进制位来进行记录,就只有 0 和 1 两个状态!
使用btimap 来记录周一到周日的打卡!
周一 : 1 周二 : 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 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0
查看某一天是否打卡
127.0.0.1:6379> getbit sign 6
(integer) 0
127.0.0.1:6379> getbit sign 1
(integer) 1
统计打卡的天数
127.0.0.1:6379> bitcount sign
(integer) 4