Flask使用Redis统计数据(持久化存储)
Redis做持久化存储
用户发表文章的统计: news_article_basic sql: select count(*) from news_article_basic where user_id=1; user_basic: article_count, fans_count sql: select article_count from user_basic where user_id=1; user_tongji: user_id, fans_count 缓存 原来统计数据的设计:在user_basic表中,添加字段进行统计。 存在的问题: 1.在高并发的情况下,在统一时刻触发统计的数量是巨大的。 2.为了数据的准确性,又必须加锁。所以对数据库的性能影响是巨大的。 在redis中,每个命令都是原子性的,既能提供高性能的访问,也能保证数据修改的完整性。 所以在项目中: 1.统计数据最终的选择方案是使用redis进行缓存。 2.redis持久保存层选择的是主从redis,因为数据要永久存储,没有对主从设置淘汰策略。 3.redis集群是用做缓存层,设置了淘汰策略。用户发布文章数量统计分析
用户发布文章redis数据库设计思路分析: 所有用户发布文章数量全部放在一个key中. key: count:user:arts value: 值选择zset类型 member: 选择user_id score: 选择用户发布文章的数量 需求分析: 1.获取用户发布文章数量 发布文章数量 = zscore(key, user_id) 2.发布文章,用户发布文章数量加1. zincrby(key, user_id, 1) 错误的操作: count = zscore(key, user_id) # 此时有可能出现并发 count += 1 zadd(key, count, user_id) 这样会存在并发改的情况 正确的操作: zincrby(key, user_id, 1) 备注: 执行zincrby命令,是原子性的,不会出现并发改的情况,只有要么成功要么失败。代码实现(存储类封装)除了文章数量还有文章阅读,文章收藏数量等待,代码都是相似的只有key值不同,所以写了一个父类,子类继承即可
class CountStorageBase(object): """ 数据存储父类 """ key = '' @classmethod def get(cls, id_value): """ 获取 """ try: count = current_app.redis_master.zscore(cls.key, id_value) except ConnectionError as e: current_app.logger.error(e) try: count = current_app.redis_slave.zscore(cls.key, id_value) except RedisError as e: current_app.logger.error(e) count = 0 count = 0 if count is None else int(count) return count @classmethod def incr(cls, id_value, increment=1): """ 增加 """ try: current_app.redis_master.zincrby(cls.key, id_value, increment) except RedisError as e: current_app.logge.error(e) @classmethod def reset(cls, redis_client, *items): """ 重置数值,用于定时任务纠偏使用 """ pl = redis_client.pipeline() pl.delete(cls.key) pl.zadd(cls.key, *items) pl.execute() class UserArticlesCountStorage(CountStorageBase): """ 用户文章数量 """ key = 'count:user:arts' # 后续用来修正统计数据使用 @classmethod def db_query(cls): ret = db.session.query(Article.user_id, func.count(Article.id)) \ .filter(Article.status == Article.STATUS.APPROVED).group_by(Article.user_id).all() return ret
版权声明:本文为weixin_45439324原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。