--- 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 ![](https://i.imgur.com/PsuuZTy.png) * 清理舊數據 >> sorted set ![](https://i.imgur.com/AUCFfIK.png) * Statistic ![](https://i.imgur.com/vDbRqgW.png) ## 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 來建立連線 ![](https://i.imgur.com/tXi6J4A.jpg)