# redis
> something redis is not a good choice, something redis is just ok, but redis is so easy
关于持久化和数据查询的相关技术 -> 关系型数据库再也不是放之四海皆准 -> 围绕数据的解决方案不可能再只有唯一一种
redis: 容易学习; 在处理一组特定的问题集的同时能保持相当的通用性 -> 什么是可行的,什么是不应该由Redis来处理的
- [try redis](http://try.redis.io/)
- [the little redis book](https://github.com/JasonLai256/the-little-redis-book/blob/master/cn/redis.md)
- [redis.cn](http://www.redis.cn/documentation.html): 文档/月报
- [Redis的数据类型——探究竟](https://mp.weixin.qq.com/s/Jve5RPYsSBsMtK1Lqo66Sg)
- [aliyun redis 开发规范](https://yq.aliyun.com/articles/531067)
- [redis的陈年往事](https://mp.weixin.qq.com/s/8-GxH4_WjoRe8DwFlk3qNw)
- [redis过期及逐出策略](https://help.aliyun.com/knowledge_detail/55892.html)
- [redis重要知识点](https://github.com/Weiwf/redis-mindmap)
## 最佳实践
- key命名: `业务:子业务:id` -> 可读/简洁/不含转义字符
- 过期时间
- 高危操作: flushdb flushall keys monitor
- 加锁: 1 == redis->incr(key)
- 游戏玩家积分排行版: zset
- 网上商城商品相关性分析: 为每种商品构建一个有序集合 -> score 为商品同时出现的次数
- pub/sub: 消息「非持久」 pub非独占 sub独占阻塞
- 数据集成(Data Integration): mysql -> redis
- 热点: client -> slb -> proxy(读写分离, 本地缓存->热点数据+技术) -> master(write) - slave(backup) - read
- 用户关注列表: hash uid-uid-value
- 评论游标分页: zset(id-timestamp) + hash(comment-id-content)
- redis 内存分析: pip install rdbtools + sqlite
- 秒杀: 秒杀前-商品详情页-浏览器缓存/CDN -> 秒杀开始-redis读写分离/数据(flag/all/donebooked) -> 库存-hash(all/booked)/lua脚本原子性 -> 落库-list
- 大量key操作: scan 分批 找到索引边界 批量(hmset pipeline)
- redis所有请求对不存在的key都有输出返回, 比如 ttl -2 -> 减少不必要的请求
- 避免value过大: 1k-性能拐点 MTU-1.5k
## base 入门
```
# key-value
set key value # 常使用 : 作为key的分隔符
get key
setnx key # set if not exist
incr key # incr 并发安全
del key
expire / expireat / ttl / persist # 过期, ttl->time to live
strlen getrange append # string类型的value
# list
lpush/rpush list value..
lpop/rpop list
llen list
lrange list 0 -1 # 查看所有
ltrim list 0 -1 # 只留下范围内的值, 其他删除
lindex/lset # 通过索引获取值/通过索引设置值
# set
sadd set value
srem set value # remove
sismember set value
smembers set
sunion s1 s2
sinter s1 s2 # 是否有共同元素
sinterstore s1 s2 s3 # 存储共同元素
# sorted set
zadd set score value # score is float number
zrange set 0 -1
zcount z s1 s2 # 按照 score 进行 count
zrank / zrevzank # 升序/降序
# hash
hset h field value
hmset h f1 v1 f2 v2 ...
hget h f
hgetall h
hincrby h f num # increment to a num value
hdel h f
# HyperLogLog
pfadd key v1 v2
pfcount key
pfmerge new key1 key2
# pub/sub
subscribe / unsubscribe # 订阅
psubscribe # 模式匹配订阅
publish channel value
blpop / brpop / blpush / brpush
# pipeline: 批量操作
# eval + lua
eval code
script load / evalsha # 加载脚本后返回 sha1 值, 通过 sha1 值执行脚本
# transaction
multi
...do something
exec / discard # 非严格意义上事务->操作失败/discard->不回滚
watch / unwatch # CAS 乐观锁
# more
redis-cli --raw # 中文乱码
redis-benchmark # 类似 ab 1w~10w/s
redis-server # 启动时没有指定 conf, redis将采用默认配置
config set slowlog-log-slower-than 0 # 修改配置
auth # 密码验证
info # 查看服务器状态
select 1 # 切换db, 默认为0, 默认有 16 个
type key # 查看 key 的数据类型
scan 0 match * count 10 # 使用 scan 替代 keys/smembers等会一次性扫描所有记录的命令; scan 返回2个值, 第一个值为游标
flushdb / flushall # 高危命令
setbit / getbit # 今天我们有多少个独立用户访问 -> 2个命令/1.28亿/50ms/16m
monitor # 监控
slowlog # 慢日志
slowlog get
slowlog get 10
sort # list/set/hash -> 基于bug严重级别的排序 / 大数据量双维度排序
# redis-cli 数据备份
bgsave # RDB
redis-cli -h old_instance_ip -p old_instance_port config set appendonly yes
redis-cli -h aliyun_redis_instance_ip -p 6379 -a password --pipe < appendonly.aof
```
- key & value: key的数据为标量, value可为任意数据类型(序列化)
- Big O Notation: 许多Redis命令都具有O(1)的时间复杂度; `O(1) -> O(log(N)) -> O(N)`; N 不一定是记录总数; 发现一些操作具有O(N)的时间复杂度时 -> 可能可以找到更为好的方法去处理
- Memory and Persistence(3种方式): snapshot append-only slaveDB
- Replication(复制): 配置 `slaveof` -> master-slave; 没有提供自动故障恢复
- backup(备份): Redis会把快照存储为一个名为`dump.rdb`的文件
- Scaling and Redis Cluster(缩放/集群)