高并发电商架构的核心:
在于通过缓存扛住读压力、异步化解耦写操作、分布式扩展提升系统容量。
Java开发者需结合具体业务场景,
灵活运用微服务、缓存、消息队列等技术,
同时重视代码优化(如减少锁竞争、避免大事务)和 全链路监控,
确保系统在高并发下的稳定性和可扩展性。
架构设计原则
分层与模块化
- 分层架构:采用表现层(如Spring MVC)、业务层(服务拆分service)、数据访问层(ORM框架)的分层设计,降低耦合性。
- 微服务拆分:将系统拆分为用户服务、商品服务、订单服务等独立模块,每个服务可独立部署和扩展(如使用Spring Cloud或Dubbo)。
无状态化与水平扩展
通过无状态服务设计(如使用JWT Token管理会话),结合Kubernetes 或 Nginx 实现动态扩缩容,应对流量峰值。(Nginx 服务发现与负载均衡 如轮询、加权随机 分发请求)
缓存机制优化
多级缓存策略
- 本地缓存:使用Guava Cache或Caffeine缓存热点数据(如商品详情),减少Redis访问。
- 分布式缓存:Redis Cluster缓存用户会话、库存信息等高频数据,通过分片和主从架构提升吞吐量(单节点QPS可达10万+)。
- 缓存穿透/雪崩防护:采用布隆过滤器拦截无效请求,设置随机过期时间避免集中失效。
静态资源缓存
将HTML、CSS、图片等静态资源上传至CDN,减少服务器压力,提升用户访问速度。
异步处理与消息队列
削峰填谷
使用Kafka或RocketMQ异步处理订单创建、库存扣减等高并发写入操作。例如,用户下单请求先写入消息队列,再由消费者批量处理,避免数据库瞬时压力太大。
最终一致性保障
通过消息队列实现分布式事务(如TCC模式或Saga模式),确保订单、库存、积分等跨服务操作的最终一致性。
数据库优化
分库分表与读写分离
- 垂直分库:将用户库、商品库、订单库分离,减少单库压力。
- 水平分表:按用户ID或订单ID哈希分片,结合ShardingSphere实现数据路由。
- 读写分离:通过MySQL主从集群,写操作走主库,读操作走从库(如使用MyCat或ShardingSphere)。
连接池与SQL优化
- 使用HikariCP或Druid连接池,控制最大连接数,避免数据库连接耗尽。
- 通过索引优化(B+树索引、覆盖索引)和慢SQL分析工具(如Arthas)提升查询效率
并发控制与限流
乐观锁与分布式锁
- 乐观锁:在扣减库存时,通过版本号或CAS机制防止超卖(如UPDATE stock SET count=count-1 WHERE id=1001 AND count>0)。
- 分布式锁:使用Redisson实现分布式锁,控制对共享资源(如秒杀库存)的并发访问。
限流与熔断
- 限流:通过Sentinel或Resilience4j设置QPS阈值(如每秒5000次),超出阈值则拒绝请求,防止系统雪崩15。
- 熔断降级:在服务调用失败率过高时,自动熔断并返回兜底数据(如Hystrix或Sentinel)
全链路监控
- 通过Prometheus + Grafana监控服务器资源(CPU、内存)及服务状态。
- 使用SkyWalking或Zipkin追踪请求链路,定位性能瓶颈
秒杀场景设计
预扣库存与异步下单
秒杀开始前,将库存预热至Redis,用户请求时通过Lua脚本原子扣减库存,生成临时订单后异步落库。
防刷与风控
通过IP限流、验证码、用户行为分析(如使用机器学习模型)识别并拦截恶意请求
-----------------------------------------------------------
下面给出 本地缓存 实战案例 供大家参考:
package..;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
/**
* @author
* @title: CacheLocalConfig
* @description:本地缓存 贼快
* @date
*/
@Component
public class CacheLocalConfigService {
private static Logger logger = LoggerFactory.getLogger(CacheLocalConfigService.class);
/** 缓存值的最大数 */
private int maximumSize = 1000;
private Cache<String,Object> cache = null;
public CacheLocalConfigService()
{
super();
}
public int getMaximumSize()
{
return maximumSize;
}
public void setMaximumSize(int maximumSize)
{
this.maximumSize = maximumSize;
}
/**
* 初始化。
*/
@PostConstruct
public void init() {
cache = CacheBuilder.newBuilder()
//基于容量回收
//基于容量的清除:通过 CacheBuilder.maximumSize() 方法设置 Cache 的最大容量数,当缓存数量达到或接近该最大值时,将清除最近最少使用的缓存;
.maximumSize(this.maximumSize)
.initialCapacity(100)
//并发级别 设置并发级别,并发级别是指可以同时写缓存的线程数
.concurrencyLevel(5)
//设置多久没被访问(读/写)的过期时间 -- expireAfterAccess指定对象多久没有被访问后过期。
.expireAfterAccess(60*10, TimeUnit.SECONDS)
//设置过期时间(写入n秒内过期)在一定时间内没有创建/覆盖时,会移除key,下次从loading中取
.expireAfterWrite(60*10, TimeUnit.SECONDS)
//.removalListener(async)
//设置缓存的移除通知
.removalListener(new RemovalListener<String, Object>() {
@Override
public void onRemoval(RemovalNotification<String, Object> notification) {
logger.error("*********CacheLocalConfigService removalListener****"+notification.getKey() + " was removed, cause is " + notification.getCause());
}
})
.recordStats()
.build();
}
/**
*
* 获取一个缓存,如果该缓存不存在则返回一个null值
* 获取{@linkplain Object}。
* @return 返回{@code null}表示没有缓存
*/
public Object getIfPresent(String key)
{
return this.cache.getIfPresent(key);
}
/**
* 添加至缓存。
* @param key
* @param o
*/
public void put(String key,Object o)
{
this.cache.put(key, o);
}
/**
* 清除指定名称缓存。
* @param key
*/
public void invalidate(String key)
{
this.cache.invalidate(key);
}
public String stats(){
/* hitRate():缓存命中率;
averageLoadPenalty():加载新值的平均时间,单位为纳秒;
evictionCount():缓存项被回收的总数,不包括显式清除。*/
return this.cache.stats().toString();
}
public long size(){
return this.cache.size();
}
}
跟我一起使用:
@Service
public class CacheLocalCommonService {
private Logger logger = LoggerFactory.getLogger(CacheLocalCommonService.class);
@Autowired
private TmanVisitAndPlanService visitAndPlanService;
@Autowired
private CacheLocalConfigService cacheLocalConfigService;
@Autowired
private ImanAreaService imanAreaService;
public static final String key_local_cache_manForSelect = "local_cache_manForSelect_visit";
public static final String key_AllProvince = "local_cache_AllProvince";
public List<Map<String, Object>> findmanForSelect(){
Object data = cacheLocalConfigService.getIfPresent(key_local_cache_manForSelect);
if(data == null){
List<Map<String, Object>> dataSelectDb = visitAndPlanService.findmanForSelect();
cacheLocalConfigService.put(key_local_cache_manForSelect,dataSelectDb);
logger.error("****findmanForSelect put缓存,key={}",key_local_cache_manForSelect);
return dataSelectDb;
}
logger.error("****使用缓存,key={}",key_local_cache_manForSelect);
return (List<Map<String, Object>>) data;
}
/**
* 清除缓存
*/
public void cleanKeymanForSelect(){
try {
logger.error("**** cleanKeymanForSelect invalidate缓存,key={}",key_local_cache_manForSelect);
cacheLocalConfigService.invalidate(key_local_cache_manForSelect);
} catch (Exception e) {
logger.error("**** invalidate缓存,key={} 异常",key_local_cache_manForSelect);
}
}
public List<TAddressProvince> findAllProvinces(){
String key = key_AllProvince;
Object data = cacheLocalConfigService.getIfPresent(key);
if(data == null){
List<TAddressProvince> provinces = imanAreaService.findAllProvinces();
cacheLocalConfigService.put(key,provinces);
logger.error("****findAllProvinces put缓存,key={}",key);
return provinces;
}
logger.error("****使用缓存,key={}",key);
logger.error("****cacheLocalConfigService 缓存 统计,cacheStats={}", cacheLocalConfigService.stats());
logger.error("****cacheLocalConfigService 缓存 统计,size={}", cacheLocalConfigService.size());
return (List<TAddressProvince>) data;
}
}