面试题答案
一键面试缓存分层架构
- 前端缓存:
- 用途:主要缓存静态资源,如交易系统的页面样式文件、脚本文件等。这些资源变化频率低,适合长期缓存。对于用户端展示的一些非实时关键信息,如常见问题解答等也可缓存于此。
- 优点:减少后端服务器的负载,加快用户页面加载速度。
- 实现技术:可使用浏览器缓存机制,设置合适的缓存头(如
Cache - Control
等)。
- 分布式缓存(如 Redis):
- 用途:
- 高频读数据:缓存交易记录摘要、近期活跃用户的账户信息等读写频率高的数据。例如,最近一小时内频繁交易用户的账户余额、交易次数等信息。
- 短期行情数据:对于市场行情数据,缓存近期短时间内(如1 - 5分钟)的行情数据,以满足大部分实时性要求不太高的查询需求。
- 优点:具备高并发读写能力,可通过集群部署提高可用性和扩展性。
- 实现技术:采用 Redis 集群,利用其丰富的数据结构(如哈希表存储用户账户信息,有序集合存储交易记录摘要等)。
- 用途:
- 本地缓存(如 Ehcache):
- 用途:在应用服务器本地缓存部分热数据,如当前应用实例频繁访问的特定交易类型的配置信息、常用的市场行情指标计算结果等。
- 优点:访问速度极快,减少对分布式缓存的压力,降低网络开销。
- 实现技术:使用 Ehcache 等本地缓存框架,根据应用需求配置合适的缓存大小和过期策略。
数据淘汰算法的选择与优化
- 选择:
- 分布式缓存(Redis):对于大部分缓存数据,采用
LRU(最近最少使用)
算法。因为在金融交易系统中,最近频繁访问的数据很可能在未来也会被频繁访问,符合 LRU 算法的应用场景。对于一些特殊的,如需要固定存储一段时间的行情数据,可以设置固定的过期时间而不依赖淘汰算法。 - 本地缓存(Ehcache):同样可采用
LRU
算法,也可结合LFU(最不经常使用)
算法。例如,对于一些计算结果缓存,如果在一段时间内访问频率较低,使用 LFU 算法能更合理地淘汰这些数据。
- 分布式缓存(Redis):对于大部分缓存数据,采用
- 优化:
- 分布式缓存(Redis):在 Redis 中,可以通过调整
maxmemory - samples
参数来优化 LRU 算法的近似度。较大的maxmemory - samples
值能使 LRU 算法更接近真实的 LRU 策略,但会增加计算成本。根据系统性能和内存使用情况,适当调整该参数,例如设置为 10 - 100 之间的值。 - 本地缓存(Ehcache):可对缓存数据进行分类,针对不同类型的数据设置不同的淘汰优先级。例如,对于交易配置信息等关键数据,设置较低的淘汰优先级;对于一些辅助计算结果的缓存数据,设置较高的淘汰优先级。
- 分布式缓存(Redis):在 Redis 中,可以通过调整
保证数据准确性和一致性
- 数据更新策略:
- 写后更新缓存:在数据持久化到数据库成功后,再更新缓存。例如,当一笔交易完成,先将交易记录写入数据库,成功后再更新相应的交易记录缓存、账户余额缓存等。为了保证更新的原子性,可以使用事务机制(在支持事务的数据库和缓存中)。
- 异步更新:对于一些对实时性要求不高的数据更新,可以采用异步方式。例如,使用消息队列(如 Kafka),当数据库数据更新后,发送一条消息给缓存更新服务,由该服务异步更新缓存,这样可减少对业务操作的响应时间影响。
- 缓存失效策略:
- 主动失效:当数据发生变化时,主动使相关缓存失效。例如,当用户账户信息修改后,主动删除或更新分布式缓存和本地缓存中对应的用户账户信息缓存。
- 被动失效:结合缓存数据的过期时间设置,当缓存数据过期后,下次访问时重新从数据源获取数据并更新缓存。对于时效性要求高的数据,设置较短的过期时间;对于相对稳定的数据,设置较长的过期时间。
- 一致性检查:
- 定期校验:定期(如每天凌晨低峰期)对缓存数据和数据库中的数据进行一致性检查。通过对比关键数据字段(如交易记录的金额、账户余额等),发现不一致的数据及时进行修复。可以使用专门的校验工具或编写校验脚本实现。
- 实时监控:利用分布式系统中的监控工具(如 Prometheus + Grafana),实时监控缓存读写操作的指标,如命中率、更新频率等。当发现异常指标时(如命中率突然大幅下降),及时排查是否存在数据一致性问题。