# auto_update_local_cache **Repository Path**: huoyingwhw/auto_update_local_cache ## Basic Information - **Project Name**: auto_update_local_cache - **Description**: Python项目自动更新本地内存的案例 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-07-25 - **Last Updated**: 2025-07-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 前言 实际项目中,为了查询的效率,我们会把数据库的数据缓存到本地,但是这会带来一个问题:如果项目是多pod部署的话,通过接口修改数据库的数据后再更新本地内存只会修改一个pod的内存数据,其他pod不会修改,这就回造成数据不同步的问题。 为了解决上述的问题,本项目提供了如下几种方案: etcd、nacos、consul、redis的PUB-SUB(发布-订阅)。 ## ✅ 注意一个细节 flask项目启动做一下设置: ```python if __name__ == '__main__': app.run(debug=False, use_reloader=False) ``` `flask run with reloader`会开启多个进程: - 一个用于监控文件变化(主进程) - 一个用于实际运行 Flask App(子进程) 我们项目中使用本地的全局变量`NameCacheDict` 去缓存数据库中的数据,由于多个进程中的数据不共享,所以会导致它们各自的`NameCacheDict`是独立的内存空间! **❗️❗️所以,如果是单体的项目,并且是多进程部署的话,如果使用全局的内存变量,并且这个变量会更新的话,就换一种方案吧!比如使用redis做缓存。我们这个项目讨论的是单进程、多pod部署的项目本地内存更新的问题。 ** ## ✅ etcd watcher 使用的模块: `etcd3`: ```shell pip3 install etcd3 ``` **使用etcd方案需要注意的点:** - 首先,需要开子线程去监听etcd对应key的变更,否则会阻塞住后面的app.run() - 因为子线程中需要查数据库获取全量的数据,所以需要将flask的`应用上下文app`当成参数传入子线程的`start_etcd_watch_thread` 方法中 ## ✅ consul 利用 Consul Key + Watch 实现缓存刷新通知: - 每次更新数据库时,更新 Consul 的一个键值 `name_mapping/notify` - 所有服务节点都在 监听(watch)这个键的变化 - 一旦这个键变化,就触发回调,刷新本地缓存 可以在consul的后台看到`name_mapping/notify`对应的数据 ```shell pip3 install python-consul ``` ## ✅ nacos的配置监听 Nacos支持配置的监听回调机制,可以用作轻量级的广播通知机制: - 服务 A 更新数据库后,通过 Nacos 修改一段配置(比如时间戳、UUID等无语义值) - 服务 B 监听这段配置,检测到变化后就自动调用 refresh_name_cache(),刷新内存 ``` ┌──────────────────────┐ │ Service A │ │ 更新数据库数据 │ │ nacos_client.publish │ └──────────────────────┘ │ ▼ ┌──────────────┐ │ Nacos KV │ │ dataId: name_mapping_update └──────────────┘ ▲ ┌──────────────────────┐ │ Service B │ │ 监听配置变化 │ │ -> refresh_name_cache() │ └──────────────────────┘ ``` 安装三方模块(但是需要注意下,这个三方模块是社区维护的,不是官方的,笔者自己试了下它内部的那个监听方法不管用,我是自己手动实现了一个“轮寻”): ```shell pip3 install nacos-sdk-python ``` **❗️另外笔者在实际中使用这个nacos的Python SDK的时候发现,publish_config方法返回了True但是实际上并没有修改对应DateId的数据,我把我的配置从public命名空间换成另外一个自定义的命名空间就好了!** 网上找到一个相关的issue: [publish_config 返回True,nacos中没有对应的配置,通过get_config获取,返回None #49](https://github.com/nacos-group/nacos-sdk-python/issues/49) ## ✅ Redis的Pub/sub [Redis Pub/sub](https://redis.io/docs/latest/develop/pubsub/) ## ✅ Redis Streams [Redis Streams](https://redis.io/docs/latest/develop/data-types/streams/) **使用Redis Streams 会将消息持久化到设定的key中** ## ✅ Redis Pub/Sub vs Redis Stream 对比 | 特性 | Pub/Sub | Redis Stream | |----------|------------|----------------------| | 是否持久化 | ❌ 不持久化消息 | ✅ 持久化 | | 是否支持消费确认 | ❌ 不支持 | ✅ 支持(ACK) | | 是否支持消息追溯 | ❌ 无法获取历史消息 | ✅ 可以读取历史消息 | | 是否支持消费者组 | ❌ 不支持 | ✅ 支持(Consumer Group) | | 适合 | 简单通知、广播 | 有消费确认要求、保证可靠性 | > **总结:** Redis Stream 更适合你现在这个“通知更新缓存”的场景,尤其是**多服务节点部署时,确保每个节点都收到并处理了消息。**