设计亚马逊按销售排名功能

1: 定义 Use Cases 和 约束

Use cases

作用域内的Use Case
  • Service 通过目录计算过去一周内最受欢迎的产品
  • User 通过目录去View过去周内最受欢迎的产品
  • Service 有高可用
作用域外
  • 整个电商网站
    • 设计组件(只是计算销售排名)

约束和假设

  • Traffic 不是平均分布的
  • 类目会被存进多个不同目录
  • 类目不能改变目录
  • 没有子目录,比如: foo/bar/baz
  • 结果会被定时更新
    • 更受换一个的产品或许需要更频繁的更新
  • 1000 万产品
  • 1000 目录
  • 10 亿交易 / 月
  • 1000 亿 请求 / 月
  • 100:1读写比率

计算使用量

  1. 每个 trasnaction 的 Size

    • created_at - 5 bytes
    • product_id - 8 bytes
    • category_id - 4 bytes
    • seller_id - 8 bytes
    • buyer_id - 8 bytes
    • quantity - 4 bytes
    • total_price - 5 bytes
    • Total: ~40 bytes
  2. 每个月有 40 GB 的新 trasnaction 内容

  • 40 字节 / transaction * 10 亿 transaction / 月
  • 1.44 TB 新 transaction 内容 / 3 年
  • 假设大部分是新的交易,而不是更新已经存在的
  1. 平均 400 transaction / s
  2. 平均 40000 读请求 / s

便利转换指南:

  • 每个月有250万秒
  • 1 request / s = 250 万 请求 / 月
  • 40 request / s = 1 亿请求每月
  • 400 request / s = 10 亿请求每月

2:创建一个High Level设计

Design

3: 设计核心组件

Use case: Service 通过category计算过去周内最受欢迎的产品

我们可以我们可以存储二进制 Sales API server的 log 文件进受管理的独享存储,比如 Amazon S3, 而不是管理我们自己的分布式文件系统

我们将假设这是一个简单的 log entry, tab delimited:

timestamp   product_id  category_id    qty     total_price   seller_id    buyer_id
t1          product1    category1      2       20.00         1            1
t2          product1    category2      2       20.00         2            2
t2          product1    category2      1       10.00         2            3
t3          product2    category1      3        7.00         3            4
t4          product3    category2      7        2.00         4            5
t5          product4    category1      1        5.00         5            6

Sales Rank Service 会使用 MapReduce, 使用这个 Sales API Sever的 log 文件作为输入,而且结果会被写进聚合表 sales_rank. 我们应该讨论数据库是选用SQL 还是NoSQL.

我们将使用多步骤的 MapReduce:

  • Step1: 转移数据到 `(category, produce_id), sum(quantity)
  • Step2: 执行分布式排序
class SalesRanker(MRJob):

    def within_past_week(self, timestamp):
        """Return True if timestamp is within past week, False otherwise."""
        ...

    def mapper(self, _ line):
        """Parse each log line, extract and transform relevant lines.

        Emit key value pairs of the form:

        (category1, product1), 2
        (category2, product1), 2
        (category2, product1), 1
        (category1, product2), 3
        (category2, product3), 7
        (category1, product4), 1
        """
        timestamp, product_id, category_id, quantity, total_price, seller_id, \
            buyer_id = line.split('\t')
        if self.within_past_week(timestamp):
            yield (category_id, product_id), quantity

    def reducer(self, key, value):
        """Sum values for each key.

        (category1, product1), 2
        (category2, product1), 3
        (category1, product2), 3
        (category2, product3), 7
        (category1, product4), 1
        """
        yield key, sum(values)

    def mapper_sort(self, key, value):
        """Construct key to ensure proper sorting.

        Transform key and value to the form:

        (category1, 2), product1
        (category2, 3), product1
        (category1, 3), product2
        (category2, 7), product3
        (category1, 1), product4

        The shuffle/sort step of MapReduce will then do a
        distributed sort on the keys, resulting in:

        (category1, 1), product4
        (category1, 2), product1
        (category1, 3), product2
        (category2, 3), product1
        (category2, 7), product3
        """
        category_id, product_id = key
        quantity = value
        yield (category_id, quantity), product_id

    def reducer_identity(self, key, value):
        yield key, value

    def steps(self):
        """Run the map and reduce steps."""
        return [
            self.mr(mapper=self.mapper,
                    reducer=self.reducer),
            self.mr(mapper=self.mapper_sort,
                    reducer=self.reducer_identity),
        ]

这个结果将变成下面的 sorted list, 我们可以插入 sales_rank 表中:

(category1, 1), product4
(category1, 2), product1
(category1, 3), product2
(category2, 3), product1
(category2, 7), product3

sales_rank table 会有如下的结构:

id int NOT NULL AUTO_INCREMENT
category_id int NOT NULL
total_sold int NOT NULL
product_id int NOT NULL
PRIMARY KEY(id)
FOREIGN KEY(category_id) REFERENCES Categories(id)
FOREIGN KEY(product_id) REFERENCES Products(id)

我们将创建一个index在id, category_id, and product_id 上去加速查询(log 时间而不是扫描整张表)
,而且放进数据去内存。从内存中序列化的读取数据需要250微妙,当从SSD读取需要4倍,从磁盘读取需要80倍。

Use Case: User 通过目录查看过去一周内最受欢迎的产品
  • Client 发送请求到Web Server
  • Web Server 转发请求到 Read API server
  • Read API server 从数据库表 sales_rank 重读取数据

我们可以使用如下Rest API:

$ curl https://amazon.com/api/v1/popular?category_id=1234

Response:

{
    "id": "100",
    "category_id": "1234",
    "total_sold": "100000",
    "product_id": "50",
},
{
    "id": "53",
    "category_id": "1234",
    "total_sold": "90000",
    "product_id": "200",
},
{
    "id": "75",
    "category_id": "1234",
    "total_sold": "80000",
    "product_id": "3",
}

4: 扩展设计

Extend Design

分析数据库可以使用数据仓库解决方案,如Amazon Redshift或Google BigQuery。

我们可能只想在数据库中存储有限时间段的数据,而将剩余数据存储在数据仓库或对象存储中。像亚马逊S3这样的对象存储可以轻松应对每月40 GB新内容的限制。

为了解决每秒 40,000 个平均读取请求(峰值更高),流行内容(及其销售排名)的流量应由内存缓存而不是数据库处理。内存缓存对于处理分布不均的流量和流量尖峰也很有效。由于读取量很大,SQL 读取副本可能无法处理缓存缺失。我们可能需要采用额外的 SQL 扩展模式。

对于单个SQL写主从架构来说,每秒400次平均写入(峰值更高)可能很困难,这也表明需要额外的扩展技术。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/340505.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

经典面试题-死锁

目录 1.什么是死锁? 2.形成死锁的四个必要条件 3.死锁的三种情况 第一种情况: 举例: 举例: 第二种情况:两个线程 两把锁 举例: 第三种情况:N个线程 M把锁 哲学家进餐问题 1.什么是死锁&…

java黑马学习笔记

数组 变量存在栈中&#xff0c;变量值存放在堆中。 数组反转 public class test{public static void main(String[] args){//目标&#xff1a;完成数组反转int[] arr {10,20,30,40,50};for (int i 0,j arr.length - 1;i < j;i,j--){int tep arr[j]; //后一个值赋给临时…

【Linux】解决普通用户无法进行sudo提权

当某个普通用户进行sudo指令提权的时候&#xff0c;可能存在无法操作的问题&#xff0c;如下图&#xff1a; 这个图中有一个细节&#xff0c;我们使用sudo进行提权的时候&#xff0c;用的可是zhangsan的密码&#xff0c;因此有人可能会有疑问&#xff0c;这不是有问题吗&#x…

爬虫-selenium自动化(3)-验证码

#验证码分很多种&#xff0c;奇葩也无处不在:哪个是真茅台&#xff0c;红绿灯&#xff0c;摩托车......(我是个人都看不出来) (๑﹏๑) #本节内容为selenium自动化实现验证码通过-------字符验证码&#xff0c;点触验证码。 验证码介绍 字符验证码案例 点触验证码案例

如何在WordPress网站中添加多语言搜索(2种简单方法)

您想在WordPress网站中添加多语言搜索吗&#xff1f; 如果您有一个多语言 WordPress 网站&#xff0c;那么添加多语言搜索功能可以帮助用户通过使用自己的语言进行搜索来更快地找到信息。 在本文中&#xff0c;我们将向您展示如何在 WordPress 中轻松添加多语言搜索&#xff…

Springboot常见报错及解决方案

1、多模块项目无法启动&#xff0c;报错Failed to execute goal on project*: Could not resolve dependencies for project 2、报错找不到符号&#xff08;在多moudle调用的时候&#xff0c;公共模块新增了东西的时候发生&#xff09; Rebuild项目 3、切换分支一开始跑不了的…

PowerShell install 一键部署grafana

grafana 前言 Grafana 是一款开源的数据可视化和监控仪表盘工具。它提供了丰富的数据查询、可视化和报警功能,可用于实时监控、数据分析和故障排除等领域。 通过 Grafana,您可以连接到各种不同的数据源,包括时序数据库(如 Prometheus、InfluxDB)和关系型数据库(如 MySQ…

解决ssh登录Permission denied, please try again

现象截图如下&#xff1a; 确定root的密码是正确的&#xff0c;最后的原因找到了&#xff0c;是远程的服务器&#xff0c;禁用了root账户可以被远程访问的权限。开启操作如下&#xff1a; 1.编辑配置文件 vi /etc/ssh/sshd_config 2.文件中找到PermitRootLogin #PermitRoo…

静态路由实验

一&#xff1a;实验内容 二&#xff1a;实验分析 &#xff08;一&#xff09;&#xff1a;实验要求 1、R6为ISP&#xff0c;接口IP地址均为公有地址&#xff1b;该设备只能配置IP地址&#xff0c;之后不能再对其进行其他任何配置&#xff1b; 2、R1-R5为局域网&#xff0c…

鸿蒙开发(七)添加常用控件(上)

相信大家已经对鸿蒙开发的布局有了基本的了解。之前我们提到过&#xff0c;一个好的UI&#xff0c;离不开选择合理的布局。当然&#xff0c;也离不开适当的控件。本篇文章&#xff0c;带着大家一起学习下如何在页面里面添加常用的控件。由于控件较多&#xff0c;我会分为两篇文…

HarmonyOS SDK,助力开发者打造焕然一新的鸿蒙原生应用

鸿蒙生态千帆启航仪式于1月18日正式启动。从2019年HarmonyOS正式发布到2020年“没有人能够熄灭漫天星光”&#xff0c;今天&#xff0c;满天星光终汇成璀璨星河&#xff0c;HarmonyOS NEXT鸿蒙星河版重磅发布&#xff0c;带来了全新架构、全新体验、全新生态。作为支撑鸿蒙原生…

设计模式——1_5 享元(Flyweight)

今人不见古时月&#xff0c;今月曾经照古人 ——李白 文章目录 定义图纸一个例子&#xff1a;可以复用的样式表绘制表格降本增效&#xff1f;第一步&#xff0c;先分析 变化和不变的地方第二步&#xff0c;把变化和不变的地方拆开来第三步&#xff1a;有没有办法共享这些内容完…

C++(Qt)软件调试---静态分析工具clang-tidy(18)

C(Qt)软件调试—静态分析工具clang-tidy&#xff08;18&#xff09; 文章目录 C(Qt)软件调试---静态分析工具clang-tidy&#xff08;18&#xff09;1、概述2、clang-tidy基本用法3、目前已有检查项4、Qt Creator中安装clang-tidy5、Qt Creator中使用clang-tidy6、Clang-Tidy配置…

66.Go从零搭建一个orm框架【简版】

文章目录 一&#xff1a;前置学习1、 为什么要用orm2、Golang里面是如何原生连接MySQL的3、ORM框架构想 二: 开始造1、连接Connect2、设置/读取表名Table/GetTable3、新增/替换Insert/Replace4、条件Where5、条件OrWhere6、删除Delete7、修改Update8、查询9、设置查询字段Field…

Linux Shell alias的简单用法:给shell起别名

alias&#xff1a;显示该用户所有起过别名的命令 alias lla‘ls -al’&#xff1a;给ls -al起别名为lla unalias lla&#xff1a;取消lla的别名 1、该命令所有的操作只对个人用户生效&#xff0c;给普通用户起的别名在root用户下不生效&#xff0c;只有回到普通用户才生效。 2…

解决Git添加.gitignore文件后不生效的问题

1. 问题描述 如上图所示&#xff0c;在已存在.gitignore文件且已经提交过的Git管理的项目中&#xff0c;其中.class、.jar文件以及.idea目录内的内容全部都还是被Git管理了&#xff0c;可见.gitignore文件并没有生效。 2. 原因发现 .gitignore文件只能作用于 Untracked Files…

Kafka 问题排查

订单宽表数据不同步 事情的起因是专员在 ze app 上查不到订单了&#xff0c;而订单数据是从 mysql 的 order_search_info 查询的&#xff0c;order_search_info 表的数据是从 oracel 的 BZ_ORDER_INFO 表同步过来的&#xff0c;查不到说明同步有问题 首先重启&#xff0c;同步…

linux性能优化-磁盘I_O优化

1.文件系统 1.1.文件系统的工作原理 文件系统是在磁盘的基础上&#xff0c;提供了一个用来管理文件的树状结构。 接下来我们就看看Linux 文件系统的工作原理。 1.1.1索引节点和目录项 在 Linux 中一切皆文件 ,文件系统,本身是对存储设备上的文件&#xff0c;进行组织管理的…

提升认知,推荐15个面向开发者的中文播客

前言 对于科技从业者而言&#xff0c;无论是自学成才的程序员&#xff0c;还是行业资深人士&#xff0c;终身学习是很有必要的&#xff0c;尤其是在这样一个技术快速迭代更新的时代。 作为一个摆脱了时间和空间限制的资讯分享平台&#xff0c;播客&#xff08;Podcast&#x…

Parasoft C++Test安装指南_含独立版和插件版

文章目录 前言一、Windows环境下1. 安装独立版CTest2. 安装插件版CTest 二、Linux环境下1. 安装独立版CTest 总结 前言 CTest是Parasoft公司出品的一款可以针对C/C源代码进行静态分析、单元测试、集成测试的测试工具&#xff0c;在C/C白盒测试领域被广泛使用。本篇文章主要讲解…