外卖平台每天有1000万笔订单查询怎么优化?

1. 业务场景与挑战

每日订单量1000万级,数据规模呈指数级增长:

  • 年度数据量达36亿条
  • 单表容量突破2000万性能临界点
  • 高峰期并发请求量超过5万QPS

核心挑战聚焦三大维度:

  1. 存储成本:海量数据物理存储成本激增
  2. 查询效率:多维度组合查询响应超时
  3. 并发压力:实时订单状态查询流量洪峰

2. 存储压力如何解决

  1. 如何保证大数据量存储

通过分库分表

如何拆分?买家和卖家是否需要分开存储?

分开存储扩展已经查询性能都会好一些。

  1. 如何分库?

分库策略,通过用户ID 或者订单创建时间 取模 分库数量

分表策略:每个库内按月份分表

  1. 数据都要存储到数据库吗?

对于很多数据在近期都不会被查询,所以可以将数据做一个拆分,冷数据 and 热数据。

30 天内的数据 -> MySQL

超过30天的数据 -> TiDB or ClickHouse ...

3. 复杂业务场景如何解决?

举个例子,比如查询卖家过去30天内金额>100元且为己完成状态的某类订单?

通过ES是不是更加高效?

  • 索引设计:建立seller_id + create_time + order_status联合索引
  • 数据同步:基于Binlog实现准实时同步
json 复制代码
// 多条件组合查询DSL优化
{
  "query": {
    "bool": {
      "filter": [
        {"term": {"seller_id": 98765}},
        {"range": {"create_time": {"gte": "now-30d/d"}}},
        {"script": {"script": "doc['order_amount'].value >= 100"}}
      ],
      "must": [
        {"term": {"order_status": "completed"}},
        {"match": {"order_type": "takeout"}}
      ]
    }
  },
  "preference": "primary_first" // 优先主分片提升稳定性
}
​

4. 热点数据查询如何解决?

对于热点数据,查询 ES 或者 MySQL 无疑是带来很大压力以及性能也会比较差。

举个例子,买家查询最近10条订单数?卖家最近1天内所有订单列表;

对于这种热点数据,我们可以缓存到 Redis 中,对于热点数据存储到Redis就好,查询中走Redis查询性能也会提升大一些。

  1. 比如买家查询最近10条订单(读多写少场景)
ruby 复制代码
# Key: 用户维度 + 业务标识
buyer:orders:{user_id}:recent  # 例如 buyer:orders:12345:recent
​
# Value: 用 Redis List 存储订单ID(按时间倒序)
[
  "order_id_100",  # 最新订单
  "order_id_99",
  ...
  "order_id_91"    # 第10条订单
]
​
# 或用 Hash 存储订单详情(如果需缓存完整数据)
{
  "order_id_100": "{订单JSON}",
  "order_id_99": "{订单JSON}",
  ...
}
​
  1. 卖家最近1天内订单列表(高频过滤查询)
csharp 复制代码
# Key: 卖家ID + 时间范围
seller:orders:{seller_id}:last_24h  # 例如 seller:orders:98765:last_24h
​
# Value: 用 Sorted Set (ZSET) 存储订单ID和创建时间戳
# Score = 订单时间戳, Member = 订单ID
[
  [1640995200, "order_id_100"],
  [1640995201, "order_id_101"],
  ...
]
​
# 或用 Hash 存储订单详情(按需)
{
  "order_id_100": "{订单JSON}",
  "order_id_101": "{订单JSON}",
  ...
}
​

5. 总结

对于存储压力比较大,可以采用分库分表优化,采用合理的分库分表手段以及分片键的选取。对于久远数据,为了避免干扰目前的查询,可以采用冷热数据分离。

为了解决复杂的查询条件,可以采用ES查询优化。

对于热点数据,可以采用将近期内的订单数据缓存到 Redis 中,利用 Redis 性能高的特性,以及引入本地缓存构建多级缓存体系进行优化。

相关推荐
虽千万人 吾往矣7 分钟前
golang channel源码
开发语言·后端·golang
_十六19 分钟前
文档即产品!工程师必看的写作密码
前端·后端
radient20 分钟前
线上FullGC问题如何排查 - Java版
后端·架构
6confim24 分钟前
掌握 Cursor:AI 编程助手的高效使用技巧
前端·人工智能·后端
知其然亦知其所以然34 分钟前
面试官问我 Java 原子操作,我一句话差点让他闭麦!
java·后端·面试
Lx35235 分钟前
📌K8s生产环境排错之:那些暗黑操作
后端·kubernetes
栗筝i40 分钟前
Spring Boot 核心模块全解析:12 个模块详解及作用说明
java·spring boot·后端
Cache技术分享43 分钟前
55. Java 类和对象 - 了解什么是对象
java·后端
楽码1 小时前
理解go指针和值传递
后端·go·编程语言