---
tags: Redis
---
# Ch5. Using Redis for application support
## 5.1 Logging to Redis
* Linux and Unix
* logging to a file
* 不同服務寫入不同log file,處理機制不同
* 不易統合所有log file並對其做些處理
* syslog
* syslog 會接收、分類及儲存記錄訊息
* 就日誌的輪換與刪除
* 轉換給其他系統做處理
* Recent log
* 紀錄最新日誌 > list
```
# 思路:将日志加入list,然后修剪到规定大小
def log_recent(conn, name, message, severity=logging.INFO, pipe=None):
severity = str(SEVERITY.get(severity, severity)).lower()
# 日志的KEY,构成:recent:日志名称:日志级别
destination = 'recent:%s:%s'%(name, severity)
message = time.asctime() + ' ' + message # 日志信息前面添加时间信息
pipe = pipe or conn.pipeline()
pipe.lpush(destination, message) # 1. 加入list
pipe.ltrim(destination, 0, 99) # 2. 截取最近100条记录
pipe.execute() # 执行以上两步
# 运行:log_recent(conn, 'test', 'test_msg')
# 结果:(key)recent:test:info (value)Sun Jun 23 11:57:38 2019 test_msg
```
* 紀錄常見日誌 > sorted set
```
# 思路:消息作为成员记录到有序集合,消息出现频率作为成员的分值(score)
# 记录的时间范围为1小时,记录的时候发现已经过了一小时,
# 则把已有的记录归档到上一小时(通过把KEY重命名来实现)
# 则新的一小时消息频率有从0开始记录
# 用于记录的KEY:[common:日志名称:日志级别]
def log_common(conn, name, message, severity=logging.INFO, timeout=5):
severity = str(SEVERITY.get(severity, severity)).lower()
destination = 'common:%s:%s'%(name, severity)
#当前所处小时数
start_key = destination + ':start' # common:日志名称:日志级别:start
pipe = conn.pipeline()
end = time.time() + timeout
while time.time() < end:
try:
pipe.watch(start_key)
# datetime(*now[:4]).isoformat() --> '2019-06-23T06:00:00'
now = datetime.utcnow().timetuple()
# 简单获取小时数(原书方法行不通,这里加以修改)
hour_start = now.tm_hour
# 获取[common:日志名称:日志级别:start]的值
# 这里返回字符串类型,注意转为整型
existing = pipe.get(start_key)
pipe.multi()
# 如果值存在 且 小于当前小时数
if existing and int(existing) < hour_start:
# 进行归档
# KEY [common:日志名称:日志级别] 重命名为 [common:日志名称:日志级别:last]
pipe.rename(destination, destination + ':last')
# KEY [common:日志名称:日志级别:start] 重命名为 [common:日志名称:日志级别:pstart]
pipe.rename(start_key, destination + ':pstart')
# 之前的KEY已经归档,这里是新的
pipe.set(start_key, hour_start)
# 不存在则添加该日志开始时间记录
elif not existing:
# KEY [common:日志名称:日志级别:start] 的值设置为当前小时数
pipe.set(start_key, hour_start)
# 对有序集合destination的成员message自增1
# 注意:zincrby在redis-py3.0+的用法
pipe.zincrby(destination, 1, message)
# 记录到最新日志
log_recent(pipe, name, message, severity, pipe)
return
# 如果其他客户端刚好有操作,修改了watch的key,进行重试
except redis.exceptions.WatchError:
continue
# 运行
log_common(conn, 'test', 'msg')
#结果
#(zset)common:test:info msg --> 1
# -->1小时后再次记录日志的话,该KEY就会变成common:test:info:last
#(string)common:test:info:start 14(小时数)
# -->1小时后再次记录日志的话,该KEY就会变成common:test:info:pstart
#(list)recent:test:info Wed Jun 26 22:53:17 2019 msg
```
## 5.2 Counters and statistic
* Counters
* 紀錄1秒鐘、5秒鐘......頁面點擊數 >> hash

* 清理舊數據 >> sorted set

* Statistic

## 5.3 IP-to-city and country lookup
1. 預先存入ip與地址進redis
2. ip 轉換成整數分值
3. sorted set
## 5.4 Service discovery and configuration
* one redis server per application component
* 使用 decorator 來建立連線
