Redis 实现高性能计数器

在高并发的互联网应用中,计数器作为一种基础功能,经常出现在如点赞、浏览量、投票等场景中。如何设计一个高效且可靠的计数器系统,是每个架构师和开发者需要关注的核心问题。传统的基于数据库的计数器在高并发情况下容易成为性能瓶颈,而使用 Redis 作为缓存解决方案,能够极大地提升系统的响应速度和处理能力。

本文将详细介绍如何使用 Spring Boot 和 Redis 实现一个高效、可靠的计数器,适用于各种高并发场景。我们会讲解如何在 Spring Boot 项目中集成 Redis,如何设计高效的计数器机制,如何处理并发问题,以及如何保证计数器数据的准确性与可靠性。

一、为什么选择 Redis?

Redis 是一个开源的内存数据结构存储系统,它不仅支持字符串、哈希、列表、集合等常见数据类型,还提供了强大的原子操作功能和高并发性能。Redis 在处理计数器时特别有优势,原因如下:

a. 高性能:Redis 基于内存操作,速度非常快。它的操作是原子性的,保证了高并发场景下的数据一致性。

b. 简单易用:Redis 提供了丰富的命令和客户端支持,能够轻松实现计数器的加减操作。

c. 持久化与高可用:虽然 Redis 是内存数据库,但它提供了持久化机制,可以将数据定期存储到硬盘中。此外,Redis 还支持主从复制、哨兵机制等,保证高可用和数据可靠性。

二、项目准备

2.1 环境准备

在本教程中,我们将使用以下技术栈:

  • Spring Boot:作为应用的框架,简化开发。
  • Redis:作为计数器的存储,提供高并发访问支持。
  • Lettuce 或 Jedis:作为 Spring Boot 和 Redis 之间的客户端库。
  • Maven:作为构建工具。

你可以通过以下命令安装 Redis:

sudo apt-get update sudo apt-get install redis-server

启动 Redis 服务:

sudo service redis-server start

2.2 创建 Spring Boot 项目

使用 Spring Initializr 创建一个新的 Spring Boot 项目,选择如下依赖:

  • Spring Web
  • Spring Data Redis
  • Lombok(用于简化代码)
  • Spring Boot DevTools(开发工具)

你可以通过访问 Spring Initializr 来创建项目,并导入到你喜欢的开发工具中。

三、引入 Redis 依赖

pom.xml 文件中,添加 Redis 相关的依赖。我们这里使用 Lettuce 作为 Redis 客户端。

<dependencies> <!-- Spring Boot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Data Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- Lettuce Redis Client --> <dependency> <groupId>io.lettuce.core</groupId> <artifactId>lettuce-core</artifactId> </dependency> <!-- Lombok (Optional, for code reduction) --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> </dependencies>

2.3 配置 Redis

application.ymlapplication.properties 中配置 Redis 连接信息:

spring: redis: host: localhost port: 6379 password: "" database: 0 jedis: pool: max-active: 10 max-idle: 5 min-idle: 1

2.4 创建 Redis 配置类

为了更好地管理 Redis 连接池,我们可以创建一个配置类来初始化 RedisTemplate。

 

javaCopy Code

package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.connection.RedisConnectionFactory; @Configuration public class RedisConfig { @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, String> template = new RedisTemplate<>(); template.setConnectionFactory(factory); return template; } }

四、实现计数器功能

4.1 计数器业务逻辑

计数器的实现可以非常简单:通过 Redis 的 INCR 命令来实现计数器的递增。INCR 命令是原子操作,能够保证高并发时的正确性。

下面是一个简单的计数器服务类:

package com.example.demo.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @Service public class CounterService { @Autowired private RedisTemplate<String, String> redisTemplate; private static final String COUNTER_KEY = "counter"; public Long incrementCounter() { return redisTemplate.opsForValue().increment(COUNTER_KEY, 1); } public Long getCurrentValue() { String value = redisTemplate.opsForValue().get(COUNTER_KEY); return value != null ? Long.parseLong(value) : 0; } }

计数器的主要操作:
  • incrementCounter:每次调用该方法会将计数器加1。
  • getCurrentValue:获取当前计数器的值。

4.2 设计接口

接下来,我们需要创建 RESTful 接口,供外部调用增减计数器的功能。我们使用 @RestController 来创建控制器:

package com.example.demo.controller; import com.example.demo.service.CounterService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class CounterController { @Autowired private CounterService counterService; @GetMapping("/increment") public Long increment() { return counterService.incrementCounter(); } @GetMapping("/current") public Long getCurrentCounter() { return counterService.getCurrentValue(); } }

在这个控制器中,我们提供了两个接口:

  • /increment:递增计数器。
  • /current:获取当前计数器值。

4.3 测试计数器

启动 Spring Boot 应用,并通过浏览器或 Postman 访问以下接口进行测试:

  • 访问 http://localhost:8080/increment,可以看到计数器的值不断递增。
  • 访问 http://localhost:8080/current,可以查看当前计数器的值。

五、处理高并发与分布式环境

5.1 锁机制保证准确性

虽然 Redis 的 INCR 操作是原子性的,但在某些高并发场景下(尤其是在分布式环境中),我们可能会面临超高并发情况下的竞态条件问题。因此,使用 Redis 分布式锁来保证操作的原子性是非常重要的。

我们可以使用 Redis 的 SETNX 命令来实现一个分布式锁,确保只有一个线程在同一时刻访问计数器。

public boolean lock(String key, String value) { return redisTemplate.opsForValue().setIfAbsent(key, value, 10, TimeUnit.SECONDS); } public void unlock(String key) { redisTemplate.delete(key); }

这样,我们可以在 incrementCounter 操作之前加锁,操作完成后再释放锁。确保并发情况下,计数器的值能够正确递增。

5.2 Redis 的过期时间设置

为了防止锁泄漏,我们可以为锁设置过期时间,在过期后自动释放锁。

public boolean lock(String key, String value) { return redisTemplate.opsForValue().setIfAbsent(key, value, 10, TimeUnit.SECONDS); }

六、总结与优化

通过本文的介绍,我们已经实现了一个基于 Redis 的高并发计数器系统。在设计过程中,我们充分利用了 Redis 的原子操作特性,确保了计数器的高效与可靠。

a. 性能优化:Redis 内存存储和原子操作使得我们的计数器在高并发场景下依然能够保持低延迟和高吞吐量。

b. 可扩展性:如果需要在分布式环境中部署,可以通过 Redis 集群模式来扩展系统,保证高可用性和分布式一致性。

c. 锁机制:在需要保证操作准确性的场景下,使用 Redis 的分布式锁是非常有效的解决方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/475782.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot基于数据挖掘的广州招聘可视化分析系统

摘 要 基于数据挖掘的广州招聘可视化分析系统是一个创新的在线平台&#xff0c;旨在通过深入分析大数据来优化和改善广州地区的招聘流程。系统利用Java语言、MySQL数据库&#xff0c;结合目前流行的 B/S架构&#xff0c;将广州招聘可视化分析管理的各个方面都集中到数据库中&a…

VIM的下载使用与基本指令【入门级别操作】

VIM——超级文本编辑器 在当今时代&#xff0c;功能极其复杂的代码编辑器和集成开发环境&#xff08;IDE&#xff09;有很多。 但如果只想要一个超轻量级的代码编辑器&#xff0c;用于 Unix、C 或其他语言/系统&#xff0c;而不需要那些华而不实的功能&#xff0c;该怎么办呢&…

心情追忆-首页“毒“鸡汤AI自动化

之前&#xff0c;我独自一人开发了一个名为“心情追忆”的小程序&#xff0c;旨在帮助用户记录日常的心情变化及重要时刻。我从项目的构思、设计、前端&#xff08;小程序&#xff09;开发、后端搭建到最终部署。经过一个月的努力&#xff0c;通过群聊分享等方式&#xff0c;用…

开源代码统计工具cloc的简单使用

一.背景 公司之前开发了个小系统&#xff0c;要去申请著作权&#xff0c;需要填写代码数量。应该怎么统计呢&#xff1f;搜索了一下&#xff0c;还是用开源工具cloc吧&#xff01;我的操作系统是windows&#xff0c;代码主要是java项目和vue项目。 二.到哪里找 可以去官方下载…

基于单片机的条形码识别结算设计

本设计基于单片机的条形码辨识与结算系统。该系统主要用于超市、商场等场所的商品结算&#xff0c;实现了在超市内对不同种类商品进行自动识别及自动分类结算的功能。该系统由STM32F103C8T6单片机、摄像头、显示、蜂鸣器报警、按键和电源等多个模块构成。该系统可实现商品自动识…

进程间通信的信号艺术:机制、技术与实战应用深度剖析

目录 1 什么是信号 2 为什么要有信号 3 对于信号的反应 3.1 默认行为 3.2 signal()函数 -- 自定义行为对信号做出反应 3.3 对信号进行忽略 4 信号的产生的类型 4.1 kill命令 4.2 键盘输入产生信号 4.3 系统调用接口 4.3.1 kill() 4.3.2 raise() 函数 4.4 软件条件 …

美畅物联丨JT/T 808 终端设备如何加入畅联云平台

在道路运输行业中&#xff0c;JT/T 808终端设备的应用正变得越来越广泛&#xff0c;把该设备接入畅联云平台&#xff0c;能够达成更高效的车辆管理与监控功能。今天&#xff0c;我们就来探讨一下JT/T 808终端设备接入畅联云平台的步骤与要点。 一、了解畅联云平台接入要求 首先…

【微服务】SpringBoot 整合ELK使用详解

目录 一、前言 二、为什么需要ELK 三、ELK介绍 3.1 什么是elk 3.2 elk工作原理 四、ELK搭建 4.1 搭建es环境 4.1.1 获取es镜像 4.1.2 启动es容器 4.1.3 配置es参数 4.1.4 重启es容器并访问 4.2 搭建kibana 4.2.1 拉取kibana镜像 4.2.2 启动kibana容器 4.2.3 修改…

jenkins的安装(War包安装)

‌Jenkins是一个开源的持续集成工具&#xff0c;基于Java开发&#xff0c;主要用于监控持续的软件版本发布和测试项目。‌ 它提供了一个开放易用的平台&#xff0c;使软件项目能够实现持续集成。Jenkins的功能包括持续的软件版本发布和测试项目&#xff0c;以及监控外部调用执行…

低速接口项目之串口Uart开发(一)——串口UART

本节目录 一、串口UART 二、串口协议 三、串口硬件 四、往期文章链接本节内容 一、串口UART 串口UART,通用异步收发传输器&#xff08;Universal Asynchronnous Receiver / Transmitter&#xff09;,一种异步收发传输器&#xff0c;全双工传输。数据发送时&#xff0c;将并行…

WEB攻防-通用漏洞SQL注入Tamper脚本Base64Jsonmd5等

知识点&#xff1a; 1、数据表现格式类型注入&#xff1b; 2、字符转义绕过-宽字节注入&#xff1b; 3、数字&字符&搜索&编码&加密等&#xff1b; 参考资料&#xff1a; https://www.cnblogs.com/bmjoker/p/9326258.html SQL注入课程体系&#xff1a; 1、…

[Unity]TileMap开发,TileMap地图缝隙问题

环境&#xff1a; windows11 unity 2021.3.14f1c1 tilemap使用的图是美术已经拼接到一起的整图&#xff0c;块与块之间没有留缝隙 问题&#xff1a; TileMap地图直接在Unity中使用时&#xff0c;格子边缘会出现缝隙&#xff0c;移动或缩放地图时较明显。 解决方案&#x…

第75期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

Vue 专属状态管理库Pinia的使用与实践

目录 前言1. 什么是 Pinia&#xff1f;2. Pinia 的安装与基本配置2.1 安装 Pinia2.2 在 Vue 应用中配置 Pinia 3. 使用 Pinia 创建和管理状态3.1 定义一个简单的 Store3.2 在组件中使用 Store 4. Pinia 的高级功能4.1 使用 Getter 简化数据处理4.2 支持异步操作4.3 在服务端渲染…

Argo workflow 拉取git 并使用pvc共享文件

文章目录 拉取 Git 仓库并读取文件使用 Kubernetes Persistent Volumes&#xff08;通过 volumeClaimTemplates&#xff09;以及任务之间如何共享数据 拉取 Git 仓库并读取文件 在 Argo Workflows 中&#xff0c;如果你想要一个任务拉取 Git 仓库中的文件&#xff0c;另一个任…

【Android】线程池的解析

引言 在Android当中根据用途分为主线程与子线程&#xff0c;主线程当中主要处理与界面相关的操作&#xff0c;子线程主要进行耗时操作。除了Thread本身以外&#xff0c;在Android当中还有很多扮演者线程的角色&#xff0c;比如AsyncTask&#xff08; 底层为线程池&#xff0c;…

【Linux网络编程】简单的UDP套接字

目录 一&#xff0c;socket编程的相关说明 1-1&#xff0c;sockaddr结构体 1-2&#xff0c;Socket API 二&#xff0c;基于Udp协议的简单通信 三&#xff0c;UDP套接字的应用 3-1&#xff0c;实现英译汉字典 一&#xff0c;socket编程的相关说明 Socket编程是一种网络通信…

【java基础】微服务篇

参考黑马八股视频。 目录 Spring Cloud 5大组件 注册中心 负载均衡 限流 CAP和BASE 分布式事务解决方案 分布式服务的接口幂等性 分布式任务调度 Spring Cloud 5大组件 注册中心 Eureka的作用 健康监控 负载均衡 限流 漏桶固定速率&#xff0c;令牌桶不限速 CAP和BA…

java八股-SpringCloud微服务-Eureka理论

文章目录 SpringCloud架构Eureka流程Nacos和Eureka的区别是&#xff1f;CAP定理Ribbon负载均衡策略自定义负载均衡策略如何实现&#xff1f;本章小结 SpringCloud架构 Eureka流程 服务提供者向Eureka注册服务信息服务消费者向注册中心拉取服务信息服务消费者使用负载均衡算法挑…

thinkphp6安装php-mqtt/client,并实现实时消息收发写入日志

thinkphp6安装php-mqtt/client,并实现实时消息收发写入日志 系统&#xff1a;centos7 第一步&#xff1a;宝塔面板安装php环境8.0&#xff1b; 第二步&#xff1a;宝塔自带安装composer; 第三步&#xff1a;下载thinkphp6 create project composer require topthink/think…