业务常见问题与解决方案
4314字约14分钟
2025-08-16
高并发问题
1. 秒杀系统设计
问题描述
- 高并发访问导致系统崩溃
- 超卖问题(库存为负数)
- 重复下单问题
- 系统响应缓慢
解决方案
前端限流
// 按钮点击限流
let canClick = true;
function handleClick() {
if (!canClick) return;
canClick = false;
// 执行下单逻辑
submitOrder().finally(() => {
setTimeout(() => {
canClick = true;
}, 1000);
});
}后端限流
@RestController
public class SeckillController {
// 使用Redis限流
@Autowired
private RedisTemplate<String, String> redisTemplate;
@PostMapping("/seckill")
public Result seckill(@RequestParam Long productId, @RequestParam Long userId) {
// 1. 用户限流(每个用户每秒只能请求一次)
String userKey = "seckill:user:" + userId;
if (!redisTemplate.opsForValue().setIfAbsent(userKey, "1", 1, TimeUnit.SECONDS)) {
return Result.error("请求过于频繁,请稍后再试");
}
// 2. 商品限流(每个商品每秒最多处理100个请求)
String productKey = "seckill:product:" + productId;
Long count = redisTemplate.opsForValue().increment(productKey);
if (count == 1) {
redisTemplate.c(productKey, 1, TimeUnit.SECONDS);
}
if (count > 100) {
return Result.error("商品太火爆,请稍后再试");
}
// 3. 执行秒杀逻辑
return seckillService.doSeckill(productId, userId);
}
}库存扣减(防超卖)
@Service
public class SeckillService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Transactional
public Result doSeckill(Long productId, Long userId) {
// 使用Redis原子操作扣减库存
String stockKey = "stock:" + productId;
Long stock = redisTemplate.opsForValue().decrement(stockKey);
if (stock < 0) {
// 库存不足,回滚
redisTemplate.opsForValue().increment(stockKey);
return Result.error("库存不足");
}
// 检查是否重复下单
String orderKey = "order:" + productId + ":" + userId;
if (redisTemplate.hasKey(orderKey)) {
// 重复下单,回滚库存
redisTemplate.opsForValue().increment(stockKey);
return Result.error("您已下单,请勿重复操作");
}
try {
// 创建订单
Order order = createOrder(productId, userId);
// 标记已下单
redisTemplate.opsForValue().set(orderKey, order.getId().toString(), 24, TimeUnit.HOURS);
return Result.success(order);
} catch (Exception e) {
// 异常回滚库存
redisTemplate.opsForValue().increment(stockKey);
throw e;
}
}
}2. 接口幂等性设计
问题描述
- 用户重复点击导致重复提交
- 网络重试导致重复请求
- 分布式环境下重复处理
解决方案
唯一标识符
@RestController
public class OrderController {
@PostMapping("/createOrder")
public Result createOrder(@RequestBody OrderRequest request,
@RequestHeader("X-Request-Id") String requestId) {
// 检查请求ID是否已处理
String processedKey = "processed:" + requestId;
if (redisTemplate.hasKey(processedKey)) {
// 幂等返回,不重复处理
return Result.success("订单已创建");
}
try {
// 处理业务逻辑
Order order = orderService.createOrder(request);
// 标记请求已处理
redisTemplate.opsForValue().set(processedKey, "1", 24, TimeUnit.HOURS);
return Result.success(order);
} catch (Exception e) {
// 异常时删除标记,允许重试
redisTemplate.delete(processedKey);
throw e;
}
}
}数据库唯一约束
-- 订单表添加唯一约束
ALTER TABLE orders ADD UNIQUE KEY uk_user_product_time (user_id, product_id, create_time);
-- 或者使用业务字段组合
ALTER TABLE orders ADD UNIQUE KEY uk_request_id (request_id);分布式锁
@Service
public class OrderService {
@Autowired
private RedissonClient redissonClient;
public Order createOrder(OrderRequest request) {
String lockKey = "order:lock:" + request.getRequestId();
RLock lock = redissonClient.getLock(lockKey);
try {
// 尝试获取锁,等待5秒,持有锁30秒
if (lock.tryLock(5, 30, TimeUnit.SECONDS)) {
// 检查是否已处理
if (orderRepository.existsByRequestId(request.getRequestId())) {
return orderRepository.findByRequestId(request.getRequestId());
}
// 创建订单
Order order = new Order();
// ... 设置订单属性
return orderRepository.save(order);
} else {
throw new RuntimeException("获取锁失败");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("获取锁被中断");
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}性能优化问题
1. 数据库查询优化
问题描述
- 慢查询导致接口响应慢
- 大量数据查询内存溢出
- 复杂关联查询性能差
解决方案
分页查询优化
@Service
public class UserService {
// 传统分页(性能差)
public Page<User> getUsersTraditional(int page, int size) {
Pageable pageable = PageRequest.of(page, size);
return userRepository.findAll(pageable);
}
// 游标分页(性能好)
public List<User> getUsersByCursor(Long lastId, int size) {
if (lastId == null) {
return userRepository.findTopByOrderByIdAsc(size);
} else {
return userRepository.findByIdGreaterThanOrderByIdAsc(lastId, size);
}
}
// 时间分页
public List<User> getUsersByTime(Date lastTime, int size) {
if (lastTime == null) {
return userRepository.findTopByOrderByCreateTimeDesc(size);
} else {
return userRepository.findByCreateTimeBeforeOrderByCreateTimeDesc(lastTime, size);
}
}
}批量操作优化
@Service
public class BatchService {
// 批量插入
public void batchInsert(List<User> users) {
int batchSize = 1000;
for (int i = 0; i < users.size(); i += batchSize) {
int end = Math.min(i + batchSize, users.size());
List<User> batch = users.subList(i, end);
userRepository.saveAll(batch);
}
}
// 批量更新
@Transactional
public void batchUpdate(List<Long> userIds, String status) {
int batchSize = 500;
for (int i = 0; i < userIds.size(); i += batchSize) {
int end = Math.min(i + batchSize, userIds.size());
List<Long> batch = userIds.subList(i, end);
userRepository.updateStatusByIds(batch, status);
}
}
// 使用JdbcTemplate批量操作
@Autowired
private JdbcTemplate jdbcTemplate;
public void batchInsertWithJdbc(List<User> users) {
String sql = "INSERT INTO users (name, email, create_time) VALUES (?, ?, ?)";
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
User user = users.get(i);
ps.setString(1, user.getName());
ps.setString(2, user.getEmail());
ps.setTimestamp(3, new Timestamp(user.getCreateTime().getTime()));
}
@Override
public int getBatchSize() {
return users.size();
}
});
}
}2. 缓存优化
问题描述
- 缓存穿透(查询不存在的数据)
- 缓存雪崩(大量缓存同时失效)
- 缓存击穿(热点数据失效)
解决方案
缓存穿透防护
@Service
public class UserService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public User getUserById(Long id) {
String key = "user:" + id;
// 1. 查询缓存
User user = (User) redisTemplate.opsForValue().get(key);
if (user != null) {
return user;
}
// 2. 查询数据库
user = userRepository.findById(id).orElse(null);
if (user != null) {
// 3. 缓存存在的数据
redisTemplate.opsForValue().set(key, user, 1, TimeUnit.HOURS);
} else {
// 4. 缓存空值,防止缓存穿透
redisTemplate.opsForValue().set(key, new NullValue(), 5, TimeUnit.MINUTES);
}
return user;
}
// 布隆过滤器防穿透
@Autowired
private BloomFilter<Long> userBloomFilter;
public User getUserByIdWithBloomFilter(Long id) {
// 1. 布隆过滤器检查
if (!userBloomFilter.mightContain(id)) {
return null;
}
// 2. 查询缓存和数据库
return getUserById(id);
}
}缓存雪崩防护
@Service
public class CacheService {
// 随机过期时间
public void setWithRandomExpire(String key, Object value, long baseExpire, TimeUnit unit) {
// 基础过期时间 + 随机偏移(±10%)
long randomOffset = (long) (baseExpire * 0.1 * (Math.random() - 0.5));
long expireTime = baseExpire + randomOffset;
redisTemplate.opsForValue().set(key, value, expireTime, unit);
}
// 缓存预热
@PostConstruct
public void cacheWarmUp() {
// 系统启动时预热热点数据
List<User> hotUsers = userRepository.findHotUsers();
for (User user : hotUsers) {
setWithRandomExpire("user:" + user.getId(), user, 1, TimeUnit.HOURS);
}
}
// 定时刷新缓存
@Scheduled(fixedRate = 30 * 60 * 1000) // 30分钟
public void refreshCache() {
List<User> hotUsers = userRepository.findHotUsers();
for (User user : hotUsers) {
String key = "user:" + user.getId();
if (redisTemplate.hasKey(key)) {
// 延长过期时间
redisTemplate.expire(key, 1, TimeUnit.HOURS);
}
}
}
}缓存击穿防护
@Service
public class HotDataService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 互斥锁防击穿
public Object getHotDataWithLock(String key, Supplier<Object> dataLoader) {
// 1. 查询缓存
Object data = redisTemplate.opsForValue().get(key);
if (data != null) {
return data;
}
// 2. 获取分布式锁
String lockKey = "lock:" + key;
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {
// 3. 双重检查
data = redisTemplate.opsForValue().get(key);
if (data != null) {
return data;
}
// 4. 加载数据
data = dataLoader.get();
redisTemplate.opsForValue().set(key, data, 1, TimeUnit.HOURS);
return data;
} else {
// 5. 获取锁失败,等待一段时间后重试
Thread.sleep(100);
return getHotDataWithLock(key, dataLoader);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("获取锁被中断");
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
// 逻辑过期防击穿
public Object getHotDataWithLogicExpire(String key, Supplier<Object> dataLoader) {
// 1. 查询缓存
Object data = redisTemplate.opsForValue().get(key);
if (data != null) {
// 2. 检查逻辑过期时间
String expireKey = "expire:" + key;
Long expireTime = (Long) redisTemplate.opsForValue().get(expireKey);
if (expireTime != null && System.currentTimeMillis() < expireTime) {
return data;
}
// 3. 逻辑过期,异步更新
CompletableFuture.runAsync(() -> {
try {
Object newData = dataLoader.get();
redisTemplate.opsForValue().set(key, newData);
redisTemplate.opsForValue().set(expireKey,
System.currentTimeMillis() + 3600000, 1, TimeUnit.HOURS);
} catch (Exception e) {
log.error("异步更新缓存失败", e);
}
});
return data;
}
// 4. 缓存不存在,同步加载
data = dataLoader.get();
redisTemplate.opsForValue().set(key, data);
redisTemplate.opsForValue().set(expireKey,
System.currentTimeMillis() + 3600000, 1, TimeUnit.HOURS);
return data;
}
}数据一致性问题
1. 分布式事务
问题描述
- 跨服务数据不一致
- 部分成功部分失败
- 数据最终一致性难以保证
解决方案
2PC(两阶段提交)
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private InventoryService inventoryService;
@Autowired
private PaymentService paymentService;
// 2PC实现
@Transactional
public Result createOrderWith2PC(OrderRequest request) {
String xid = UUID.randomUUID().toString();
try {
// 第一阶段:准备阶段
if (!inventoryService.prepare(xid, request.getProductId(), request.getQuantity())) {
return Result.error("库存准备失败");
}
if (!paymentService.prepare(xid, request.getUserId(), request.getAmount())) {
// 回滚库存
inventoryService.rollback(xid);
return Result.error("支付准备失败");
}
// 第二阶段:提交阶段
if (!inventoryService.commit(xid)) {
paymentService.rollback(xid);
return Result.error("库存提交失败");
}
if (!paymentService.commit(xid)) {
inventoryService.rollback(xid);
return Result.error("支付提交失败");
}
// 创建订单
Order order = createOrder(request);
return Result.success(order);
} catch (Exception e) {
// 异常回滚
inventoryService.rollback(xid);
paymentService.rollback(xid);
throw e;
}
}
}TCC(Try-Confirm-Cancel)
@Service
public class OrderTCCService {
// Try阶段:资源预留
@Transactional
public boolean tryCreateOrder(String xid, OrderRequest request) {
try {
// 1. 预留库存
if (!inventoryService.tryReserve(xid, request.getProductId(), request.getQuantity())) {
return false;
}
// 2. 预留资金
if (!paymentService.tryReserve(xid, request.getUserId(), request.getAmount())) {
// 回滚库存预留
inventoryService.cancelReserve(xid);
return false;
}
// 3. 创建预订单
Order order = new Order();
order.setStatus(OrderStatus.PENDING);
order.setXid(xid);
// ... 设置其他属性
orderRepository.save(order);
return true;
} catch (Exception e) {
// 异常回滚
inventoryService.cancelReserve(xid);
paymentService.cancelReserve(xid);
throw e;
}
}
// Confirm阶段:确认执行
@Transactional
public boolean confirmCreateOrder(String xid) {
try {
// 1. 确认库存扣减
if (!inventoryService.confirmReserve(xid)) {
return false;
}
// 2. 确认支付
if (!paymentService.confirmReserve(xid)) {
return false;
}
// 3. 确认订单
Order order = orderRepository.findByXid(xid);
order.setStatus(OrderStatus.CONFIRMED);
orderRepository.save(order);
return true;
} catch (Exception e) {
log.error("确认订单失败", e);
return false;
}
}
// Cancel阶段:取消操作
@Transactional
public boolean cancelCreateOrder(String xid) {
try {
// 1. 取消库存预留
inventoryService.cancelReserve(xid);
// 2. 取消资金预留
paymentService.cancelReserve(xid);
// 3. 取消订单
Order order = orderRepository.findByXid(xid);
if (order != null) {
order.setStatus(OrderStatus.CANCELLED);
orderRepository.save(order);
}
return true;
} catch (Exception e) {
log.error("取消订单失败", e);
return false;
}
}
}最终一致性(消息队列)
@Service
public class OrderEventService {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
// 创建订单(本地事务)
@Transactional
public Order createOrder(OrderRequest request) {
// 1. 创建订单
Order order = new Order();
// ... 设置订单属性
order = orderRepository.save(order);
// 2. 发送事件消息
OrderEvent event = new OrderEvent();
event.setOrderId(order.getId());
event.setType(OrderEventType.CREATED);
event.setData(request);
kafkaTemplate.send("order-events", JSON.toJSONString(event));
return order;
}
// 消费订单事件
@KafkaListener(topics = "order-events")
public void handleOrderEvent(String message) {
try {
OrderEvent event = JSON.parseObject(message, OrderEvent.class);
switch (event.getType()) {
case CREATED:
handleOrderCreated(event);
break;
case CANCELLED:
handleOrderCancelled(event);
break;
default:
log.warn("未知事件类型: {}", event.getType());
}
} catch (Exception e) {
log.error("处理订单事件失败", e);
// 可以发送到死信队列重试
}
}
private void handleOrderCreated(OrderEvent event) {
OrderRequest request = (OrderRequest) event.getData();
// 1. 扣减库存
inventoryService.decreaseStock(request.getProductId(), request.getQuantity());
// 2. 扣减余额
paymentService.decreaseBalance(request.getUserId(), request.getAmount());
// 3. 更新订单状态
Order order = orderRepository.findById(event.getOrderId()).orElse(null);
if (order != null) {
order.setStatus(OrderStatus.PAID);
orderRepository.save(order);
}
}
}2. 缓存与数据库一致性
问题描述
- 缓存更新不及时
- 缓存与数据库数据不一致
- 并发更新导致数据错乱
解决方案
先更新数据库,再删除缓存
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 更新用户信息
@Transactional
public void updateUser(User user) {
// 1. 更新数据库
userRepository.save(user);
// 2. 删除缓存
String key = "user:" + user.getId();
redisTemplate.delete(key);
}
// 删除用户
@Transactional
public void deleteUser(Long id) {
// 1. 删除数据库
userRepository.deleteById(id);
// 2. 删除缓存
String key = "user:" + id;
redisTemplate.delete(key);
}
}延迟双删策略
@Service
public class UserService {
// 延迟双删
@Transactional
public void updateUserWithDelayDelete(User user) {
// 1. 删除缓存
String key = "user:" + user.getId();
redisTemplate.delete(key);
// 2. 更新数据库
userRepository.save(user);
// 3. 延迟删除缓存(防止并发问题)
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(500); // 延迟500ms
redisTemplate.delete(key);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
}缓存更新策略
@Service
public class CacheUpdateService {
// 缓存更新策略
public void updateCache(String key, Object value, long expire, TimeUnit unit) {
// 1. 先更新缓存
redisTemplate.opsForValue().set(key, value, expire, unit);
// 2. 再更新数据库
updateDatabase(key, value);
}
// 缓存删除策略
public void deleteCache(String key) {
// 1. 先删除缓存
redisTemplate.delete(key);
// 2. 再删除数据库
deleteFromDatabase(key);
}
// 缓存读取策略
public Object getCache(String key, Supplier<Object> dataLoader) {
// 1. 查询缓存
Object data = redisTemplate.opsForValue().get(key);
if (data != null) {
return data;
}
// 2. 查询数据库
data = dataLoader.get();
if (data != null) {
// 3. 更新缓存
redisTemplate.opsForValue().set(key, data, 1, TimeUnit.HOURS);
}
return data;
}
}分布式问题
1. 分布式锁
问题描述
- 并发访问导致数据不一致
- 锁超时导致业务异常
- 死锁问题
解决方案
Redis分布式锁
@Service
public class RedisLockService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
// 获取锁
public boolean tryLock(String key, String value, long expire, TimeUnit unit) {
Boolean result = redisTemplate.opsForValue()
.setIfAbsent(key, value, expire, unit);
return Boolean.TRUE.equals(result);
}
// 释放锁
public boolean releaseLock(String key, String value) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) else return 0 end";
Long result = redisTemplate.execute(
new DefaultRedisScript<>(script, Long.class),
Collections.singletonList(key),
value
);
return Long.valueOf(1).equals(result);
}
// 使用分布式锁
public Object executeWithLock(String key, Supplier<Object> task,
long expire, TimeUnit unit) {
String lockValue = UUID.randomUUID().toString();
String lockKey = "lock:" + key;
try {
// 尝试获取锁
if (!tryLock(lockKey, lockValue, expire, unit)) {
throw new RuntimeException("获取锁失败");
}
// 执行任务
return task.get();
} finally {
// 释放锁
releaseLock(lockKey, lockValue);
}
}
}Zookeeper分布式锁
@Service
public class ZookeeperLockService {
@Autowired
private CuratorFramework client;
// 获取锁
public InterProcessMutex getLock(String path) {
return new InterProcessMutex(client, path);
}
// 使用锁
public Object executeWithLock(String path, Supplier<Object> task,
long timeout, TimeUnit unit) {
InterProcessMutex lock = getLock(path);
try {
// 尝试获取锁
if (lock.acquire(timeout, unit)) {
// 执行任务
return task.get();
} else {
throw new RuntimeException("获取锁超时");
}
} catch (Exception e) {
throw new RuntimeException("获取锁失败", e);
} finally {
try {
if (lock.isAcquiredInThisProcess()) {
lock.release();
}
} catch (Exception e) {
log.error("释放锁失败", e);
}
}
}
}2. 分布式ID生成
问题描述
- 自增ID在分布式环境下冲突
- UUID性能差且无序
- 雪花算法时钟回拨问题
解决方案
雪花算法
@Component
public class SnowflakeIdGenerator {
private final long workerId;
private final long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
private final long workerIdBits = 5L;
private final long datacenterIdBits = 5L;
private final long sequenceBits = 12L;
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final long workerIdShift = sequenceBits;
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
public SnowflakeIdGenerator(@Value("${snowflake.worker-id:1}") long workerId,
@Value("${snowflake.datacenter-id:1}") long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException("Worker ID超出范围");
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException("Datacenter ID超出范围");
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
// 时钟回拨检查
if (timestamp < lastTimestamp) {
throw new RuntimeException("时钟回拨,拒绝生成ID");
}
// 同一毫秒内序列号递增
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 同一毫秒内序列号用完,等待下一毫秒
timestamp = waitNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// 组合ID
return ((timestamp - 1288834974657L) << timestampLeftShift) |
(datacenterId << datacenterIdShift) |
(workerId << workerIdShift) |
sequence;
}
private long waitNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
}Redis自增ID
@Service
public class RedisIdGenerator {
@Autowired
private RedisTemplate<String, String> redisTemplate;
// 生成订单ID
public String generateOrderId() {
String key = "order:id:" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
Long sequence = redisTemplate.opsForValue().increment(key);
// 设置过期时间(避免无限增长)
redisTemplate.expire(key, 1, TimeUnit.DAYS);
return String.format("O%s%06d",
LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE),
sequence);
}
// 生成用户ID
public Long generateUserId() {
String key = "user:id";
return redisTemplate.opsForValue().increment(key);
}
}安全相关问题
1. SQL注入防护
问题描述
- 恶意SQL注入攻击
- 数据库信息泄露
- 数据被恶意修改
解决方案
参数化查询
@Repository
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
// 正确的参数化查询
public User findByUsername(String username) {
String sql = "SELECT * FROM users WHERE username = ?";
try {
return jdbcTemplate.queryForObject(sql, new Object[]{username}, new UserRowMapper());
} catch (EmptyResultDataAccessException e) {
return null;
}
}
// 使用NamedParameterJdbcTemplate
public List<User> findByCondition(String username, String email) {
String sql = "SELECT * FROM users WHERE 1=1";
MapSqlParameterSource params = new MapSqlParameterSource();
if (StringUtils.hasText(username)) {
sql += " AND username = :username";
params.addValue("username", username);
}
if (StringUtils.hasText(email)) {
sql += " AND email = :email";
params.addValue("email", email);
}
return namedParameterJdbcTemplate.query(sql, params, new UserRowMapper());
}
}MyBatis参数绑定
<!-- 正确的参数绑定 -->
<select id="findByCondition" resultType="User">
SELECT * FROM users
<where>
<if test="username != null and username != ''">
AND username = #{username}
</if>
<if test="email != null and email != ''">
AND email = #{email}
</if>
</where>
</select>
<!-- 错误的字符串拼接(容易SQL注入) -->
<select id="findByConditionWrong" resultType="User">
SELECT * FROM users WHERE username = '${username}'
</select>2. XSS防护
问题描述
- 恶意脚本注入
- 用户信息泄露
- 会话劫持
解决方案
输入过滤
@Component
public class XssFilter {
// HTML转义
public String escapeHtml(String input) {
if (input == null) {
return null;
}
return input.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("\"", """)
.replace("'", "'");
}
// 移除危险标签
public String removeDangerousTags(String input) {
if (input == null) {
return null;
}
// 移除script、iframe等危险标签
return input.replaceAll("(?i)<script[^>]*>.*?</script>", "")
.replaceAll("(?i)<iframe[^>]*>.*?</iframe>", "")
.replaceAll("(?i)<object[^>]*>.*?</object>", "")
.replaceAll("(?i)<embed[^>]*>.*?</embed>", "");
}
}输出编码
<!-- Thymeleaf自动转义 -->
<div th:text="${user.name}"></div>
<div th:utext="${user.description}"></div>
<!-- 手动转义 -->
<div th:utext="${#strings.escapeXml(user.description)}"></div>监控告警问题
1. 业务监控
问题描述
- 业务异常无法及时发现
- 性能问题难以定位
- 缺乏业务指标监控
解决方案
业务指标监控
@Component
public class BusinessMetrics {
private final MeterRegistry meterRegistry;
public BusinessMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
// 订单创建成功率
public void recordOrderSuccess() {
Counter.builder("order.success")
.tag("type", "create")
.register(meterRegistry)
.increment();
}
public void recordOrderFailure() {
Counter.builder("order.failure")
.tag("type", "create")
.register(meterRegistry)
.increment();
}
// 接口响应时间
public Timer.Sample startTimer(String name) {
return Timer.start(meterRegistry);
}
public void stopTimer(Timer.Sample sample, String name) {
sample.stop(Timer.builder("api.response.time")
.tag("name", name)
.register(meterRegistry));
}
// 业务异常监控
public void recordBusinessException(String type, String message) {
Counter.builder("business.exception")
.tag("type", type)
.tag("message", message)
.register(meterRegistry)
.increment();
}
}自定义注解监控
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MonitorBusiness {
String value() default "";
String[] tags() default {};
}
@Aspect
@Component
public class BusinessMonitorAspect {
private final MeterRegistry meterRegistry;
public BusinessMonitorAspect(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@Around("@annotation(monitor)")
public Object around(ProceedingJoinPoint point, MonitorBusiness monitor) throws Throwable {
Timer.Sample sample = Timer.start(meterRegistry);
try {
Object result = point.proceed();
// 记录成功
Counter.builder("business.success")
.tag("name", monitor.value())
.register(meterRegistry)
.increment();
return result;
} catch (Exception e) {
// 记录失败
Counter.builder("business.failure")
.tag("name", monitor.value())
.tag("exception", e.getClass().getSimpleName())
.register(meterRegistry)
.increment();
throw e;
} finally {
// 记录执行时间
sample.stop(Timer.builder("business.execution.time")
.tag("name", monitor.value())
.register(meterRegistry));
}
}
}2. 告警配置
问题描述
- 告警阈值设置不合理
- 告警信息不准确
- 告警风暴问题
解决方案
Prometheus告警规则
groups:
- name: business.rules
rules:
# 订单成功率告警
- alert: OrderSuccessRateLow
expr: rate(order_success_total[5m]) / (rate(order_success_total[5m]) + rate(order_failure_total[5m])) < 0.95
for: 2m
labels:
severity: warning
annotations:
summary: "订单成功率过低"
description: "订单成功率低于95%,当前值: {{ $value | humanizePercentage }}"
# 接口响应时间告警
- alert: ApiResponseTimeHigh
expr: histogram_quantile(0.95, rate(api_response_time_seconds_bucket[5m])) > 1
for: 1m
labels:
severity: warning
annotations:
summary: "接口响应时间过高"
description: "95%分位响应时间超过1秒,当前值: {{ $value }}s"
# 业务异常告警
- alert: BusinessExceptionHigh
expr: rate(business_exception_total[5m]) > 10
for: 1m
labels:
severity: critical
annotations:
summary: "业务异常频率过高"
description: "业务异常频率超过每分钟10次,当前值: {{ $value }}"告警抑制和分组
# 告警抑制规则
inhibit_rules:
# 如果订单服务完全不可用,抑制订单相关的其他告警
- source_match:
alertname: OrderServiceDown
target_match:
alertname: OrderSuccessRateLow
equal: [ 'service' ]
# 如果数据库不可用,抑制所有业务告警
- source_match:
alertname: DatabaseDown
target_match:
severity: warning
equal: [ 'instance' ]
# 告警分组
route:
group_by: [ 'alertname', 'service' ]
group_wait: 30s # 等待30秒后发送第一个告警
group_interval: 5m # 5分钟后发送重复告警
repeat_interval: 4h # 4小时后重复告警总结
业务常见问题的解决需要:
- 预防为主:设计合理的架构和流程
- 监控先行:建立完善的监控体系
- 快速响应:制定应急预案和回滚策略
- 持续优化:根据实际运行情况不断改进
关键原则
- 幂等性:所有操作都要支持重复执行
- 最终一致性:允许短暂不一致,但要保证最终一致
- 降级策略:核心功能优先,非核心功能可降级
- 限流保护:防止系统过载,保护核心业务
记住:没有完美的解决方案,只有最适合当前业务场景的方案。要根据实际情况选择合适的策略组合。
