设计出有利于后期扩展成高可用高并发的java单例应用的一些建议

ops/2025/1/16 19:13:14/

将一个单例的 Java 应用程序设计成易于后期扩展为高并发高可用系统是一个重要的架构决策。以下是一些关键的设计原则和步骤,帮助你实现这一目标。

关键设计原则

  1. 模块化设计
    • 将应用分解为多个独立的服务或模块,便于单独扩展和维护。
  2. 无状态设计
    • 设计服务为无状态的,避免依赖于本地存储或会话状态。
  3. 使用分布式缓存
    • 使用 Redis 或 Memcached 等分布式缓存来减轻数据库压力。
  4. 采用微服务架构
    • 将应用拆分为多个微服务,每个服务负责特定的功能。
  5. 引入负载均衡
    • 使用 Nginx、HAProxy 等负载均衡器分配流量到多个实例。
  6. 数据库优化
    • 使用读写分离、主从复制、分片等技术提高数据库性能。
  7. 消息队列
    • 使用 RabbitMQ、Kafka 等消息队列解耦异步任务。
  8. 监控和日志管理
    • 实施全面的监控和日志管理(如 Prometheus + Grafana, ELK Stack)以便及时发现问题。
  9. 容错和恢复策略
    • 设计自动故障转移和恢复机制。

案例:设计 Java 单例应用利于后期扩展

1. 背景

假设我们有一个简单的 Java Web 应用程序,使用 Spring Boot 和 MySQL 数据库。当前架构如下:

 

2. 目标

将其设计为易于后期扩展为高并发高可用系统,架构如下:

步骤详解

1. 模块化设计

拆分功能模块:

将应用的主要功能拆分为多个模块,例如用户管理、订单处理、商品管理等。每个模块可以独立开发、测试和部署。

java

java">// UserModule.java
@Service
public class UserModule {@Autowiredprivate UserRepository userRepository;public User getUserById(Long id) {return userRepository.findById(id).orElse(null);}// Other user-related methods
}// OrderModule.java
@Service
public class OrderModule {@Autowiredprivate OrderRepository orderRepository;public Order createOrder(Order order) {return orderRepository.save(order);}// Other order-related methods
}

 

2. 无状态设计


确保服务无状态:

避免在服务中保存任何会话状态或本地数据。所有状态应存储在外部系统中,如数据库或缓存。

java

java">@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserModule userModule;@GetMapping("/{id}")public ResponseEntity<User> getUser(@PathVariable Long id) {User user = userModule.getUserById(id);if (user == null) {return ResponseEntity.notFound().build();}return ResponseEntity.ok(user);}// Other endpoints
}
3. 使用分布式缓存

引入 Redis 缓存:

pom.xml 中添加 Redis 依赖:

xml

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置 Redis 连接:

spring.redis.host=localhost
spring.redis.port=6379

使用 Redis 进行缓存:

java

java">@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Autowiredprivate StringRedisTemplate redisTemplate;public User getUserById(Long id) {String cacheKey = "user:" + id;ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();String cachedUser = opsForValue.get(cacheKey);if (cachedUser != null) {return new ObjectMapper().readValue(cachedUser, User.class);}User user = userRepository.findById(id).orElse(null);if (user != null) {opsForValue.set(cacheKey, new ObjectMapper().writeValueAsString(user));}return user;}// Other methods
}
4. 采用微服务架构

拆分微服务:

将应用拆分为多个微服务,每个微服务负责特定的功能。例如:

  • 用户服务 (user-service)
  • 订单服务 (order-service)
  • 商品服务 (product-service)

每个微服务都可以独立部署和扩展。

5. 引入负载均衡

配置 Nginx 负载均衡:

安装 Nginx:

bash

sudo apt update
sudo apt install nginx -y

编辑 Nginx 配置文件 /etc/nginx/sites-available/default

nginx

upstream app_servers {server user-service:8080;server order-service:8080;server product-service:8080;
}server {listen 80;location / {proxy_pass http://app_servers;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}
}

重启 Nginx:

bash

sudo systemctl restart nginx

6. 数据库优化

设置 MySQL 主从复制:

  1. 主服务器配置 (my.cnf)

ini

[mysqld]
server-id=1
log-bin=mysql-bin
binlog-do-db=mydatabase

2.从服务器配置 (my.cnf)

ini

[mysqld]
server-id=2
relay-log=mysql-relay-bin
log-slave-updates=1
read-only=1
replicate-do-db=mydatabase

3.在主服务器上创建复制用户

sql

CREATE USER 'replicator'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%';
FLUSH PRIVILEGES;

4.获取主服务器的状态

sql

SHOW MASTER STATUS;

5.在从服务器上配置主服务器信息

CHANGE MASTER TO
MASTER_HOST='master_ip',
MASTER_USER='replicator',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=107;
START SLAVE;
7. 消息队列

引入 RabbitMQ:

安装 RabbitMQ:

bash

sudo apt-get install rabbitmq-server -y
sudo systemctl start rabbitmq-server
sudo systemctl enable rabbitmq-server

在 Spring Boot 应用中引入 RabbitMQ 依赖并在 pom.xml 中添加:

xml

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

配置 RabbitMQ 连接:

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

定义生产者和消费者:

java

java">@Configuration
public class RabbitConfig {@Beanpublic Queue queue() {return new Queue("myQueue");}@Beanpublic TopicExchange exchange() {return new TopicExchange("myExchange");}@Beanpublic Binding binding(Queue queue, TopicExchange exchange) {return BindingBuilder.bind(queue).to(exchange).with("foo.bar.#");}@Beanpublic MessageConverter jsonMessageConverter() {return new Jackson2JsonMessageConverter();}
}

生产者代码:

java

java">@Component
public class Sender {@Autowiredprivate RabbitTemplate template;@Value("${rabbitmq.exchange.name}")private String exchangeName;public void send(MyObject object) {this.template.convertAndSend(this.exchangeName, "foo.bar.baz", object);}
}

消费者代码:

java

java">@Component
public class Receiver {@RabbitListener(queues = "${rabbitmq.queue.name}")public void receiveMessage(MyObject object) {System.out.println("Received message: " + object);}
}
8. 监控和日志管理

安装和配置 Prometheus + Grafana:

  1. 安装 Prometheus:

bash

wget https://github.com/prometheus/prometheus/releases/download/v2.30.3/prometheus-2.30.3.linux-amd64.tar.gz
tar xvfz prometheus-2.30.3.linux-amd64.tar.gz
cd prometheus-2.30.3.linux-amd64/

编辑 prometheus.yml 文件:

yaml

global:scrape_interval: 15sscrape_configs:- job_name: 'springboot'static_configs:- targets: ['localhost:8080']

启动 Prometheus:

bash

./prometheus --config.file=prometheus.yml

2.安装 Grafana

bash

sudo apt-get install -y software-properties-common wget
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install grafana
sudo systemctl start grafana-server
sudo systemctl enable grafana-server
  1. 访问 http://your_grafana_server:3000 并登录 Grafana(默认用户名和密码为 admin/admin),然后添加 Prometheus 数据源并导入合适的仪表盘模板。

9. 容错和恢复策略

使用 Kubernetes 或 Docker Swarm:

为了实现自动故障转移和恢复,可以考虑使用容器编排工具如 Kubernetes 或 Docker Swarm。

使用 Kubernetes
  1. 安装 Kubernetes:

     

    参考 Kubernetes 官方文档 进行安装。

  2. 创建 Deployment 和 Service:

     

    创建一个 deployment.yaml 文件:

yaml

apiVersion: apps/v1
kind: Deployment
metadata:name: my-spring-boot-app
spec:replicas: 3selector:matchLabels:app: my-spring-boot-apptemplate:metadata:labels:app: my-spring-boot-appspec:containers:- name: my-spring-boot-appimage: my-spring-boot-app:latestports:- containerPort: 8080

创建一个 service.yaml 文件:

yaml

 

apiVersion: v1
kind: Service
metadata:name: my-spring-boot-service
spec:type: NodePortselector:app: my-spring-boot-appports:- protocol: TCPport: 80targetPort: 8080

应用配置

bash

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

总结

通过上述步骤,我们将一个单例的 Java 应用程序设计得更加模块化、无状态,并引入了分布式缓存、微服务架构、负载均衡、数据库优化、消息队列、监控和日志管理以及容错和恢复策略。这些设计原则和步骤有助于使应用程序更容易扩展为高并发高可用系统。

具体代码示例

1. 分离模块

UserService.java:

java

java">package com.example.demo.service;import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.ObjectMapper;@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Autowiredprivate StringRedisTemplate redisTemplate;public User getUserById(Long id) {String cacheKey = "user:" + id;ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();String cachedUser = opsForValue.get(cacheKey);if (cachedUser != null) {try {return new ObjectMapper().readValue(cachedUser, User.class);} catch (Exception e) {e.printStackTrace();}}User user = userRepository.findById(id).orElse(null);if (user != null) {try {opsForValue.set(cacheKey, new ObjectMapper().writeValueAsString(user));} catch (Exception e) {e.printStackTrace();}}return user;}// Other methods
}

UserController.java:

java

java">package com.example.demo.controller;import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public ResponseEntity<User> getUser(@PathVariable Long id) {User user = userService.getUserById(id);if (user == null) {return ResponseEntity.notFound().build();}return ResponseEntity.ok(user);}// Other endpoints
}
2. 配置 Redis

application.properties:

java">spring.redis.host=localhost
spring.redis.port=6379
3. 配置 RabbitMQ

RabbitConfig.java:

java

java">package com.example.demo.config;import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitConfig {@Beanpublic Queue queue() {return new Queue("myQueue");}@Beanpublic TopicExchange exchange() {return new TopicExchange("myExchange");}@Beanpublic Binding binding(Queue queue, TopicExchange exchange) {return BindingBuilder.bind(queue).to(exchange).with("foo.bar.#");}@Beanpublic MessageConverter jsonMessageConverter() {return new Jackson2JsonMessageConverter();}
}

Sender.java:

java

java">package com.example.demo.service;import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class Sender {@Autowiredprivate RabbitTemplate template;@Value("${rabbitmq.exchange.name}")private String exchangeName;public void send(Object object) {this.template.convertAndSend(this.exchangeName, "foo.bar.baz", object);}
}

Receiver.java:

java

java">package com.example.demo.service;import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class Receiver {@RabbitListener(queues = "${rabbitmq.queue.name}")public void receiveMessage(Object object) {System.out.println("Received message: " + object);}
}
4. 配置 Prometheus

prometheus.yml:

yaml

java">global:scrape_interval: 15sscrape_configs:- job_name: 'springboot'static_configs:- targets: ['localhost:8080']
5. 配置 Kubernetes

deployment.yaml:

yaml

java">apiVersion: apps/v1
kind: Deployment
metadata:name: my-spring-boot-app
spec:replicas: 3selector:matchLabels:app: my-spring-boot-apptemplate:metadata:labels:app: my-spring-boot-appspec:containers:- name: my-spring-boot-appimage: my-spring-boot-app:latestports:- containerPort: 8080

service.yaml:

yaml

java">apiVersion: v1
kind: Service
metadata:name: my-spring-boot-service
spec:type: NodePortselector:app: my-spring-boot-appports:- protocol: TCPport: 80targetPort: 8080

通过以上详细的设计和配置,你可以将一个单例的 Java 应用程序逐步调整为一个高并发高可用系统。


http://www.ppmy.cn/ops/150623.html

相关文章

【LeetCode: 240. 搜索二维矩阵 II + 指针 + 遍历】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

CES 2025:XEO 展出双眼8K VR头显,售价2000美元

在2025年国际消费类电子产品展览会(CES)上,XEO公司凭借其最新的VR头显设备吸引了众多目光。这款标榜双眼8K分辨率的高端VR头显不仅展示了当前虚拟现实技术的顶尖水平,同时也设定了新的行业标杆。本文将详细介绍这款产品的特点、技术和市场定位。 XEO 双眼8K VR头显:极致视…

《基于深度学习的多色光度巡天项目天文目标检测框架》论文精读

A deep learning based astronomical target detection framework for multi-colour photometry sky survey projects 摘要 多色测光巡天项目将利用广角望远镜和几种不同的滤光片获得不同颜色的天体图像。不同颜色的图像可以揭示天体的不同组成部分。我们将能够利用这些图像研…

探秘 JMeter (Interleave Controller)交错控制器:解锁性能测试的隐藏密码

嘿&#xff0c;小伙伴们&#xff01;今天咱们要把 JMeter 里超厉害的 Interleave Controller&#xff08;交错控制器&#xff09;研究个透&#xff0c;让你从新手直接进阶成高手&#xff0c;轻松拿捏各种性能测试难题&#xff01; 一、Interleave Controller 深度剖析 所属家族…

python-应用自动化操作方法集合

python-PC应用自动化操作 pywinauto&#xff1a;适合Windows系统的软件&#xff08;GUI&#xff09;&#xff0c;通过遍历窗口&#xff08;对话框&#xff09;和窗口里的UI控件进行定位操作&#xff0c;也可以控制鼠标和键盘输入等 https://geekdaxue.co/read/pywinauto-doc-zh…

SSE部署后无法连接问题解决

1. 问题现象 通过域名访问 https://api-uat.sfxs.com/sse/subscribe?tokenBearer%20eyJUxMiJ9.eyJhY2NvdW50IjoiYWRtaWZ0NvZGUiOiIwMDEiLCJyb2xidXNlcm5hbWUiOiLotoXnuqfnrqHnkIblkZgifQ.tlz9N61Y4 一直无法正常连接 2. 问题解决 nginx.conf进行配置 server {location /ss…

【再谈设计模式】模板方法模式 - 算法骨架的构建者

一、引言 在软件工程、软件开发过程中&#xff0c;我们经常会遇到一些算法或者业务逻辑具有固定的流程步骤&#xff0c;但其中个别步骤的实现可能会因具体情况而有所不同的情况。模板方法设计模式&#xff08;Template Method Design Pattern&#xff09;就为解决这类问题提供了…

汉图科技XP356DNL高速激光打印一体机综合性能测评

汉图科技XP356DNL高速激光打印一体机效率方面表现出色&#xff0c;支持A4纸型的高速打印&#xff0c;单面打印速度高达35页/分钟&#xff0c;自动双面打印速度可达32面/分钟&#xff0c;这样的速度在日常办公中能够极大地提高打印效率&#xff0c;减少等待时间&#xff0c;满足…