网易首页 > 网易号 > 正文 申请入驻

分布式订单系统:订单号编码设计实战

0
分享至

分布式订单系统:订单号编码设计实战

作者 : Carve_the_Code 标签 : #分布式系统 #数据库分片 #性能优化 #架构设计 声明 :本文基于通用分布式系统实践总结,代码为简化示例,性能数据为典型场景参考值。
一、背景:分库分表后的路由困境1.1 业务场景

某大型 OTA 平台的订单系统支持多国家、多渠道业务,主要服务于:

  • EU_CHANNEL: 欧洲多国业务
  • GLOBAL_CHANNEL: 国际站业务
  • CN_CHANNEL: 国内站国际业务

#后端 #Java #新人报道作为核心服务,订单详情查询是最高频的操作之一,每天处理千万级查询请求。

二、架构演进2.1 单库时代

订单号设计

  • 使用公司统一的分布式 ID 服务(基于 Snowflake)
  • orderId 为 64 位 Long,全局唯一、趋势递增
  • 不包含任何业务路由信息

查询方式

SELECT * FROM t_order WHERE order_id = ?

简单高效,单库足以支撑初期业务量。

2.2 分库分表(路由困境浮现)

改造背景:订单量持续增长,单库性能瓶颈,必须分库分表。

分片方案

  • 按 channel + orderId % 4 拆分
  • 不同渠道的数据物理隔离

问题来了:订单号仍然是普通 Snowflake ID,不包含路由信息

查询订单时的困境:

  1. 拿到 orderId,但不知道属于哪个渠道
  2. 必须先查询订单索引表,获取渠道信息
  3. 再根据渠道信息定位到具体分片

性能影响

查询耗时:从几十毫秒 → 数百毫秒P99 延迟:超过 1 秒原因:每次查询都要先"找分片"
2.3 订单号编码优化(解决路由问题)

核心思路:改造 ID 生成逻辑,将路由信息编码到订单号中。

灵感来源:身份证号

身份证号: 110101 1990 0101 001X└──┬─┘ └───┬──┘ └┬┘地区  出生日期  序列号(北京) (1990.01.01)

看到身份证号前 6 位,就知道是哪个地区的人,无需查库

方案:在 64 位订单号中嵌入 4 位 routeKey,查询时直接解析,无需查库。

核心收益

  • 95% 的查询无需查库获取路由信息
  • 查询性能显著提升(数十倍提升
  • 数据库负载降低 80%

兼容策略

  • 新订单:编码了 routeKey,可直接解析
  • 老订单:没有编码信息,走兜底查库
  • 异常情况:三层降级策略保证可用性
三、技术实现:订单号编码3.1 位结构设计
方案参考了业界成熟的分布式 ID 实践(如美团 Leaf),在此基础上增加了路由信息编码。

原有 Snowflake 结构(64 位):

┌─────────────┬──────────────┬──────────────┬──────────────┐│ 时间戳(41位) │ 数据中心(5位) │ 机器ID(5位)   │ 序列号(12位)  │└─────────────┴──────────────┴──────────────┴──────────────┘

改造后:压缩机器 ID,腾出 4 位给 routeKey

64 位订单号结构

block-betacolumns 4block:timestamp["时间戳\n41位\nbit63-23"]endblock:dc["数据中心\n5位\nbit22-18"]endblock:routeKey["routeKey\n4位\nbit17-14"]endblock:seq["序列号\n14位\nbit13-0"]end

┌──────────────┬──────────────┬──────────────┬──────────────┐│  时间戳(41位)  │ 数据中心(5位) │ routeKey(4位) │  序列号(14位)  │├──────────────┼──────────────┼──────────────┼──────────────┤│   bit 63-23   │   bit 22-18  │   bit 17-14  │   bit 13-0   │└──────────────┴──────────────┴──────────────┴──────────────┘高位 ◄────────────────────────────────────────────► 低位

关键设计点

  • routeKey 占 4 位(4 bits):可以表示 16 种渠道(2^4 = 16)
  • 位置选择:放在序列号之前(bit 17-14,从高到低),便于位运算提取
  • 编码映射:EU_CHANNEL → 5, GLOBAL_CHANNEL → 2, CN_CHANNEL → 1
3.2 为什么是 4 位?

容量计算

  • 当前业务有 3 个主要渠道
  • 未来可能增加更多渠道
  • 4 位可以表示 16 种渠道,预留 13 种扩展空间

位数权衡

  • 太少(2 位):只能表示 4 种渠道,扩展性不足
  • 太多(8 位):浪费空间,挤压序列号位数,影响并发性能
  • 4 位刚好:满足当前需求 + 未来扩展
3.3 编码过程(完整流程)

订单号生成时序图

客户端 订单服务 ID 生成器 用户数据服务 位运算编码 routeKey 下单请求(region=GB) 查询 routeKey(region) EU_CHANNEL 生成订单号(routeKey) orderId(含路由信息) 订单创建成功 客户端 订单服务 ID 生成器 用户数据服务

步骤 1:用户传入 region (用户地区,国家代码)

// 用户下单时传入 regionGenerateOrderIdRequest request = new GenerateOrderIdRequest();request.setRegion("GB");  // 英国request.setUid("user123");

步骤 2:region → routeKey 映射

// 订单号生成服务内部会将 region 映射为 routeKey// GB (英国) → EU_CHANNEL// ES (西班牙) → EU_CHANNEL// CN (中国) → CN_CHANNEL// 这个映射关系由用户数据服务维护GenerateOrderIdRequest generateOrderIdRequest = new GenerateOrderIdRequest(); generateOrderIdRequest.setUid(request.getUid()); generateOrderIdRequest.setRegion(request.getRegion());// 调用订单号生成服务 Long orderId = idGeneratorService.generateId(generateOrderIdRequest).getOrderId();

步骤 3:routeKey → 4 位编码

// 订单号生成服务内部实现(简化示例)public class OrderIdEncoder {private int encodeRouteKey(String routeKey) { // routeKey 映射为 4 位整数 switch (routeKey) { case "EU_CHANNEL": return 5; // 0101 case "GLOBAL_CHANNEL": return 2; // 0010 case "BIZ_CHANNEL": return 3; // 0011 case "CN_CHANNEL": return 1; // 0001 case "CORP_CHANNEL": return 4; // 0100 default: return 0; // 0000 (异常情况) } } }

步骤 4:拼接到 orderId(位运算)

// Snowflake 改造版本(伪代码)public long generateOrderId(String routeKey) {// 1. 获取当前时间戳(毫秒)long timestamp = System.currentTimeMillis() - EPOCH;  // 相对时间戳// 2. 获取数据中心 ID int datacenter = 3; // 假设当前数据中心 ID 为 3// 3. 编码 routeKey int routeKeyBits = encodeRouteKey(routeKey); // 5 (EU_CHANNEL)// 4. 获取序列号(同一毫秒内递增) int sequence = getSequence(); // 假设当前序列号为 123// 5. 位拼接:将各段信息拼接成 64 位 Long // 时间戳(41位) | 数据中心(5位) | routeKey(4位) | 序列号(14位) long orderId = 0; orderId |= (timestamp << 23); // 时间戳左移 23 位(5+4+14) orderId |= (datacenter << 18); // 数据中心左移 18 位(4+14) orderId |= (routeKeyBits << 14); // routeKey 左移 14 位 ⬅️ 关键!orderId |= sequence; // 序列号占据低 14 位return orderId; }

生成的订单号示例

十进制: 1234567890123456789二进制: 0001 0001 0010 0011 0100 0101 0110 01111000 1001 0000 0001 0010 0011 0100 0101↑ (bit 17-14)routeKey = 0101(值 5 → EU_CHANNEL)

关键技术

  • 左移运算(<<):将数据移到指定位置
  • 或运算(|):拼接多段数据
  • 无损编码:所有信息都保留在 64 位 Long 中
3.4 解码过程(反向提取)

完整的 getRouteKey 方法

private static String getRouteKey(Long orderId) {OrderIdDecoder orderIdDecoder = OrderIdFactory.getOrderIdDecoder();// 【第一层】优先从 orderId 解析 String routeKey = orderIdDecoder.decodeRouteKey(orderId); if (StringUtils.isEmpty(routeKey)) { // 【第二层】其次从请求上下文获取 routeKey = RequestContext.get("routeKey"); }if (StringUtils.isEmpty(routeKey)) { // 【第三层】最后从 region 推断 String region = RequestContext.get("region"); Optional routeKeyByRegion = DataMappingService.getRouteKey(region); routeKey = routeKeyByRegion.orElse(""); }return routeKey; }

OrderIdDecoder 内部实现

public class OrderIdDecoder {private static final int ROUTE_KEY_OFFSET = 14; // 右移 14 位 private static final long ROUTE_KEY_MASK = 0xF; // 低 4 位掩码(0b1111)public String decodeRouteKey(Long orderId) { if (orderId == null) { return null; }try { // 位运算提取 routeKey(bit14-17,右移 14 位后取低 4 位) int routeKeyBits = (int)((orderId >> ROUTE_KEY_OFFSET) & ROUTE_KEY_MASK);// 解码为字符串 return decodeRouteKeyBits(routeKeyBits); } catch (Exception e) { log.error("解析 orderId 失败: {}", orderId, e); return null; } }private String decodeRouteKeyBits(int bits) { switch (bits) { case 5: return "EU_CHANNEL"; case 2: return "GLOBAL_CHANNEL"; case 3: return "BIZ_CHANNEL"; case 1: return "CN_CHANNEL"; case 4: return "CORP_CHANNEL"; default: return null; // 解析失败 } } }

解码示例

// 示例订单号Long orderId = 1234567890123456789L;// 位运算过程:// 1.// 2. 取低 4 位:& 0xF (0b1111)int routeKeyBits = (int)((orderId >> 14) & 0xF); // 提取 routeKey String routeKey = decodeRouteKeyBits(routeKeyBits); // 映射为渠道名称
四、三层路由策略4.1 设计理念

核心问题:不是所有订单都能解析成功

  • 新订单:编码了 routeKey,可以直接解析
  • 老订单:没有编码信息,无法解析
  • 异常情况:解析失败、数据异常等

解决方案:三层路由策略(逐层降级)

命中

未命中

解析成功

解析失败

获取成功

获取失败

查询成功

查询失败

查询请求 orderId

Layer 0: 缓存

返回分片索引

Layer 1: orderId 解析

计算分片索引

写入缓存

Layer 2: 请求上下文

Layer 3: 查库兜底

返回默认分片

各层职责

┌─────────────────────────────────────────────────────────────┐│                     查询请求(orderId)                       │└─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐│ 【Layer 0】缓存层                                            ││ 命中 → 直接返回分片索引                                        ││ 未命中 → 进入 Layer 1                                         │└─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐│ 【Layer 1】orderId 解析层                                     ││ 从 orderId 位运算提取 routeKey                             ││ 成功 → 计算分片索引,写入缓存,返回                              ││ 失败 → 进入 Layer 2                                          │└─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐│ 【Layer 2】上下文获取层                                        ││ 从请求上下文获取 routeKey / region                             ││ 成功 → 计算分片索引,写入缓存,返回                              ││ 失败 → 进入 Layer 3                                          │└─────────────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────────────┐│ 【Layer 3】查库兜底层                                         ││ 查询订单索引表获取渠道字段                                      ││ 成功 → 计算分片索引,写入缓存,返回                              ││ 失败 → 返回默认分片(兜底)                                     │└─────────────────────────────────────────────────────────────┘
4.2 各层占比(实际数据)

| 路由层 | 占比 | 说明 | | ---

| Layer 0(缓存) | 95%+

| Layer 1(orderId 解析) | 70-80% | 新订单直接解析 | | Layer 2(上下文) | 5-10% | 链路中携带信息 | | Layer 3(查库兜底) | 15-25% | 老订单 + 异常情况 |

目标:逐步降低 Layer 3 占比,最终 < 5%

五、核心代码实现5.1 缓存层实现

public class ShardingCacheHelper {private static final String CACHE_PREFIX = "shard:"; private static final int CACHE_EXPIRE_SECONDS = 24 * 3600; // 24小时private final CacheService cacheService;/** * 获取分片索引(带缓存) */ public Integer getShardIndex(Long orderId) { String cacheKey = CACHE_PREFIX + orderId;// 1. 先查缓存 String cachedValue = cacheService.get(cacheKey); if (StringUtils.isNotEmpty(cachedValue)) { return Integer.parseInt(cachedValue); }return null; // 缓存未命中 }/** * 写入缓存 */ public void setShardIndex(Long orderId, int shardIndex) { String cacheKey = CACHE_PREFIX + orderId; cacheService.setEx(cacheKey, String.valueOf(shardIndex), CACHE_EXPIRE_SECONDS); } }
5.2 分片定位器完整实现

public class ShardingRouter {private static final int SHARD_COUNT = 4; // 每个渠道的分片数量 private final ShardingCacheHelper cacheHelper; private final OrderDao orderDao; private final ChannelShardConfig channelShardConfig; // 渠道分片配置/** * 定位订单所在分片 */ public int locate(Long orderId) { // 【Layer 0】缓存层 Integer cachedIndex = cacheHelper.getShardIndex(orderId); if (cachedIndex != null) { return cachedIndex; }// 【Layer 1】orderId 解析层 String routeKey = getRouteKey(orderId); if (StringUtils.isNotEmpty(routeKey)) { int shardIndex = calculateShardIndex(routeKey, orderId); cacheHelper.setShardIndex(orderId, shardIndex); return shardIndex; }// 【Layer 2 & 3】上下文 + 查库兜底 return fallbackLocate(orderId); }/** * 计算分片索引 */ private int calculateShardIndex(String routeKey, Long orderId) { int baseIndex = getBaseIndex(routeKey); int offset = (int)(orderId % SHARD_COUNT); // 分片数量 return baseIndex + offset; }private int getBaseIndex(String routeKey) { // 不同渠道对应不同的分片基础索引 // 具体映射关系根据业务配置 return channelShardConfig.getBaseIndex(routeKey); }/** * 兜底定位(查库) */ private int fallbackLocate(Long orderId) { // 1. 查询订单索引表 Order order = orderDao.queryById(orderId); if (order == null) { return ShardIndex.OTHER.getIndex(); // 默认分片 }// 2. 根据渠道字段计算分片索引 String channel = order.getChannel(); int shardIndex = calculateShardIndex(channel, orderId);// 3. 写入缓存(避免重复查库) cacheHelper.setShardIndex(orderId, shardIndex);return shardIndex; } }
六、踩坑与经验6.1 实际遇到的问题

问题 1:调用方未传 region 参数

现象

  • 上线后发现兜底查库比例高达 25%+
  • 监控显示大量订单号解析失败

原因

  • ID 生成服务升级后,需要调用方传入 region 参数
  • 部分老接口、定时任务、消息消费者未及时改造
  • 生成的订单号中 routeKey 位段为 0,无法解析

解决方案

// 1.if (StringUtils.isEmpty(request.getRegion())) { // 记录调用来源,便于推动改造 metric("id_gen_no_region", getCallerService()); }// 3. 设置 deadline,未改造的服务降低优先级

问题 2:历史订单兼容

现象

  • 改造前已存在的订单(百万级)无法解析 routeKey
  • 这些订单仍然有查询需求(售后、对账等)

解决方案

  • 设计三层降级策略(见第四章)
  • 历史订单走兜底查库 + 缓存
  • 随着时间推移,历史订单查询占比自然下降

问题 3:灰度发布时的数据一致性

现象

  • 灰度期间,部分机器用新版 ID 生成逻辑,部分用旧版
  • 同一渠道的订单,有的能解析,有的不能

解决方案

// 按渠道灰度,而不是按机器灰度// 确保同一渠道的订单要么全部新版,要么全部旧版if (grayConfig.isNewVersionEnabled(routeKey)) {return newIdGenerator.generate(request);} else {return oldIdGenerator.generate(request);
6.2 设计权衡

权衡 1:为什么不用 UUID?

| 方案 | 优点 | 缺点 | 结论 | | ---

| UUID | • 全局唯一• 无需协调 | • 128 位太长• 无序,影响 B+

| Snowflake | • 64 位紧凑• 单调递增• 可编码业务信息 | • 需要协调机器 ID | ✅ 采用 |

权衡 2:为什么只编码 routeKey?

考虑过的方案

  • 方案 1:编码更多信息(国家、用户类型、业务线等)
  • 方案 2:只编码最关键的路由信息(routeKey)

最终选择方案 2

  • 64 位空间有限,每增加 1 位编码,序列号就减少 1 位
  • 序列号越少,并发性能越差(同一毫秒内可生成的 ID 数量)
  • routeKey 是分片路由的唯一依据,优先保证路由性能
  • 其他信息可以通过查询订单索引表获取

权衡 3:为什么保留兜底查库?

理想状态:100% 解析成功,完全不查库

现实情况

  • 老订单(10-20%)无法避免
  • 老代码升级需要时间(5-10%)
  • 异常情况难以杜绝(1-2%)

权衡结果

  • ✅ 保留兜底查库,确保系统 100% 可用
  • ✅ 通过监控推动解析成功率逐步提升
  • ✅ 目标:Layer 3 占比从 25% → 10% → 5% → 1%
6.3 监控与优化

关键监控指标

// 1.metricError("orderId_decode_failed", orderId);metric("route_cache_hit", count); // 缓存命中 metric("route_layer_1", count); // orderId 解析 metric("route_layer_2", count); // 上下文获取 metric("route_layer_3", count); // 查库兜底metric("decode_fail_no_region", count); // 没传 region metric("decode_fail_old_order", count); // 老订单 metric("decode_fail_exception", count); // 解析异常

监控面板示例

订单号解析成功率(实时)┌────────────────────────────────────────┐│ 总请求数: 1,000,000                     ││ 缓存命中: 950,000 (95%)  ✅             ││ Layer 1:  750,000 (75%)  ✅             ││ Layer 2:   50,000 (5%)   ✅             ││ Layer 3:  200,000 (20%)  ⚠️             │└────────────────────────────────────────┘解析失败原因分布 ┌────────────────────────────────────────┐ │ 没传 region: 80,000 (8%) ⬅️ 重点优化 │ │ 老订单: 110,000 (11%) ⬅️ 历史包袱 │ │ 解析异常: 10,000 (1%) ⬅️ 异常情况 │ └────────────────────────────────────────┘Top 10 未传 region 的服务 ┌────────────────────────────────────────┐ │ 1.│ 2.│ 3.│ ... │ └────────────────────────────────────────┘

持续优化

  • 阶段 1(当前):识别问题代码,制定迁移计划
  • 阶段 2(1-3 个月):逐步升级老代码,Layer 3 占比降到 10%
  • 阶段 3(3-6 个月):继续优化,Layer 3 占比降到 5%
  • 阶段 4(6-12 个月):最终目标,Layer 3 占比降到 1% 以下
七、总结核心收益

| 指标 | 优化前 | 优化后 | | ---

| 查询耗时 | 数百毫秒 | 个位数毫秒 | | P99 延迟 | 超过 1 秒 | 百毫秒以内 | | 免查库比例 | 0% | 95% |

适用场景

适合:分库分表系统、有明确路由维度、可控制 ID 生成逻辑

不适合:小数据量、路由维度频繁变化、使用第三方 ID 服务

八、参考资料

  • Snowflake 算法 - Twitter
  • 分布式 ID 生成方案 - 美团 Leaf

---Carve_the_Code- 大型 OTA 平台订单系统开发

欢迎留言交流!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
2-0!英超创纪录:水晶宫+森林晋级,9队全进欧战16强,有望拿3冠

2-0!英超创纪录:水晶宫+森林晋级,9队全进欧战16强,有望拿3冠

体育知多少
2026-02-27 07:27:23
8记三分轰28+4,四号秀升历史第一!助飞鱼腩16战13胜蜕变成黑马

8记三分轰28+4,四号秀升历史第一!助飞鱼腩16战13胜蜕变成黑马

锅子篮球
2026-02-27 11:37:19
中到大雪,局部暴雪!河南迎大范围雨雪天气,局部积雪深度可达12厘米,气温骤降近10℃,出行需防滑防冻

中到大雪,局部暴雪!河南迎大范围雨雪天气,局部积雪深度可达12厘米,气温骤降近10℃,出行需防滑防冻

大象新闻
2026-02-27 08:46:16
藏得太深!星链离不开的7家中国公司,每一家都是全球顶尖!

藏得太深!星链离不开的7家中国公司,每一家都是全球顶尖!

Thurman在昆明
2026-02-26 16:52:11
这次荷兰没话说了!中方正式宣布:更换国内供应商,从此不再合作

这次荷兰没话说了!中方正式宣布:更换国内供应商,从此不再合作

晓劗就是我
2026-02-26 15:50:07
你占过最大的便宜是啥?网友:我也是,捡漏一个老公

你占过最大的便宜是啥?网友:我也是,捡漏一个老公

带你感受人间冷暖
2026-02-25 00:17:46
撒贝宁一家回武汉走完亲戚返京!老婆太漂亮,龙凤胎身高没有随爹

撒贝宁一家回武汉走完亲戚返京!老婆太漂亮,龙凤胎身高没有随爹

大中国
2026-02-26 18:05:01
新加坡住了一年才敢说:被吹上天的居者有其屋,其实是一地鸡毛

新加坡住了一年才敢说:被吹上天的居者有其屋,其实是一地鸡毛

天下霸奇
2026-02-24 08:09:25
沈阳富家千金身家十几亿,破产后卖2000万奢侈品,餐厅打工已看淡

沈阳富家千金身家十几亿,破产后卖2000万奢侈品,餐厅打工已看淡

牛牛叨史
2026-02-25 22:04:38
2026年正在崩盘的5个行业!聪明人早跑光了,傻子还在往里冲!

2026年正在崩盘的5个行业!聪明人早跑光了,傻子还在往里冲!

生活新鲜市
2026-02-17 10:37:00
湖人内讧的元凶?米切尔:球员们厌倦和他打球,保罗:他不防守!

湖人内讧的元凶?米切尔:球员们厌倦和他打球,保罗:他不防守!

你的篮球频道
2026-02-27 09:49:26
火箭113-108魔术2喜2忧!谢泼德+史密斯太好用,阿门+电风扇废了

火箭113-108魔术2喜2忧!谢泼德+史密斯太好用,阿门+电风扇废了

篮球资讯达人
2026-02-27 11:33:07
火箭19分逆转113-108客胜魔术,杜兰特40+8,谢泼德20分

火箭19分逆转113-108客胜魔术,杜兰特40+8,谢泼德20分

懂球帝
2026-02-27 11:34:34
“太恐怖,iPhone半夜自己给陌生人打47分钟电话!”

“太恐怖,iPhone半夜自己给陌生人打47分钟电话!”

都市快报橙柿互动
2026-02-25 11:28:41
《王牌特工》男主演“秃”然亮相惊呆网友,此前被称为“英伦男神”,头发茂密

《王牌特工》男主演“秃”然亮相惊呆网友,此前被称为“英伦男神”,头发茂密

红星新闻
2026-02-26 20:22:15
ESPN:40岁吉布森与灰熊签约2年,将成为NBA第35位40+球员

ESPN:40岁吉布森与灰熊签约2年,将成为NBA第35位40+球员

懂球帝
2026-02-27 09:37:05
一级军士长的地位有多高?相当于什么级别?为何师长见了都得敬礼

一级军士长的地位有多高?相当于什么级别?为何师长见了都得敬礼

观锐器
2026-02-26 22:20:40
最可惜的十位革命先烈,每一位都足以改变历史

最可惜的十位革命先烈,每一位都足以改变历史

【历史客栈】
2026-02-25 10:00:31
世预赛-中国台北男篮爆冷大胜韩国 陈盈骏13+5+4林庭谦18分

世预赛-中国台北男篮爆冷大胜韩国 陈盈骏13+5+4林庭谦18分

醉卧浮生
2026-02-26 20:55:30
18岁亚马尔新欢曝光:21岁网红 巴萨铁粉!取代闺蜜上位

18岁亚马尔新欢曝光:21岁网红 巴萨铁粉!取代闺蜜上位

叶青足球世界
2026-02-26 16:21:14
2026-02-27 11:51:00
冒泡泡的鱼儿
冒泡泡的鱼儿
每天带来社会资讯
403文章数 15333关注度
往期回顾 全部

科技要闻

英伟达业绩亮眼仍跌5% 两大因素成核心隐忧

头条要闻

特朗普在白宫"宴请"夺金的美国男子冰球队:吃麦当劳

头条要闻

特朗普在白宫"宴请"夺金的美国男子冰球队:吃麦当劳

体育要闻

一场必须要赢的比赛,男篮何止击败了裁判

娱乐要闻

继网暴谷爱凌后 美国欲没收其全部收入

财经要闻

魅族手机,终成弃子?

汽车要闻

宝马X5传承版发布:给经典G05的一场体面谢幕?

态度原创

游戏
时尚
旅游
艺术
军事航空

《FF7重制版》第三部顺利开发因仍然使用虚幻4

今年春天最美搭配:西装+半裙,怎么穿都好看!

旅游要闻

整整俩月!河南这家5A级景区对全国游客免门票

艺术要闻

紫气东来,好运一整年!

军事要闻

美国11架F-22隐形战机抵达以色列

无障碍浏览 进入关怀版