当前位置: 首页 > news >正文

【设计题】如何涉及一个高并发的计数器

设计高并发计数器需解决性能瓶颈(高并发写入)、数据一致性(分布式场景下计数准确)、可扩展性(支持流量增长)三大核心问题。业界成熟方案基于 “分层计数、异步聚合、持久化兜底” 思路,结合本地缓存、Redis、数据库等组件实现,以下是具体设计:

一、核心设计原则

  1. 分层计数:本地缓存(线程级 / 进程级)承担高频写入,降低远程存储压力。
  2. 异步聚合:本地计数定期批量同步到全局存储(如 Redis),减少网络开销。
  3. 持久化兜底:全局计数定时同步到数据库,防止数据丢失。
  4. 水平扩展:支持多实例部署,通过分片避免单点瓶颈。

二、业界成熟方案实现

1. 单机高并发计数器(基于 LongAdder

Java 中的 LongAdder 是单机高并发计数的首选,其通过 “分段累加”(多个单元格分摊计数)避免 CAS 竞争,性能远超 AtomicLong(适合百万级 QPS 场景)。

实现代码

import java.util.concurrent.LongAdder;public class LocalCounter {private final LongAdder counter = new LongAdder();// 计数+1public void increment() {counter.increment();}// 计数+npublic void add(long n) {counter.add(n);}// 获取当前计数public long get() {return counter.sum();}// 重置计数(可选)public void reset() {counter.reset();}
}

适用场景:单机服务的高频计数(如接口访问量、瞬时点击量),优势是无锁、高性能,缺点是不支持分布式。

2. 分布式高并发计数器(本地 + Redis 分层设计)

分布式场景下,需结合本地计数与 Redis 实现全局计数,平衡性能与一致性。

(1)核心架构

plaintext

用户请求 → 本地计数器(LongAdder)→ 定时同步(每秒)→ Redis(INCRBY)→ 定时持久化 → 数据库
(2)实现代码
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;public class DistributedCounter {private final String redisKey; // Redis 键(如 "counter:page_view")private final StringRedisTemplate redisTemplate;private final LongAdder localCounter = new LongAdder(); // 本地计数器private final ScheduledExecutorService syncExecutor = Executors.newSingleThreadScheduledExecutor();public DistributedCounter(String redisKey, StringRedisTemplate redisTemplate) {this.redisKey = redisKey;this.redisTemplate = redisTemplate;// 启动定时任务:每秒将本地计数同步到Redisthis.syncExecutor.scheduleAtFixedRate(this::syncToRedis, 1, 1, TimeUnit.SECONDS);}// 计数+1public void increment() {localCounter.increment();}// 同步本地计数到Redis(批量累加)private void syncToRedis() {long count = localCounter.sumThenReset(); // 获取并重置本地计数if (count > 0) {redisTemplate.opsForValue().increment(redisKey, count); // Redis原子累加}}// 获取全局计数(Redis当前值 + 本地未同步值)public long getTotal() {Long redisCount = redisTemplate.opsForValue().increment(redisKey, 0); // 不修改值,仅查询return (redisCount == null ? 0 : redisCount) + localCounter.sum();}// 关闭资源public void close() {syncExecutor.shutdown();syncToRedis(); // 最后一次同步,避免数据丢失}
}
(3)关键设计
  • 本地缓冲LongAdder 处理高频写入(单机支持每秒千万级操作),避免直接操作 Redis 导致的网络瓶颈。
  • 批量同步:每秒一次批量同步到 Redis(INCRBY 原子命令),减少网络请求次数(从每秒百万次降至每秒一次)。
  • 实时性权衡:牺牲 1 秒内的实时性(本地计数未同步到 Redis),换取极高性能,适合允许短暂延迟的场景(如访问量统计)。
3. 超高并发场景(分片 + 预聚合)

当 QPS 超过单 Redis 实例承载能力(如每秒 100 万 +),需对计数器分片,分散压力。

(1)分片策略
  • 按 key 哈希分片:将计数器 key 按哈希值分散到多个 Redis 实例(如 counter:page_view:{shardId}shardId = hash(key) % 10)。
  • 实现代码(分片计数):
    public class ShardedCounter {private final List<DistributedCounter> shardCounters; // 分片计数器列表private final int shardCount; // 分片数量(如10)public ShardedCounter(String baseKey, StringRedisTemplate redisTemplate, int shardCount) {this.shardCount = shardCount;this.shardCounters = new ArrayList<>(shardCount);// 初始化每个分片的计数器for (int i = 0; i < shardCount; i++) {String shardKey = baseKey + ":" + i;shardCounters.add(new DistributedCounter(shardKey, redisTemplate));}}// 计数+1:根据key哈希选择分片public void increment(String key) {int shardId = Math.abs(key.hashCode() % shardCount);shardCounters.get(shardId).increment();}// 汇总所有分片的计数public long getTotal() {long total = 0;for (DistributedCounter counter : shardCounters) {total += counter.getTotal();}return total;}
    }
    
(2)优势
  • 分散 Redis 写入压力:10 个分片可将单实例压力降低 10 倍。
  • 支持水平扩展:增加分片数量或 Redis 实例即可提升承载能力。
4. 持久化与高可用
  • 定时持久化到数据库:通过定时任务(如每 5 分钟)将 Redis 计数同步到数据库(如 MySQL),避免 Redis 宕机导致数据丢失。
    @Scheduled(cron = "0 0/5 * * * ?") // 每5分钟执行
    public void persistToDb() {String redisKey = "counter:page_view";Long count = redisTemplate.opsForValue().get(redisKey);if (count != null) {counterMapper.updateCount(redisKey, count); // 写入数据库}
    }
    
  • Redis 高可用:采用 Redis 集群(主从 + 哨兵),确保 Redis 节点故障时自动切换,不影响计数服务。

三、业界参考案例

  1. Twitter 计数器:基于本地计数 + 异步聚合到 Redis,支持每秒千万级推文点赞计数。
  2. 阿里云 SLS 计数器:通过分片 + 预聚合实现日志访问量实时统计,支持每秒亿级操作。
  3. 开源方案
    • Redisson RLongAdder:分布式版本的 LongAdder,自动分片,适合 Java 生态。
    • InfluxDB/Prometheus:时序数据库,内置高并发计数能力,适合监控指标场景。

四、选型建议

场景方案优势局限
单机高频计数LongAdder无锁、高性能(千万级 QPS)不支持分布式
分布式一般并发本地 LongAdder + Redis平衡性能与一致性(十万级 QPS)1 秒级延迟
分布式超高并发分片 + 本地 + Redis支持百万级 QPS,可水平扩展实现复杂,汇总计数有开销
监控 / 时序数据计数Prometheus/InfluxDB原生支持高并发时序计数,带聚合分析依赖外部组件,适合特定场景

核心总结

高并发计数器的核心是 **“分层缓冲” 与 “异步聚合”**:

  • 用本地计数(LongAdder)吸收高频写入,减少远程交互;
  • 用 Redis 实现分布式全局计数,支持高可用;
  • 用分片扩展承载能力,用定时持久化保证数据安全。根据业务的并发量、实时性要求和分布式需求选择合适方案,优先复用成熟组件(如 Redisson、Prometheus)避免重复造轮子。
http://www.dtcms.com/a/575232.html

相关文章:

  • 网站开发教程 布局长域名转换短域名
  • 通过Ollama搭建本地LLM
  • 《新概念英语青少年版》单词全整理
  • 好的建筑设计网站有没有什么好看的网址
  • 8、webgl 基本概念 + 图像变换(平移 + 旋转 + 缩放)
  • 郑州建设信息网站环球网最新国际新闻
  • 租赁公司网站源码上线吧做的网站可以备案
  • 手机网站开发解决方案如何将自己做的网页做成网站
  • 在JavaScript中,将包含HTML实体字符的字符串转换为普通字符
  • 网站 建设理由网页设计教程详细步骤ppt
  • 深入理解 Python 的“左闭右开”设计哲学
  • 公司网站建设维保协议wordpress文本块表格
  • hanchengkeji杭州网站建设做网站后台维护的岗位叫什么
  • 企业网站建设最新技术diy小程序开发平台
  • 网站建设功能报价单网站建设资格预审公告
  • wordpress添加动漫人物深圳网站优化
  • 日均亿级数据的实时分析:Doris如何接过Spark的接力棒?
  • 网站建设微信官网开发外贸网站做的作用是什么
  • 东莞网络公司哪个网站好wordpress博客怎么搜索
  • 怎么给网站创建二维码国内知名企业网站
  • 网站建设的公司邢台市信都区
  • 功能型网站开发者模式有什么危害
  • 手机网站开发 1433端口错误sem优化系统
  • 关键词解释:Focal Loss解决类别极度不平衡问题而设计的损失函数
  • Kubernetes-入门概念
  • 竞拍网站建设电子商务网站建设概括
  • 用卫生纸做的礼物街网站模板网站自助建站
  • 电影模板哪个网站好2345浏览器导航页
  • 扬州市市政建设处网站上海网络维护有哪些公司
  • 农村网站建设调查报告兰州市城乡建设局网站官网