- SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
- SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存, 也可以是 memcache), 此处别名依赖缓存的设置
- =================================
九, Redis 补充 - 分布式, 高可用, 读写分离
- Redis
- http://www.cnblogs.com/wupeiqi/articles/9348938.html
1. Redis 是什么?
是一个由 C 语言编写的对内存进行存取数据的软件(NoSQL 数据库; 非关系型数据库);
2. Redis 是单进程单线程的.
3. Redis 基础:
- 5 大数据类型;
- 字符串
- 列表
- 字典
- 集合
- 有序结合
- 发布和订阅
- 事务
4. 主从 = 高可用 = HA
服务器 A:10.211.55.19
Redis-server /etc/Redis-6379.conf # 内部 bind:0.0.0.0 port: 6379
服务器 B: 10.211.55.20
Redis-server /etc/Redis-6379.conf # 内部 bind:0.0.0.0 port: 6379 slaveof: 10.211.55.19
特殊情况来了: 如果主宕机, 应该讲从切换成主;
手动:
- 登录 Redis 将从变成主
- 修改代码, 将连接字符串 IP 改成 10.211.55.20
自动:
- keepalived, 监听服务器的状态做高可用; 第三方组件;
- sentinel(哨兵), 检测 Redis 主服务器的状态并将所有的 slave 获取到, 一旦主挂掉, 则立即将从切换成主;
- Redis-sentinel /etc/Redis-sentinel-26379.conf(主 IP, 失败个数)
- Redis-sentinel /etc/Redis-sentinel-26380.conf
- Redis-sentinel /etc/Redis-sentinel-26381.conf
Python 操作:
- from Redis.sentinel import Sentinel
- # 连接哨兵服务器(主机名也可以用域名)
- sentinel = Sentinel([('10.211.55.20', 26379)],socket_timeout=0.5)
- # # 获取主服务器地址
- # master = sentinel.discover_master('mymaster')
- # print(master)
- #
- # # # 获取从服务器地址
- # slave = sentinel.discover_slaves('mymaster')
- # print(slave)
- #
- #
- # # # 获取主服务器进行写入
- # master = sentinel.master_for('mymaster')
- # master.set('foo', 'bar')
- # # # # 获取从服务器进行读取(默认是 round-roubin)
- # slave = sentinel.slave_for('mymaster', password='redis_auth_pass')
- # r_ret = slave.get('foo')
- # print(r_ret)
总结:
- 高可用
- 读写分离
5. 集群 = 分布式
如何实现分布式集群:
- codis, 国产 豌豆荚 开源;
- twemproxy,Twitter 开源
- cluster,Redis 官方提供
Redis 的 cluster 的原理?
16384 槽位
服务器 A: 0-5000
服务器 B: 5001-10000
服务器 B: 10001 - 16384
Python 操作 Redis cluester:
Redis-py-cluster 模块
6. 分布式锁 redlock 算法
- dlm = Redlock([{"host": "localhost", "port": 6379, "db": 0}, ])
- # 如果 my_lock 有值, 则表示获取锁了
- # 如果 my_lock 无值, 则表示未获取锁, 别人获取走了.
- my_lock = dlm.lock("my_resource_name",1000)
- dlm.unlock(my_lock) # 删除时调用 lru 脚本
Redis 分布式锁实现原理:
1. 配置所有要连接的服务器并计算服务器一半的个数;
2. 获取锁:
- 传入参数: key, 内部生成随机字符串, 超时时间
- 循环所有服务器, 在服务器上设置:
SET key 随机字符串 NX PX 超时时间 # 如果已经存在则不设置
- 设置成功的个数>= 一半 + 1 且 花费时间小于超时时间
3. 释放锁
- 删除 key 和 value(内部调用 lru 脚本)
- 超时释放
7. 其他:
- 持久化:
- AOF, 记录所有命令;
- RDB, 指定时间间隔做快照;
- 过期策略
voltile-lru: 从已设置过期时间的数据集 (server.db[i].expires) 中挑选最近最少使用的数据淘汰
volatile-ttl: 从已设置过期时间的数据集 (server.db[i].expires) 中挑选将要过期的数据淘汰
volatile-random: 从已设置过期时间的数据集 (server.db[i].expires) 中任意选择数据淘汰
allkeys-lru: 从数据集 (server.db[i].dict) 中挑选最近最少使用的数据淘汰
allkeys-random: 从数据集 (server.db[i].dict) 中任意选择数据淘汰
no-enviction(驱逐): 禁止驱逐数据
- 不要是直接使用:
- - key
- - all
一定要使用 scan_iter
十, Redis 补充 - 应用
Redis 是一个 key-value 存储系统 http://baike.baidu.com/view/51839.htm . 和 Memcached 类似, 它支持存储的 value 类型相对更多, 包括 string(字符串),list(链表 http://baike.baidu.com/view/549479.htm ),set(集合),zset(sorted set -- 有序集合)和 hash(哈希类型). 这些数据类型 http://baike.baidu.com/view/675645.htm 都支持 push/pop,add/remove 及取交集并集和差集及更丰富的操作, 而且这些操作都是原子性的. 在此基础上, Redis 支持各种不同方式的排序. 与 Memcached 一样, 为了保证效率, 数据都是缓存在内存中. 区别的是 Redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件, 并且在此基础上实现了 master-slave(主从)同步.
View Code
实现计数器
5, 发布订阅
发布者: 服务器
订阅者: Dashboad 和数据处理
Demo 如下:
RedisHelper
订阅者:
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- from monitor.RedisHelper import RedisHelper
- obj = RedisHelper()
- redis_sub = obj.subscribe()
- while True:
- msg= redis_sub.parse_response()
- print msg
发布者:
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- from monitor.RedisHelper import RedisHelper
- obj = RedisHelper()
- obj.public('hello')
- 6. sentinel
Redis 重的 sentinel 主要用于在 Redis 主从复制中, 如果 master 顾上, 则自动将 slave 替换成 master
- #!/usr/bin/env python
- # -*- coding:utf-8 -*-
- from Redis.sentinel import Sentinel
- # 连接哨兵服务器(主机名也可以用域名)
- sentinel = Sentinel([('10.211.55.20', 26379),
- ('10.211.55.20', 26380),
- ],
- socket_timeout=0.5)
- # # 获取主服务器地址
- # master = sentinel.discover_master('mymaster')
- # print(master)
- #
- # # # 获取从服务器地址
- # slave = sentinel.discover_slaves('mymaster')
- # print(slave)
- #
- #
- # # # 获取主服务器进行写入
- # master = sentinel.master_for('mymaster')
- # master.set('foo', 'bar')
- # # # # 获取从服务器进行读取(默认是 round-roubin)
- # slave = sentinel.slave_for('mymaster', password='redis_auth_pass')
- # r_ret = slave.get('foo')
- # print(r_ret)
来源: http://www.bubuko.com/infodetail-2956184.html