首页 智能穿戴

苍穹外卖菜品管理:新增与删除功能的架构设计与实践避坑

分类:智能穿戴
字数: (9015)
阅读: (6471)
内容摘要:苍穹外卖菜品管理:新增与删除功能的架构设计与实践避坑,

在苍穹外卖这类高并发的餐饮系统中,菜品的新增和删除功能看似简单,实则对后端架构提出了不小的挑战。稍有不慎,就会导致数据不一致、接口响应缓慢,甚至引发雪崩效应。本文将深入探讨苍穹外卖系统中菜品新增和删除功能的底层原理、架构设计、以及实战中需要注意的各种坑,并提供具体的代码和配置示例。

问题场景重现:高并发下的数据一致性挑战

想象一下,在高峰时段,大量的商家同时进行菜品的新增和删除操作。如果没有合理的设计,很容易出现以下问题:

苍穹外卖菜品管理:新增与删除功能的架构设计与实践避坑
  • 数据库锁竞争激烈: 多个线程同时修改同一张表,导致数据库锁等待,影响性能。
  • 缓存数据不一致: 菜品信息修改后,缓存没有及时更新,导致用户看到过时的数据。
  • 消息队列积压: 如果使用消息队列异步更新相关服务,在高并发下可能导致消息积压,延缓数据同步。

底层原理深度剖析:CAP 理论与最终一致性

在分布式系统中,CAP 理论告诉我们,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)三者不可兼得。对于苍穹外卖系统,分区容错性是必须保证的,因此我们需要在一致性和可用性之间做出权衡。通常情况下,我们会选择最终一致性,即允许数据在短时间内不一致,但最终会达到一致的状态。

苍穹外卖菜品管理:新增与删除功能的架构设计与实践避坑

为了实现最终一致性,我们可以采用以下策略:

苍穹外卖菜品管理:新增与删除功能的架构设计与实践避坑
  • 读写分离: 将读操作和写操作分离到不同的数据库节点上,减轻数据库的压力。
  • 缓存: 使用 Redis 等缓存服务,缓存热点数据,提高读取速度。同时,需要考虑缓存失效策略,防止缓存雪崩。
  • 消息队列: 使用 RabbitMQ、Kafka 等消息队列,异步更新相关服务的数据,降低耦合性。

具体的代码/配置解决方案

下面以 Spring Boot + MySQL + Redis + RabbitMQ 为例,演示如何实现菜品新增和删除功能。

苍穹外卖菜品管理:新增与删除功能的架构设计与实践避坑

1. 数据库设计

CREATE TABLE `dish` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `category_id` bigint NOT NULL COMMENT '菜品分类id',
  `name` varchar(255) NOT NULL COMMENT '菜品名称',
  `price` decimal(10,2) NOT NULL COMMENT '菜品价格',
  `image` varchar(255) DEFAULT NULL COMMENT '菜品图片',
  `description` varchar(255) DEFAULT NULL COMMENT '菜品描述',
  `status` int DEFAULT '0' COMMENT '0表示禁用,1表示启用',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL COMMENT '更新时间',
  `create_user` bigint NOT NULL COMMENT '创建人',
  `update_user` bigint NOT NULL COMMENT '修改人',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜品表';

2. 新增菜品接口

@PostMapping("/dish")
public Result<String> save(@RequestBody DishDTO dishDTO) {
    dishService.saveWithFlavor(dishDTO);
    return Result.success("新增菜品成功");
}

3. 删除菜品接口

@DeleteMapping("/dish")
public Result<String> delete(@RequestParam List<Long> ids) {
    dishService.deleteBatch(ids);
    return Result.success("菜品删除成功");
}

4. 使用 Redis 缓存菜品信息

@Autowired
private RedisTemplate redisTemplate;

public Dish getDishById(Long id) {
    String key = "dish:" + id;
    Dish dish = (Dish) redisTemplate.opsForValue().get(key);
    if (dish == null) {
        dish = dishMapper.selectById(id);
        redisTemplate.opsForValue().set(key, dish, 60, TimeUnit.MINUTES); // 设置过期时间为 60 分钟
    }
    return dish;
}

public void deleteDishCache(Long id) {
    String key = "dish:" + id;
    redisTemplate.delete(key);
}

5. 使用 RabbitMQ 异步更新相关服务

@Autowired
private RabbitTemplate rabbitTemplate;

public void sendMessage(Long dishId) {
    rabbitTemplate.convertAndSend("dish.exchange", "dish.update", dishId);
}

6. Nginx 配置 (作为反向代理和负载均衡)

http {
  upstream backend {
    server 192.168.1.100:8080; # 服务实例1
    server 192.168.1.101:8080; # 服务实例2
  }

  server {
    listen 80;
    server_name example.com;

    location / {
      proxy_pass http://backend;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
    }
  }
}

宝塔面板可以方便地管理 Nginx 和其他服务,但需要注意安全配置,例如限制 IP 访问、设置防火墙等。在处理高并发连接时,需要合理调整 Nginx 的 worker 进程数、连接超时时间等参数。

实战避坑经验总结

  1. 避免大事务: 菜品新增和删除操作可能涉及多个表,尽量避免使用大事务,可以考虑使用 Saga 模式或 TCC 模式。
  2. 缓存穿透: 如果大量请求查询不存在的菜品,会导致缓存穿透,直接请求数据库。可以使用布隆过滤器来解决。
  3. 缓存击穿: 如果某个热点菜品的缓存失效,大量请求同时请求数据库,会导致缓存击穿。可以使用互斥锁或永不过期的缓存来解决。
  4. 消息队列积压: 如果消息队列积压,需要及时处理,例如扩容队列、优化消费者逻辑等。可以考虑设置死信队列,处理失败的消息。
  5. 数据库连接池配置: 合理配置数据库连接池的大小,避免连接数不足或连接数过多导致性能下降。常用的连接池有 Druid、HikariCP 等。

在实际应用中,还需要根据具体场景进行优化。例如,可以使用 CDN 加速静态资源的访问,使用 Elasticsearch 进行菜品搜索,使用 Prometheus 监控系统性能等。

苍穹外卖菜品管理:新增与删除功能的架构设计与实践避坑

转载请注明出处: 代码旅行家

本文的链接地址: http://m.acea1.store/blog/885171.SHTML

本文最后 发布于2026-04-11 13:17:17,已经过了16天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 香菜必须死 3 天前
    Nginx 的配置这一块能不能再详细一点?例如如何配置 HTTPS 和 Gzip 压缩?
  • 秃头程序员 1 天前
    讲的真透彻,点赞!特别是缓存穿透和击穿的解决方案,受益匪浅。
  • 绿茶观察员 1 天前
    讲的真透彻,点赞!特别是缓存穿透和击穿的解决方案,受益匪浅。
  • 豆腐脑 2 天前
    讲的真透彻,点赞!特别是缓存穿透和击穿的解决方案,受益匪浅。