一道面试题
最近我在面试。有一次,面试官问了我一个电商秒杀的问题。
对于这个问题,无论前端如何耍猴(比如像以前小米页面弄个无限loading),怎么各种分布式消息队列,多级缓存,读写分离。到最后都会发现,数据库都会是最大的瓶颈。
淘宝商城的双十一搞了很多年,但说实话,每年都崩。也就是说,连支付宝这么优秀的团队,服务可用性也是有上限的。
(非)关系型数据库的解决方案
基本上都是数据库读写分离+乐观锁 or 悲观锁 的选择。
如果用乐观锁,那么尽量让实时数据流引擎(消息队列消费者)在尽可能短的时间内砍掉无效的订单。尽可能让用户在下单与付款之间过滤掉无效的订单。 俗称砍单。
如果用悲观锁,那么瓶颈必定是库存那部分的计算。对于这部分频繁更改的数据,建议走 Redis + 定期落盘。Redis 本身可以集群化,这样就可以最大程度地规避可用性问题。
土豪的解决方案
12306选择了 Pivotal GemFire分布式内存计算平台(Distributed In-memory computing)。
那么,用时间序列数据库怎么处理电商订单?
时间序列数据库的解决方案
在我之前写的文章中,我确立了不可变性作为时间序列数据库的第一属性。也就是说,对于时间序列数据库而言,只有 create 和 query ,没有 update 和 delete 。
那么,所有的数据,在时间序列数据库中都是一种状态机一般的存在。
比如商品库存表长这样:
| date | goodID | count |
|---|---|---|
| 2020-09-07 16:00 | 3 | 1 |
| 2020-09-07 16:01 | 3 | 0 |
订单长这一样子:
| date | orderID | userID | goodID | status |
|---|---|---|---|---|
| 2020-09-07 16:01 | 1 | 2 | 3 | 已下单 |
| 2020-09-07 16:02 | 1 | 2 | 3 | 已付款 |
数据库本身只是一个加了索引的表,写入之后记录不可变,数据库本身通过不变应万变。
事务靠实时数据流分析引擎去实现。
在库存运算方面,我建议这部分数据放内存里面,然后靠实时数据流分析引擎完成计算完事务后,再落盘时间序列数据库。也就是说,时间序列数据库存的是既定的结果。
不过关于这一块内容,以上只是一种设想。欢迎大家给我留言,一起讨论。
进一步思考
其实,与其用复杂的技术实现,还不如重新设计一个流程,规避超大并发的问题。
像后来天猫的双十一,前期会有一些锁定定金的订单,这些订单的支付时间是在1点之后,也就是说,从活动设计之初,我们就尽可能地错开了0点秒杀这个流量峰值。 这是一种时间换空间的做法。
结论
能够用钱解决的问题都不是问题。
参考链接
[1] 12306网站:分布式内存数据技术为查询提速75倍 https://cloud.tencent.com/developer/article/1074220
[2] 时间序列数据库的重要性 https://zhuanlan.zhihu.com/p/122145626
[3] 时间序列数据库才是未来 http://www.zeusro.com/2020/04/02/tsdb/
[4] 电商网站中,50W-100W高并发,秒杀功能是怎么实现的? - 九章算法的回答 - 知乎 https://www.zhihu.com/question/20978066/answer/1415294056
An Interview Question
Recently I’ve been interviewing. Once, an interviewer asked me about an e-commerce flash sale problem.
For this problem, no matter how the frontend monkeys around (like Xiaomi’s infinite loading page back in the day), no matter what distributed message queues, multi-level caching, or read-write separation you use, you’ll eventually find that the database is always the biggest bottleneck.
Taobao’s Double Eleven has been running for many years, but honestly, it crashes every year. That is to say, even a team as excellent as Alipay has an upper limit on service availability.
(Non-)Relational Database Solutions
Basically, it’s all about database read-write separation + optimistic locking or pessimistic locking.
If using optimistic locking, try to make the real-time data stream engine (message queue consumer) cut off invalid orders as quickly as possible. Filter out invalid orders between the user placing an order and paying. Commonly known as order cancellation.
If using pessimistic locking, the bottleneck must be the inventory calculation part. For this frequently changing data, I suggest using Redis + periodic disk writes. Redis itself can be clustered, which maximizes availability.
The Rich Guy’s Solution
12306 chose Pivotal GemFire Distributed In-memory Computing Platform.
So, how do you handle e-commerce orders with a time-series database?
Time-Series Database Solution
In my previous article, I established immutability as the first property of time-series databases. That is, for time-series databases, there’s only create and query, no update and delete.
So, all data in a time-series database exists like a state machine.
For example, the product inventory table looks like this:
| date | goodID | count |
|---|---|---|
| 2020-09-07 16:00 | 3 | 1 |
| 2020-09-07 16:01 | 3 | 0 |
Orders look like this:
| date | orderID | userID | goodID | status |
|---|---|---|---|---|
| 2020-09-07 16:01 | 1 | 2 | 3 | Ordered |
| 2020-09-07 16:02 | 1 | 2 | 3 | Paid |
The database itself is just an indexed table. After writing, records are immutable. The database itself handles everything through immutability.
Transactions are implemented by real-time data stream analysis engines.
For inventory calculations, I suggest keeping this data in memory, then after the real-time data stream analysis engine completes the transaction calculations, write it to the time-series database. That is, the time-series database stores predetermined results.
However, regarding this content, the above is just a concept. Feel free to leave me a message to discuss together.
Further Thoughts
Actually, rather than using complex technical implementations, it’s better to redesign a process to avoid massive concurrency problems.
Like Tmall’s Double Eleven later on, there will be some orders with locked deposits in advance. The payment time for these orders is after 1 AM. That is, from the beginning of the activity design, we tried to stagger the 0:00 flash sale traffic peak as much as possible. This is a time-for-space approach.
Conclusion
Problems that can be solved with money are not problems.
References
[1] 12306 Website: Distributed In-memory Data Technology Speeds Up Queries by 75x https://cloud.tencent.com/developer/article/1074220
[2] The Importance of Time-Series Databases https://zhuanlan.zhihu.com/p/122145626
[3] Time-Series Databases Are the Future http://www.zeusro.com/2020/04/02/tsdb/
[4] How is the flash sale feature with 500K-1M high concurrency implemented in e-commerce websites? - Jiuzhang Algorithm’s Answer - Zhihu https://www.zhihu.com/question/20978066/answer/1415294056
面接問題
最近、面接を受けています。ある時、面接官が私にEコマースの秒殺(フラッシュセール)の問題を聞きました。
この問題について、フロントエンドがどれだけ猿真似をしようと(例えば以前のXiaomiのページのように無限ローディング)、どれだけ分散メッセージキュー、マルチレベルキャッシュ、読み書き分離を使おうと、結局データベースが最大のボトルネックになることがわかります。
淘宝商城のダブルイレブンは何年も続いていますが、正直に言うと、毎年クラッシュしています。つまり、Alipayのような優秀なチームでさえ、サービスの可用性には上限があるということです。
(非)リレーショナルデータベースの解決策
基本的には、データベースの読み書き分離+楽観的ロックまたは悲観的ロックの選択です。
楽観的ロックを使う場合、リアルタイムデータストリームエンジン(メッセージキューコンシューマー)ができるだけ短い時間で無効な注文をカットするようにします。ユーザーが注文を出してから支払いまでの間に、できるだけ無効な注文をフィルタリングします。 俗に「注文カット」と呼ばれます。
悲観的ロックを使う場合、ボトルネックは必ず在庫計算の部分になります。この頻繁に変更されるデータについては、Redis + 定期的なディスク書き込みを推奨します。Redis自体はクラスタ化できるため、可用性の問題を最大限に回避できます。
金持ちの解決策
12306はPivotal GemFire分散インメモリコンピューティングプラットフォームを選択しました。
では、時系列データベースでEコマースの注文をどう処理するか?
時系列データベースの解決策
以前書いた記事で、私は不変性を時系列データベースの第一属性として確立しました。つまり、時系列データベースには、createとqueryしかなく、updateとdeleteはありません。
したがって、時系列データベース内のすべてのデータは、状態マシンのような存在です。
例えば、商品在庫テーブルは次のようになります:
| date | goodID | count |
|---|---|---|
| 2020-09-07 16:00 | 3 | 1 |
| 2020-09-07 16:01 | 3 | 0 |
注文は次のようになります:
| date | orderID | userID | goodID | status |
|---|---|---|---|---|
| 2020-09-07 16:01 | 1 | 2 | 3 | 注文済み |
| 2020-09-07 16:02 | 1 | 2 | 3 | 支払い済み |
データベース自体は単なるインデックス付きテーブルです。書き込み後、レコードは不変です。データベース自体は不変性を通じてすべてを処理します。
トランザクションはリアルタイムデータストリーム分析エンジンによって実装されます。
在庫計算については、このデータをメモリに保持し、リアルタイムデータストリーム分析エンジンがトランザクション計算を完了した後、時系列データベースに書き込むことを推奨します。つまり、時系列データベースには既に決定された結果が保存されます。
ただし、この内容については、上記は単なる概念です。ぜひメッセージを残して、一緒に議論しましょう。
さらなる考察
実際、複雑な技術実装を使うよりも、プロセスを再設計して、超大規模な同時実行の問題を回避する方が良いでしょう。
後期の天猫のダブルイレブンのように、事前にデポジットをロックした注文があります。これらの注文の支払い時間は1時以降です。つまり、アクティビティ設計の最初から、0時の秒殺トラフィックピークをできるだけずらすようにしました。 これは時間と空間を交換するアプローチです。
結論
お金で解決できる問題は問題ではない。
参考リンク
[1] 12306ウェブサイト:分散インメモリデータ技術がクエリを75倍高速化 https://cloud.tencent.com/developer/article/1074220
[2] 時系列データベースの重要性 https://zhuanlan.zhihu.com/p/122145626
[3] 時系列データベースこそが未来 http://www.zeusro.com/2020/04/02/tsdb/
[4] Eコマースウェブサイトで、50W-100Wの高同時実行、秒殺機能はどのように実装されているか? - 九章算法の回答 - 知乎 https://www.zhihu.com/question/20978066/answer/1415294056
Вопрос на собеседовании
Недавно я проходил собеседования. Один раз интервьюер задал мне вопрос о проблеме электронной коммерции с флэш-продажами.
Для этой проблемы, независимо от того, как фронтенд обезьянничает (например, как Xiaomi делала бесконечную загрузку раньше), какие бы распределенные очереди сообщений, многоуровневое кэширование или разделение чтения-записи вы не использовали, в конце концов вы обнаружите, что база данных всегда является самым большим узким местом.
Двойной одиннадцатый день Taobao проводится много лет, но, честно говоря, он падает каждый год. То есть, даже такая отличная команда, как Alipay, имеет верхний предел доступности сервиса.
Решения (не)реляционных баз данных
В основном это выбор между разделением чтения-записи базы данных + оптимистичной блокировкой или пессимистичной блокировкой.
Если использовать оптимистичную блокировку, то старайтесь сделать так, чтобы движок потоков данных в реальном времени (потребитель очереди сообщений) отсекал недействительные заказы как можно быстрее. Фильтруйте недействительные заказы между размещением заказа пользователем и оплатой. Обычно это называется отменой заказа.
Если использовать пессимистичную блокировку, то узким местом обязательно будет часть расчета запасов. Для этих часто изменяющихся данных рекомендуется использовать Redis + периодическую запись на диск. Redis сам по себе может быть кластеризован, что максимально избегает проблем с доступностью.
Решение богача
12306 выбрал платформу распределенных вычислений в памяти Pivotal GemFire.
Итак, как обрабатывать заказы электронной коммерции с помощью базы данных временных рядов?
Решение базы данных временных рядов
В моей предыдущей статье я установил неизменяемость как первое свойство баз данных временных рядов. То есть, для баз данных временных рядов есть только create и query, нет update и delete.
Таким образом, все данные в базе данных временных рядов существуют как конечный автомат.
Например, таблица запасов товаров выглядит так:
| date | goodID | count |
|---|---|---|
| 2020-09-07 16:00 | 3 | 1 |
| 2020-09-07 16:01 | 3 | 0 |
Заказы выглядят так:
| date | orderID | userID | goodID | status |
|---|---|---|---|---|
| 2020-09-07 16:01 | 1 | 2 | 3 | Заказано |
| 2020-09-07 16:02 | 1 | 2 | 3 | Оплачено |
Сама база данных - это просто индексированная таблица. После записи записи неизменяемы. Сама база данных обрабатывает все через неизменяемость.
Транзакции реализуются движками анализа потоков данных в реальном времени.
Для расчетов запасов я предлагаю хранить эти данные в памяти, а затем после того, как движок анализа потоков данных в реальном времени завершит расчеты транзакций, записать их в базу данных временных рядов. То есть, база данных временных рядов хранит предопределенные результаты.
Однако, относительно этого содержания, вышеизложенное - это всего лишь концепция. Пожалуйста, оставьте мне сообщение, чтобы обсудить вместе.
Дальнейшие размышления
На самом деле, вместо использования сложных технических реализаций, лучше перепроектировать процесс, чтобы избежать проблем с массовой конкурентностью.
Как в случае с Double Eleven Tmall позже, будут некоторые заказы с заблокированными депозитами заранее. Время оплаты для этих заказов - после 1 часа ночи. То есть, с самого начала проектирования активности мы старались максимально разнести пик трафика флэш-продажи в 0:00. Это подход обмена времени на пространство.
Заключение
Проблемы, которые можно решить деньгами, не являются проблемами.
Ссылки
[1] Сайт 12306: Технология распределенных данных в памяти ускоряет запросы в 75 раз https://cloud.tencent.com/developer/article/1074220
[2] Важность баз данных временных рядов https://zhuanlan.zhihu.com/p/122145626
[3] Базы данных временных рядов - это будущее http://www.zeusro.com/2020/04/02/tsdb/
[4] Как реализована функция флэш-продажи с высокой конкурентностью 50W-100W на сайтах электронной коммерции? - Ответ Jiuzhang Algorithm - Zhihu https://www.zhihu.com/question/20978066/answer/1415294056