跳到主要内容

9 篇博文 含有标签「architecture」

查看所有标签

Lyft 的营销自动化平台 Symphony

· 阅读需 4 分钟

获客效率问题:广告投放如何花更少的钱用更少的人得到更高回报?

具体来讲,Lyft 的广告投放要服务如下特点

  1. 管理基于地域的 campaign
  2. 数据驱动的增长:增长必须是规模化的、可测量的、可预测的
  3. 支撑起 Lyft 独特的增长模型,如图:

lyft growth model

主要的挑战是:难以规模化管理跨地域营销中的各个环节,广告竞标、预算、素材、激励、选择受众、测试等等。下图是营销者的一天:

营销者的一天

我们可以发现“执行”占去了大部分的时间,而更少的时间花在了更重要的“分析和决策”上。规模化意味着减少繁复的操作,让营销人员专注于分析与决策。

解决方案:自动化

为了降低成本,提高做实验的效率,需要

  1. 预测新用户是否对产品感兴趣
  2. 多渠道优化,有效评估和分配预算
  3. 方便地管理上千个 campaigns

数据由 Lyft 的 Amundsen 系统做增强学习。

自动化的部分包括:

  1. 更新 bid 的关键词
  2. 关掉效果不好的素材
  3. 根据市场改变 referrals values
  4. 找到高价值的用户 segment
  5. 在多个 campaign 中共享策略

构架

Lyft Symphony Architecture

技术栈:Apache Hive, Presto, ML platform, Airflow, 3rd-party APIs, UI.

具体的组成模块

LTV 预测模块

用户的终身价值是衡量渠道的重要标准,预算由 LTV 和我们愿意为该地区的获客付出的价格共同决定。

我们对新用户的认知有限,随着交互的增多,所提供的历史记录会更准确地预测。

一开始的特征值:

特征值

随着历史上的交互记录的积累,做出的判断就会越准确:

根据历史记录判断 LTV

预算分配模块

搞定了 LTV,接下来是根据价格定预算。拟合出 LTV = a * (spend)^b 形式的曲线以及周围的区间里类似参数的曲线。为了找到全局最优,需要付出一些随机性的代价。

预算计算

投放模块

分为两部分,一部分是调参者,一部分是执行者。调参者根据定价,设定基于渠道的具体的参数;执行者把这些参数执行到具体的渠道上。

有很多流行的投放策略,在各色的渠道中,是共通的:

投放策略

总结

要注意人的经验在系统中的重要性,否则会 garbage in, garbage out. 当人从繁琐的投放任务解放出来,专注于理解用户、理解渠道、理解自身要传达给受众的信息之后,就能够获得更好的投放效果——花更少的时间达到更高的 ROI。

构架入门

· 阅读需 5 分钟

什么是构架

构架是软件系统的形状。拿建筑物来举例子:

  • 范式 paradigm 是砖块
  • 设计原则是房间
  • 组件是建筑

他们共同服务于一个特定的目的,就像医院治疗病人,学校教育学生一样。

我们为什么需要架构?

行为 vs. 结构

每一个软件系统提供两个不同的价值给利益相关者:行为与结构。软件开发者必须确保这两项价值都要高

==由于其工作的需要,软件架构师更多地聚焦于系统的结构而不是特性和功能。==

终极目标——==减少每加一个新特性所需要耗费的人力成本==

架构服务于软件系统的整个生命周期,使其易于理解,开发,测试,部署和操作。 其目标是最小化每个业务用例的人力资源成本。

O’Reilly 出版的《软件架构》一书很好地介绍了这样五种基本的构架。

1.分层架构

分层架构是被广泛采用,也是被开发者所熟知的一种架构。因此,它也是应用层面上事实上的标准。如果你不知道应该使用什么架构,用分层架构就是不错的选择。

示例

  • TCP/IP模式:应用层 > 运输层 > 网际层 > 网络接口层
  • Facebook TAO网络层 > 缓存层(follower + leader) > 数据库层

优缺点:

  • 优点
    • 易于使用
    • 职责划分
    • 可测试性
  • 缺点
    • 庞大而僵化
      • 想要对架构进行调整、扩展或者更新就必须要改变所有层,十分棘手

2.事件驱动架构

任何一个状态的改变都会向系统发出一个事件。系统组件之间的通信都是经由事件完成的。

一个简化的架构包含中介(mdiator),事件队列(event queue)和通道(channel)。下图所示即为简化的事件驱动架构:

示例

  • QT:信号(signals)和槽(slots)
  • 支付基础设施:由于银行网关通常有较高的延迟,因此银行的架构中采用了异步技术

3.微核架构(aka Plug-in Architecture)

软件的功能被分散到一个核心和多个插件中。核心仅仅含有最基本的功能。各个插件之间互相独立并实现共享借口以实现不同的目标。

示例

  • Visual Studio Code 和 Eclipse
  • MINIX 操作系统

4.微服务架构

大型系统被解离成众多微服务,每一个都是单独部署的单位,他们之间通过RPCs进行通信。

uber architecture

示例

5.基于空间的架构

“基于空间的架构”这一名称来源于“元组空间”,“元组空间“有”分布式共享空间“的含义。基于空间的架构中没有数据库或同步数据库访问,因此该架构没有数据库的瓶颈问题。所有处理单元共享内存中应用数据副本。这些处理单元都可以很弹性地启动和关闭。

示例:详见 Wikipedia

  • 主要被使用Java的架构所采用:例如:JavaSpaces

流处理和批处理框架

· 阅读需 3 分钟

为什么有这种框架?

  • 为了在更短的时间内处理更多的数据。
  • 统一处理分布式系统中的容错问题。
  • 将任务简化抽象以应对多变的业务要求。
  • 分别适用于有界数据集(批处理)和无界数据集(流处理)。

批处理与流处理的发展史简介

  1. Hadoop 与 MapReduce。谷歌让批处理在一个分布式系统中像 MapRduceresult = pairs.map((pair) => (morePairs)).reduce(somePairs => lessPairs)一样简单。
  2. Apache Storm 与有向图拓扑结构。MapReduce 不能很好地表示迭代算法。因此,内森·马兹(Nathan Marz)将流处理抽象成一个由 spouts 和 bolts 组件构成的图结构。
  3. Spark 内存计算。辛湜(Reynold Xin)指出 Spark 在处理相同数据的时候比 Hadoop 少使用十倍机器的同时速度却快三倍
  4. 基于 Millwheel 和 FlumeJava 的谷歌数据流(Google Dataflow)。谷歌使用窗口化API同时支持批处理与流处理。
  1. Flink 快速采纳了 ==Google Dataflow== 以及 Apache Beam 的编程模式。
  2. Flink 对 Chandy-Lamport checkpointing 算法的高效实现。

这些框架

架构选择

若要用商业机器来满足以上的需求,有这些热门的分布式系统架构……

  • master-slave(中心化的):Apache Storm + zookeeper, Apache Samza + YARN
  • P2P(去中心化的):Apache s4

功能

  1. DAG Topology 用来迭代处理 -例如Spark 中的 GraphX, Apache Storm 中的 topologies, Flink 中的 DataStream API。
  2. 交付保证 (Delivery Guarantees)。如何确保节点与节点之间数据交付的可靠性?至少一次 / 至多一次 / 一次。
  3. 容错性。使用cold/warm/hot standby, checkpointing 或者 active-active 来实现容错。
  4. 无界数据集的窗口化API。例如 Apache 的流式窗口。Spark 的Window函数。Apache Beam 的窗口化。

不同架构的区别对照表

架构StormStorm-tridentSparkFlink
模型原生微批量微批量原生
Guarentees至少一次一次一次一次
容错性记录Ack记录Ack检查点检查点
最大容错
延迟非常低
吞吐量

使用半监督学习进行欺诈检测

· 阅读需 2 分钟

动机

在用户登录时利用用户和设备数据进行斗争

  1. ATO(账户接管)
  2. 僵尸网络攻击

ATO的检测难度从易到难

  1. 单个IP
  2. 同一设备上的IP
  3. 全球范围内的IP
  4. 10万个IP
  5. 针对特定账户的攻击
  6. 网络钓鱼和恶意软件

解决方案

半监督学习 = 无标签数据 + 少量有标签数据

为什么?学习准确性优于无监督学习 + 所需时间和成本低于监督学习

  • K均值:效果不佳
  • DBSCAN:效果更好。使用标签来
    1. 调整超参数
    2. 约束

挑战

  • 手动特征选择
  • 对抗环境中的特征演变
  • 可扩展性
  • 无在线DBSCAN

架构

反欺诈查询

反欺诈特征

生产设置

  • 批处理:7天的数据,每小时运行一次DBSCAN
  • 流处理:60分钟的移动窗口,运行流式K均值
  • 使用反馈信号成功率将聚类标记为好、坏或未知
  • 坏聚类:始终丢弃
  • 好聚类:小比例的尝试
  • 未知聚类:X%的尝试

再窥iOS架构模式

· 阅读需 4 分钟

我们为什么要在架构上费心思?

答案是:为了减少在每做一个功能的时候所耗费的人力资源

移动开发人员会在以下三个层面上评估一个架构的好坏:

  1. 各个功能分区的职责分配是否均衡
  2. 是否具有易测试性
  3. 是否易于使用和维护
职责分配的均衡性易测试性易用性
紧耦合MVC
Cocoa MVC❌ V和C是耦合的✅⭐
MVP✅ 独立的视图生命周期一般:代码较多
MVVM一般:视图(View)存在对UIKit的依赖一般
VIPER✅⭐️✅⭐️

紧耦合MVC

传统 MVC

举一个例子,在一个多页面的网页Web应用程序中,当你点击一个链接导航至其他页面的时候,该页面就会被全部重新加载。该架构的问题在于视图(View)与控制器(Controller)和模型(Model)是紧密耦合的。

Cocoa MVC

Cocoa MVC 是苹果公司建议iOS开发者使用的架构。理论上来说,该架构可以通过控制器(Controller)将模型(Model)与视图(View)剥离开。

Cocoa MVC

然而,在实际操作过程中,Cocoa MVC 鼓励大规模视图控制器的使用,最终使得视图控制器完成所有操作。

实际的 Cocoa MVC

尽管测试这样的耦合大规模视图控制器是十分困难的,然而在开发速度方面,Cocoa MVC是现有的这些选择里面表现最好的。

MVP

在MVP中,Presenter与视图控制器(view controller)的生命周期没有任何关系,视图可以很轻易地被取代。我们可以认为UIViewController实际上就是视图(View)。

MVC 的变体

还有另外一种类型的MVP:带有数据绑定的MVP。如下图所示,视图(View)与模型(Model)和控制器(Controller)是紧密耦合的。

MVP

MVVM

MVVM与MVP相似不过MVVM绑定的是视图(View)与视图模型(View Model)。

MVVM

VIPER

不同于MV(X)的三层结构,VIPER具有五层结构(VIPER View, Interactor, Presenter, Entity, 和 Routing)。这样的结构可以很好地进行职责分配但是其维护性较差。

VIPER

相较于MV(X),VIPER有下列不同点:

  1. Model 的逻辑处理转移到了 Interactor 上,这样一来,Entities 没有逻辑,只是纯粹的保存数据的结构。
  2. ==UI相关的业务逻辑分在Presenter中,数据修改功能分在Interactor中==。
  3. VIPER为实现模块间的跳转功能引入了路由模块 Router 。

iOS 架构模式再探

· 阅读需 3 分钟

为什么要关注架构?

答案:为了降低每个功能的人力资源成本

移动开发者从三个维度评估架构。

  1. 功能参与者之间责任的平衡分配。
  2. 可测试性
  3. 易用性和可维护性
责任分配可测试性易用性
紧耦合 MVC
Cocoa MVC❌ VC 耦合✅⭐
MVP✅ 分离的视图生命周期一般:代码较多
MVVM一般:由于视图依赖 UIKit一般
VIPER✅⭐️✅⭐️

紧耦合 MVC

传统 MVC

例如,在一个多页面的 web 应用中,一旦点击链接导航到其他地方,页面会完全重新加载。问题在于视图与控制器和模型紧密耦合。

Cocoa MVC

苹果的 MVC 理论上通过控制器将视图与模型解耦。

Cocoa MVC

实际上,苹果的 MVC 鼓励 ==庞大的视图控制器==。而视图控制器最终负责所有事情。

现实中的 Cocoa MVC

测试耦合的庞大视图控制器是困难的。然而,Cocoa MVC 在开发速度方面是最佳的架构模式。

MVP

在 MVP 中,呈现者与视图控制器的生命周期无关,视图可以轻松模拟。我们可以说 UIViewController 实际上就是视图。

MVC 变体

还有另一种 MVP:带有数据绑定的 MVP。正如你所看到的,视图与其他两个之间存在紧密耦合。

MVP

MVVM

它类似于 MVP,但绑定是在视图和视图模型之间。

MVVM

VIPER

与 MV(X) 相比,VIPER 有五个层次(VIPER 视图、交互器、呈现者、实体和路由)。这很好地分配了责任,但可维护性较差。

VIPER

与 MV(X) 相比,VIPER

  1. 模型逻辑转移到交互器,实体作为简单的数据结构保留。
  2. ==与 UI 相关的业务逻辑放入呈现者,而数据修改能力放入交互器==。
  3. 引入路由器负责导航。

Lambda 架构

· 阅读需 2 分钟

为什么要使用lambda架构?

为了解决大数据所带来的三个问题

  1. 准确性(好)
  2. 延迟(快)
  3. 吞吐量(多)

例如:以传统方式扩展网页浏览数据记录的问题

  1. 首先使用传统的关系数据库
  2. 然后添加一个“发布/订阅”模式队列
  3. 然后通过横向分区或者分片的方式来扩展规模
  4. 容错性问题开始出现
  5. 数据损坏(data corruption)的现象开始出现

关键问题在于AKF扩展立方体中,==仅有X轴的水平分割一个维度是不够的,我们还需要引入Y轴的功能分解。而 lambda 架构可以指导我们如何为一个数据系统实现扩展==。

什么是lambda架构

如果我们将一个数据系统定义为以下形式:

Query=function(all data)

那么一个lamda架构就是

Lambda Architecture

batch view = function(all data at the batching job's execution time)
realtime view = function(realtime view, new data)

query = function(batch view. realtime view)

==lambda架构 = 读写分离(批处理层 + 服务层) + 实时处理层==

Lambda Architecture for big data systems

将软件架构视为物理建筑

· 阅读需 2 分钟

什么是架构?

架构是软件系统的形状。将其视为物理建筑的全景。

  • 范式是砖块。
  • 设计原则是房间。
  • 组件是建筑。

它们共同服务于特定的目的,比如医院是为治愈病人而设,学校是为教育学生而设。

我们为什么需要架构?

行为与结构

每个软件系统为利益相关者提供两种不同的价值:行为和结构。软件开发人员负责确保这两种价值保持高水平。

::软件架构师由于其职位描述,更加关注系统的结构,而非其特性和功能。::

最终目标 - ==降低每个特性的人工资源成本==

架构服务于软件系统的整个生命周期,使其易于理解、开发、测试、部署和操作。 目标是最小化每个业务用例的人力资源成本。

设计非常大的(JavaScript)应用程序

· 阅读需 4 分钟

非常大的 JS 应用 = 很多开发者 + 大型代码库

如何处理很多开发者?

同理心

什么是 ==高级工程师==?没有初级工程师的高级工程师团队就是工程师团队

  1. 成为高级工程师意味着我能够解决几乎所有别人可能抛给我的问题。
  2. 让初级工程师最终成为高级工程师。

高级工程师的下一步是什么?

  1. 高级: “我知道我会如何解决这个问题”,因为我知道我会如何解决它,我也可以教别人怎么做。
  2. 下一个层次: “我知道别人会如何解决这个问题”

良好的编程模型

人们如何编写软件,例如 react/redux, npm。这里有一个影响所有大型 JS 应用的模型 - 代码分割。

  1. 人们必须考虑打包什么以及何时加载
  2. ==基于路由的代码分割==
  3. 但是,如果这还不够呢?
    1. 懒加载我们网站的每一个组件
    2. Google 是怎么做的?通过渲染逻辑和应用逻辑进行分割。==简单地在服务器端渲染一个页面,然后实际渲染的内容触发下载相关的应用程序包。== Google 不做同构渲染 - 没有双重渲染

如何处理大型代码库?

==代码可移除性/可删除性==

例如,CSS 在代码可移除性方面表现不佳

  1. 一个大的 CSS 文件。里面有这个选择器。谁真的知道它是否仍然与您的应用程序中的任何内容匹配?所以,您最终只是把它留在那里。
  2. 因此,人们创建了 CSS-in-JS

==不惜一切代价避免应用程序的中央配置==

  1. 坏例子
    1. 中央路由配置
    2. 中央 webpack.config.js
  2. 好例子
    1. 去中心化的 package.json

避免中央导入问题:路由器导入组件 A、B 和 C

  1. 为了解决这个问题,做 ==“增强”而不是“导入”==
  2. 然而,开发者仍然必须决定何时增强,何时导入。由于这可能导致非常糟糕的情况,我们使“增强”成为非法,没人可以使用它——只有一个例外:生成的代码。

避免基础包的垃圾堆

  1. 例如,基础包绝不应包含 UI 代码
  2. 通过禁止依赖测试解决此问题
  3. ==最直接的方法必须是正确的方法;否则添加一个测试以确保正确的方法。==

小心抽象

我们必须变得善于找到正确的抽象:同理心和经验 -> 正确的抽象