高可用、高并发电商系统的大致架构以及关键部分示例代码
一、整体架构概述
- 前端层:包括电商网站的页面展示、移动端 APP 等,通过 API 网关与后端微服务进行交互,负责向用户呈现商品信息、处理用户操作等。
- API 网关层(Spring Cloud Gateway):作为所有请求的入口,负责路由转发、鉴权、限流等功能,将不同的请求分发到对应的后端微服务上,实现统一的接口管理与安全控制。
- 微服务层(Spring Cloud + Dubbo):
- 商品服务:负责商品信息的管理,包括商品的添加、删除、查询、修改等操作,与数据库交互获取商品数据,并可利用 Redis 进行缓存加速热门商品的查询。
- 订单服务:处理订单的创建、支付、查询、取消等流程,可能会涉及到分布式事务的处理(可结合 Seata 等框架来实现),同时与消息队列(如 RabbitMQ 或 Kafka)交互,用于异步处理订单相关业务,比如通知库存扣减等。
- 用户服务:管理用户的注册、登录、信息修改、权限验证等功能,也可使用 Redis 缓存用户登录态等信息来提升性能。
- 库存服务:维护商品的库存数量,接收来自订单服务等的库存扣减请求,并更新库存信息,借助分布式锁(基于 Redis 等实现)来保证库存扣减的准确性。
- 搜索服务(ElasticSearch):提供商品的全文搜索功能,会定期从数据库中将商品数据同步到 ElasticSearch 索引中,方便用户快速搜索到想要的商品。
- 服务治理与注册中心(Zookeeper):用于服务的注册与发现,各个微服务启动时将自己的信息注册到 Zookeeper 上,方便其他服务在调用时进行查找和负载均衡,同时配合 Dubbo 实现分布式服务的治理,比如动态配置管理、服务降级等。
- 消息队列层(RabbitMQ 或 Kafka):用于解耦微服务之间的依赖关系,实现异步通信,例如订单支付成功后发送消息通知库存服务扣减库存、通知物流服务发货等场景,同时可以处理高并发下的流量削峰,保证系统的稳定性。
- 分布式缓存层(Redis):缓存常用数据,如热门商品信息、用户登录态、菜单数据等,减轻数据库压力,提升系统响应速度,并且可用于实现分布式锁等功能保证并发情况下数据的一致性。
- 分布式搜索层(ElasticSearch):为商品等数据提供强大的全文搜索功能,通过合理的索引构建与查询优化,满足用户快速查找商品的需求。
- 数据存储层:使用关系数据库(如 MySQL)存储核心业务数据,如商品信息、用户信息、订单信息等,同时结合分库分表等策略应对大数据量和高并发读写的情况。
二、关键技术示例代码
1. Spring Cloud 微服务基础配置(以服务注册发现为例,使用 Eureka,实际中可用 Zookeeper 替代,配置类似)
在 pom.xml
中引入相关依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在启动类上添加注解开启服务注册发现功能:
import org.springframework.boot.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ProductServiceApplication {
public static void main(String[] args) {
SpringBootApplication.run(ProductServiceApplication.class, args);
}
}
配置 application.yml
文件,指定服务注册中心地址等信息(以下以 Eureka 为例,Zookeeper 配置对应修改):
spring:
application:
name: product-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
2. Dubbo 服务配置与使用(以商品服务接口和实现为例)
定义商品服务接口:
public interface ProductService {
Product getProductById(Long productId);
List<Product> listProducts();
// 其他商品相关操作方法
}
实现类:
import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
@Component
@Service(version = "1.0.0")
public class ProductServiceImpl implements ProductService {
@Override
public Product getProductById(Long productId) {
// 从数据库或缓存等获取商品信息的逻辑
return productDao.findById(productId);
}
@Override
public List<Product> listProducts() {
// 查询商品列表逻辑
return productDao.findAll();
}
}
在消费者端(比如订单服务调用商品服务),注入商品服务接口进行远程调用:
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
@Service
public class OrderServiceImpl implements OrderService {
@Reference(version = "1.0.0")
private ProductService productService;
@Override
public void createOrder(Order order) {
Product product = productService.getProductById(order.getProductId());
// 后续创建订单的其他逻辑
}
}
3. Zookeeper 作为服务注册中心配置(结合 Dubbo 使用)
在 dubbo.properties
(或 application.yml
等配置文件中配置,以 dubbo.properties
为例):
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.registry.protocol=zookeeper
4. RabbitMQ 消息队列使用示例(发送消息)
引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置文件 application.yml
:
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
在代码中发送消息(以订单支付成功后发送消息通知库存服务为例):
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class OrderMessageSender {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendStockDeductionMessage(Order order) {
rabbitTemplate.convertAndSend("stock.deduction.exchange", "stock.deduction.routing.key", order);
}
}
接收消息(库存服务端):
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class StockMessageReceiver {
@RabbitListener(queues = "stock.deduction.queue")
public void receiveStockDeductionMessage(Order order) {
// 处理库存扣减逻辑
stockService.deductionStock(order.getProductId(), order.getQuantity());
}
}
5. Redis 缓存使用示例(缓存商品信息)
引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件指定 Redis 连接信息(application.yml
):
spring:
redis:
host: localhost
port: 6379
在商品服务中使用 Redis 缓存查询逻辑(以查询商品为例):
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private RedisTemplate<String, Product> redisTemplate;
@Autowired
private ProductDao productDao;
@Override
public Product getProductById(Long productId) {
String cacheKey = "product:" + productId;
Product product = redisTemplate.opsForValue().get(cacheKey);
if (product == null) {
product = productDao.findById(productId);
if (product!= null) {
redisTemplate.opsForValue().set(cacheKey, product);
}
}
return product;
}
}
6. ElasticSearch 使用示例(商品搜索功能)
引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
配置 application.yml
指定 ElasticSearch 连接信息:
spring:
data:
elasticsearch:
client:
reactive:
endpoints: localhost:9200
定义商品搜索的 Repository 接口:
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductSearchRepository extends ElasticsearchRepository<Product, Long> {
List<Product> findByNameContaining(String keyword);
}
在搜索服务中调用该 Repository 进行搜索:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SearchServiceImpl implements SearchService {
@Autowired
private ProductSearchRepository productSearchRepository;
@Override
public List<Product> searchProducts(String keyword) {
return productSearchRepository.findByNameContaining(keyword);
}
}
7. Docker 部署微服务示例(以商品服务为例,编写 Dockerfile)
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/product-service.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
构建镜像并运行容器(在包含 Dockerfile 的目录下执行命令):
docker build -t product-service-image.
docker run -d -p 8080:8080 product-service-image