抖音技术能力大揭密!钜惠大礼、深度体验,尽在火山引擎增长沙龙,就等你来! 立即报名>> 了解详情
写点什么

挑战空中加油——1 号店 B2C 电商系统演进之路

2011 年 11 月 28 日

一、 面临的挑战

  • 发展速度快:每年近十倍的业务增长。既要及时响应业务发展的新需求,又要对系统平滑地进行技术升级重构,其难度堪比飞机空中加油。
  • 系统越来越复杂:
    1. 多渠道: 1 号店、掌上商城、第三方商城、多个分站
    2. 产品多样: 既有各类百货,也有各种虚拟票劵,还有机票充值等
    3. 多种经营模式: 有自营也有代售,有自配送也有第三方配送
    4. 多部门协同:采购、市场、销售、仓储、配送、客服等多部门需高效协同。
    5. 更智能化:随着业务和系统的复杂,各部门完全人工的运营决策变得十分低效,需要系统更加智能化。
  • 流量越来越大:流量每年增长 10 倍。

二、演进的策略

  • 新旧兼容,平滑升级:我们在实施任何技术升级时,首要强调的就是新系统要尽量兼容旧系统,以支持平滑升级。完全新的架构看似很吸引人,比较容易开发,但是不兼容原来的系统可能使得新系统风险非常大。所以 1 号店采用兼容的方式,滚动开发,把架构从原来的合成一团的小系统方式逐步改变为子系统独立,多数据库的模式。这好比一边高速飞行,一边加油。

  • 系统拆分:解决系统复杂性的唯一方法是分解。同时拆分后系统也使各自进行新的技术改造变得相对平滑。我们从终端渠道、业务逻辑、使用部门等多个维度进行了系统拆分。 例如:

  • 适当放弃一致性:在一些实时性要求不高的场合,我们适当放弃一致性要求。这样就可以充分利用多种手段来提高系统吞吐量,例如页面缓存、分布式数据缓存、数据库读写分离、查询数据搜索索引化。

  • 系统共用组件 Service 化:随着系统的分拆,各子系统间的重复代码越来越多,增加了很多不必要的维护成本。为提高代码的复用,降低维护成本,我们将多个子系统都需要用到的业务组件,进行了 Service 化。例如:

  • 中间件的研发使用:随着子系统和 Service 的增多,面临很多共同的技术性挑战。为降低应用系统人员的开发难度,我们在一些开源系统的基础上,研发了多个适应我们的中间件系统。例如:ESB 平台 (支持远程服务、异步消息)、分布式缓存、数据访问层等。大大简化了应用系统的开发。使用中间件后的总体示意图如下:

  • 系统自动化:为进一步提高运营效率,我们采用了很多自动化的设计理念,尽量减少人工配置的需要。例如:根据比价系统和策略自动调整商品价格,根据投放效果和策略自动调整广告投放,根据库存和销售预测自动安排采购等。

三、 经典案例:数据访问层 YhdDAL 1.0 设计与实施

1) 实施前旧系统状态与结构:

  • 整体已拆分有多个子系统和多个数据库。
  • 每个应用系统与多个数据库直连,使用 iBatis 进行 O/R Mapping。
  • 各应用系统代码中,使用 MemCached 服务器进行数据缓存。

2) 旧系统面临的问题:

  • 数据库连接数大,数据库服务器负担重。
  • Cache 代码繁琐: 本来一行代码的事需要写四五行。下面是典型的示例伪代码:
复制代码
result = getFromMemCached(key);
if (result != null) return result;
result = getFromDatabase(...);
writeMemCached(key, timeout);
return result;
  1. Cache 管理困难: 失效时间代码分散,不便管理。不同系统还容易 key 冲突。
  2. 数据分库和读写分离代码繁琐,某库故障时无法自动切换到可用库上。
  3. 系统 Service 化改造困难: 原 Web 层与 Dao 层代码耦合度高,不易实现 Service 化。拆分粒度太细连接数上升和故障概率增加,粒度太粗又效果不佳。
  4. 无法充分发挥 Cache 潜能:某个 Cache 项失效时,因前端的并发性会导致多次数据库请求。到期 Cache 无法延期使用,数据库故障时应用系统就立即故障。
    3) 备选方案的优缺点:
  • 基于 iBatis 本地扩展: 优点是工作量小。缺点是连接数和 Service 化等问题无法很好解决。
  • 基于 jdbc 驱动的 DAL:优点是客户端代码兼容性好,原代码改动工作量小。缺点是实现一个完整的 jdbc 驱动本身代价很高。
  • DAL 服务化,接口自定义: 优点是代码可控性高,各项需求特性易实现。缺点是有一定的迁移成本。

4) YhdDAL 1.0 设计方案:

  • 引入 DAL 服务器。应用系统仅访问 DAL 服务器,DAL 才连接数据库。
  • 客户端与 DAL 采用成熟的远程调用协议,接口简化为一个:
  • Object execute(functionName, parameters…)
  • 参数和返回值一律采用 Map 或基本类型,必要时可在客户端转换为 Java Bean
  • 支持 iBatis 格式的 sql 脚本定义和字段映射,以降低 iBatis 代码迁移成本。
  • DAL 层支持 JavaScript 脚本语言编写的类似存储过程的计算代码,简化业务层数据处理代码实现。
  • 因 DAL 服务器数量明显小于应用服务器数量,可有效减少数据库连接总数。
  • DAL 层封装 Cache 处理机制,一方面简化应用层代码。另一方面可采取缓存主动更新,失效延期等机制,充分发挥 Cache 潜能。
  • DAL 层封装分库和读写分离处理机制,简化应用层代码。
  • 参考数据库存储过程的设计思想,客户端仅传入过程名称和参数,DAL 层计算完成后返回结果。有利于实现 Service 化。
  • 大量简化应用层代码,很多简单的 Sevice/Dao 类可以完全省略。
  • 1.0 的缓存和负载均衡采用相对成熟简单方案,以降低风险。结构图如下:

5) 实施与升级过渡步骤:

  • 实现 DAL 核心功能。进行压力测试,评估系统性能。
  • 先对一个风险相对较小的应用系统进行改造,评估系统稳定性和改造成本。
  • 采用 iBatis 兼容模式,直接转换迁移旧代码。以快速将原有系统升级至新平台。
  • 采用新平台的设计理念,如读写分离、Service 化,进行旧代码改造。
  • 扩展 DAL 附加功能,如日志记录、权限控制、缓存优化、连接分组等。

通过一系列的方法与手段,1 号店基本实现了从小系统向大系统演变,使得 1 号店的系统能够支撑大量高并发的访问,同时满足了业务的需要。

关于作者

韩军,1967 年出生。1989 年毕业于上海交通大学计算机系, Monash MBA

  • 1 号店的第一个员工,CTO, 设计并开发了 1 号店所有的系统
  • 2004 年,设计了 美国著名的比较购物系统 smarter.com
  • 1999 年加入 51job,设计并开发了中国最为成功的工作网站与系统

感谢晁晓娟对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2011 年 11 月 28 日 00:0011645

评论

发布
暂无评论
发现更多内容

并发编程系列:阻塞队列的实现原理

程序员架构进阶

jdk 阻塞队列 七日更 28天写作 2月春节不断更

gradle中的build script详解

程序那些事

maven Gradle 程序那些事 构建脚本 构建程序

12周架构

FreeOcean

hadoop mapreduce YARN

LeetCode 数据库刷题 - 596. 超过5名学生的课

小马哥

七日更 二月春节不断更

职场心得

时间是一个人最好的证明

职场

千行百业中的我们,数字山河间的中国速度

脑极体

第四周作业

Ashley.

书画装裱物料与选择参考

boshi

业余爱好 七日更

Ray 1.0 架构解读

lipi

分布式计算 Apache Arrow ray

微信限量纪念版code封面来啦,速看领取方式

孙叫兽

视频号 2月春节不断更 孙叫兽 微信红包封面 纪念版

Elasticsearch 分词器

escray

elastic 七日更 死磕Elasticsearch 60天通过Elastic认证考试 2月春节不断更

聊聊金钱

熊斌

2月春节不断更

备战春招/秋招,开源社区系统 Echo,基于目前主流 Java Web 技术栈,并提供详细的开发文档和配套教程

飞天小牛肉

Java 开源 后端 springboot 2月春节不断更

7. ✎会查新华字典不?会。Python字典已经掌握了

梦想橡皮擦

Python 爬虫 2月春节不断更 python入门

【LeetCode】杨辉三角Java题解

HQ数字卡

算法 LeetCode 2月春节不断更

8. ㊙ Python 集合三板斧,滚雪球学 Python

梦想橡皮擦

Python 2月春节不断更 python入门

手摸手Go 深入剖析sync.Pool

Leo叔叔

go Go Concurrency Patterns sync.pool

这段时间学习机器学习的感受

Nydia

第四周笔记

Ashley.

前端冲刺必备指南-this/call/apply/bind(万字长文)

魔王哪吒

学习 程序员 面试 前端 2月春节不断更

写一个用例(第四周)

mas

走进 Tokio 的异步世界

lipi

rust 异步 tokio

Python优化机制:常量折叠

Python猫

Python

日记 2021年2月12日(周五)

Changing Lin

2月春节不断更

定投,积沙成塔的财富增长方式

boshi

理财 七日更

【STM32】5分钟了解STM32的串口通信

AXYZdong

硬件 stm32 2月春节不断更

GitHub 上的优质 Linux 开源项目,真滴牛逼!

JackTian

GitHub Linux 开源项目 运维工程师 2月春节不断更

为您收录的操作系统系列 - 进程管理(加餐)

Arvin

线程 进程 同步 生产者与消费者

【LeetCode】找到所有数组中消失的数字Java题解

HQ数字卡

算法 LeetCode 2月春节不断更

Elasticsearch query string 分词

escray

elastic 七日更 死磕Elasticsearch 60天通过Elastic认证考试 2月春节不断更

翻译:《实用的Python编程》01_02_Hello_world

codists

Python

Study Go: From Zero to Hero

Study Go: From Zero to Hero

挑战空中加油——1号店B2C电商系统演进之路-InfoQ