关于uber:时隔3个月Uber-再遭数据泄露

在往年9月,Uber 就产生过一起数据泄露事件,只管黑客并无心动员大规模攻打或以此来获取巨额利益,但其胜利获取对 Uber 所有敏感服务的齐全管理员拜访权限仍令人后怕。而在上周,名为“UberLeak”的用户又在黑客论坛上公开了一个600Mb 的存档文件,其中蕴含来自 Uber 零碎的2000万条数据记录。泄露的数据包含可能蕴含与 Uber、Uber Eats 和第三方供应商应用的选定挪动治理平台 (MDM) 相关联的源代码的档案。  数据泄露状况新泄露的数据包含源代码、IT 资产治理报告、数据销毁报告、Windows 域登录名和电子邮件地址,以及其余公司信息。超过 77,000 名 Uber 员工的 Windows Active Directory 信息被公开。此外,与 Uber Eats 外卖平台相干的一个十分小的存档文件也被同一用户泄露,目前只蕴含一些测试数据。据 Uber 称,本次数据透露是因为第三方供应商 Tequivity 的网络安全破绽造成的,该平台帮助 Uber 进行资产治理并提供跟踪服务。黑客取得了对 Teqtivity AWS 备份服务器的拜访权限,该服务器为 Teqtivity 的客户存储数据。  员工数据安全与第三方平安提醒超过 77,000 名 Uber 员工的 Windows Active Directory 信息遭裸露,网络犯罪分子可能会利用此信息来发动针对 Uber 员工的简单网络钓鱼攻打。攻击者可能会试图诱使员工泄露敏感的公司信息,例如公司帐户的登录凭据。鉴于此状况,Uber 须要增强员工对网络钓鱼电子邮件的警觉意识。此类电子邮件可能假冒Uber IT Support人员,因而员工在回复之前间接与管理员或其余平安人员确认电子邮件的真实性。  为了更好地应答第三方及供应商带来的潜在平安威逼,企业能够将操作能力和管制映射到特定的攻打场景。这样平安业余人员可能更深刻地理解如何预防、检测和应答这些类型的威逼。此外,企业应继续监控其第三方网络安全情况,这样可能提供对整个攻击面的可见性,并有可能升高网络攻击的可能性。同时定期进行威逼模仿演习能够帮忙企业反抗和应答第三方威逼。企业还应审查第三方供应商的平安实际,并确保定期向员工提供网络安全意识培训和反网络钓鱼教育。  参考链接: https://www.securityweek.com/... https://www.cybertalk.org/202...

December 19, 2022 · 1 min · jiezi

关于uber:Hudi起源分析DEEPNOVA开发者社区

1、概述 Hudi(Hadoop Update Delete Incremental)官网介绍是为数据湖之上提供事务反对、行级别更新/删除(Row Level Update/deletes)和变更流(Change Stream)的一个数据湖框架,最早是由Uber开发于2016年,2017进入开源社区,并在2020年成为Apache 顶级我的项目。本文会从Hudi诞生背景条件登程,搞清楚Hudi最后是为了解决什么问题而呈现的。 2、近实时场景需要 随着大数据技术的倒退,逐步倒退出了两种比拟成熟的计算模型:一种是批处理模型,技术栈以Hadoop为代表,其特点是规模大,容错高,提早高,次要利用在离线的大规模剖析场景下;另一种是流解决模型,技术栈以Strom/Flink此类流解决框架为代表,其特点是提早非常低,次要利用在要求提早很低的实时场景下。这两种模型笼罩了绝大多数大数据的利用场景。 然而在流解决与批处理之间却存在一个含糊的边缘地带,即提早在5分钟~1小时的范畴,在这个范畴内,既能够用批处理技术也能够用流解决技术,称为近实时(Near Real-time)需要。比方过来若干分钟某些维度指标的变动统计。此类场景有有以下3个特点:1、对提早度要求在亚小时级别。2、数据来源于业务数据的统计分析(可能存在多表join)。3、数据在业务窗口期内会变动。 3、传统模型的解决形式 3.1、利用批处理解决近实时问题批处理模型面向离线计算场景,须要将数据从业务数据库导入数仓中。这个阶段采纳Select * From Where Condition查问数据的形式。Condition通常是工夫维度,并且抉择也会综合思考业务数据库的受影响水平来确定启动周期,个别抉择隔天的凌晨业务量小的时间段拉取前一天的数据。数据导入实现后,再进行计算作业。 当应用批处理模型来解决解决近实时场景需要时,须要将调度周期设置为5分钟~1小时,这会带来一些问题。 3.1.1业务数据库负载 Select * from Condition 是一个代价很大的操作,失常批处理都会抉择业务量小的时候进行,防止影响业务。若为了反对近实时业务而将工作距离设为每分钟或每小时,会对业务数据库产生十分大的压力,有可能对业务产生影响。 3.1.2无奈疏忽的数据更新 同样是Select的问题,通过SQL查问数据的形式,获取变更数据须要额定的条件,并不是所有状况都能通过select取得变更数据。这在传统的离线解决场景下,产生的影响绝对较小。因为工夫范畴和启动周期都根本都在24H以上,绝大部分数据都不会再发生变化,且此时的数据量级为天级,数据量较大,即便有个别数据没有更新,对最终后果的影响水平也能够忽略不计。 然而在近实时场景下:因为启动周期的缩短,在这期间数据变动的概率大幅回升,同时数据总量在大幅缩小。此消彼长,最终后果的正确性就无奈失去保障。因而,在近实时场景下,批处理不反对数据更新的问题带来的影响,很有可能无奈被忽视。 3.2、利用流解决解决近实时问题 流解决次要用来应答提早要求低的实时计算场景,个别解决事件驱动的场景。因而,近实时场景天生能够间接应用流解决模型进行解决。但因为近实时场景的面向的事件工夫在5分钟1小时之间,相比拟于秒级工夫窗口的事件,利用流解决技术解决工夫窗口为5分钟1小时的数据时,会带来更大的老本。 3.2.1、更大的内存耗费 在解决业务数据库的Changelog中的update/delete语句时,须要基于对应的历史数据进行操作,这就须要将大量的数据载入内存中。而相比拟于解决秒级别的实时工作,近实时的工夫窗口因为在5分钟~1小时之间,这会导致近实时工作须要数倍甚至数十倍于秒级实时工作的内存资源。 3.2.2、峰谷资源错配 因为须要实时处理,解决工作须要始终运行,占用的资源大于批处理所需的资源。当业务顶峰来长期须要更多的资源用于撑持业务,这部分资源在业务低谷期来长期,就可能无奈失去高效利用,如果是云上零碎还好,能够将资源开释,如果是自建机房,那么多进去的资源就有可能造成节约。 3.3、小结 应用批处理和流解决两种解决模型解决近实时问题时,都有着各自不同的问题。批处理有无奈漠视的数据更新解决问题;流解决付出的老本较高,能够说是用牛刀杀鸡。这就难免会让人陷入抉择。那是否有一种解决模型,可能刚好满足需要呢?带着这样的谋求,一种新的解决模型被提了进去。 4、增量解决模型 4.1、根本构造增量解决模型面向近实时场景提出,它的根本构造能够认为是全量数据存储+增量数据处理。数据导入阶段采纳变更流捕捉将数据导入存储引擎中,在剖析计算阶段,查问增量数据进行后果计算 4.2、与传统解决模型的区别 4.2.1、与批处理的区别 与批处理相比,增量解决模型中的存储局部能够反对Update/Delete。这就能够在将批处理中数据摄取的形式从本来的查问数据这一种,拓展为既能够查问数据也能够解决Changelog。 4.2.2、与流解决的区别 与流解决相比,数据模型实质还是批,数据的解决须要周期性的导入和抽取计算,数据须要通过经验内存到磁盘再到内存的过程。 4.3、增量解决模型解决近实时场景的长处 既然增量解决模型面向近实时场景问题提出,那么增量解决在解决近实时场景时相比传统的两种解决模型具备哪些长处 4.3.1、可能应答数据变更 增量解决模型通过引入反对Update/Delete的存储引擎,具备了解决changelog的能力。在面对近实时场景中的变更数据流时,不会呈现数据无奈解决数据变更的问题 4.3.2、通过解决Changelog升高对业务库的影响 通过捕捉changelog来防止Select 查问的形式来升高对数据库的影响。通常生产级别的业务数据库(OLTP)的日志在数据库自身就须要通过生成,解决,落盘归档,主从同步等一系列动作来保障生产级别的HA。只须要额定的线程获取到changelog即可。此外,通常changelog只须要一条EL作业将其先导入Kafka中作为缓冲,增量模型的EL作业只须要生产Kafka中的changelog即可。相比拟于不定时的从业务数据库查问历史数据来说,负载大大降低。 4.3.3、通过批处理升高内存资源占用 增量解决模型将changelog写入存储引擎中,并从存储引擎查问须要剖析的数据,相比于流解决须要将数据加载至内存中,增量解决模型的数据不须要将数据加载至内存中。 4.3.4、通过微批计算取得更灵便的调度空间 微批的形式意味着数据导入和计算作业都不须要像流解决作业一样的继续运行,这也就留出了更多的可调度空间。在同样的计算资源下,借助正当的调度零碎能够同时包容更多的计算作业同时运行,为企业节省成本。 4.4、小结 增量模型能够说是一种非凡的批,也能够说是一种非凡的流。相比于流来说,它其实是周期性运行的批处理。相比拟于批来说,它具备了解决变更事件的能力。它在解决近实时场景需要时所体现出的长处,其实都是在谋求收益和老本之间的均衡。 5、总结 本文介绍了Hudi须要解决的问题—近实时场景的需要,并比拟了在大数据畛域中两种成熟的解决模型:流解决和批处理在解决此类场景中各自的不足之处。最初介绍了一种新的增量解决模型的解决形式。 增量解决模型以CDC的形式数据摄取,以微批的形式进行计算剖析,均衡了提早和老本。为了应答数据变更,须要引入数据更新/删除操作的反对。不难发现,其中的关键点就是在传统的大数据存储引擎之上提供数据更新/删除的能力,那么Hudi又是做了哪些具体的工作来反对增量解决的实现?请关注下期专题文章。 6、参考援用 Uber’s case for incremental processing on Hadoop – O’Reilly (oreilly.com)Uber’s Big Data Platform: 100+ Petabytes with Minute Latency - Uber Engineering BlogApache Hudi - The Data Lake Platform | Apache Hudi《大数据流解决架构 | 滴普科技FastData系列解读》

April 25, 2022 · 1 min · jiezi

关于uber:Uber实战案例基于Alluxio实现Presto缓存

如上图所示,在Uber,所有的决策都与数据无关。Presto以及其余各种查问引擎在Uber是被宽泛应用的。例如,经营团队在Dashboard等服务中大量应用了Presto,而UberEats和市场团队也依赖于这些查问后果来确定价格。此外,Presto也在Uber的合规部、增长营销部门、ad-hoc数据分析等场景下应用。上图展现了Uber外部的一些重要数据。总的来说,目前Presto在Uber外部有12K的月沉闷用户,每天要解决400K的查问并且要解决超过50PB的数据。在基础设施方面,Uber有2个数据中心,部署Presto在大概6千个节点和14个集群。Uber的Presto架构如上图所示。 最上层是UI/Client层,这其中包含了一些外部的Dashboard、Google Data Studio、Tableau等工具。此外,咱们还有一些后盾服务,应用了JDBC或其余的外部查问引擎来与Presto进行通信。 Proxy层,这一层负责从每一个Presto集群的coordinator拉取数据,以获取query数量、task数量、CPU和Memory使用率等信息,咱们也基于此判断应该将每个query调度到哪一个集群,来提供load-balancing和query-gating服务。 在底层,就是多个Presto集群,它们与底层Hive、HDFS、Pinot等进行通信。不同plugin或不同的数据集之间能够进行join操作。 此外,如图中的左右两侧所示,对上述架构中的每一层,咱们还有: 外部的监控服务 基于Kerberos Security提供的Security broker咱们的workloads能够大抵分为两类: Interactive:由数据科学家和工程师发送的query Scheduled:次要是Batch query,包含Dashboard查问、ETL查问等接下来,咱们简略介绍一下咱们对于业务上云的思考。 在过来的几年中,Uber的团队始终在思考如何上云和何时上云的问题,以及应该以怎么的布局(layout)来与云进行交互。这里以“what-how-why”模型列出了一些咱们认为值得探讨的点。 ● What:咱们有多种多样的利用布局,比方,利用方面,咱们有BI等利用;计算引擎方面,咱们不仅有Spark、Presto等。在云这个场景下,咱们还有许多云原生的抉择;存储方面,有gcs、S3、甚至是HDFS等多种抉择。 ● Why:对咱们来说,上云最重要的一个动机是,咱们心愿进步cost efficiency,更好地帮忙硬件设施来实现资源弹性扩大。同时,咱们也心愿能提供高可用、可扩展性、可靠性。 ● How:如何上云,这其中也有很多要点值得探讨。1.云能提供很多原生的个性,那么咱们就须要思考,这些个性如何能力与开源组件放弃互相统一;2.不同规模下的性能如何,Uber保护了一个十分大型的数据湖,因而性能数据对咱们和客户来说都是十分重要的;3.咱们也很器重云上的Security和Compliance问题;4.咱们也能够应用云提供的一些原生的个性,来补救咱们本人的“技术债”(Tech Debt)。上图展现了咱们对于Presto上云的布局。 基于这样的架构,咱们的解决方案能够扩大到不同云服务厂商中。这个目前只是作为咱们的长期布局和愿景,还处在十分初期的实现阶段。 总体上,咱们有Cloud集群和PROD集群。如图中右下角所示,咱们心愿大部分的数据还是在onPrem HDFS上。图中偏左的蓝色箭头代表了咱们做的一些事后测试,咱们在HDFS之上不加任何的缓存进行了一些试验,结果表明,网络流量十分高,从而带来了微小的开销。因而,咱们构想能应用云提供的服务,比方GCS或S3,来提供相似于L2 Cache的性能。咱们心愿能将数据集中的一些高拜访频率的重要数据放在这些“云上的L2 Cache”中,而对于云上的每个Presto集群,咱们打算利用本地的SSD来缓存一些数据,以晋升性能。总体来说,Alluxio的Cache Library与Alluxio Service的运行形式很不同。Alluxio Cache Library是在Presto worker外部的运行的本地缓存。咱们在默认的HDFS client的实现之上封装了一层,当读取HDFS的API被调用时,零碎首先会查看缓存空间,以通晓这是否为一次缓存命中(cache hit or miss)。如果缓存命中,则从本地的SSD中读取数据;否则,将从远端的HDFS中读取并将数据缓存在本地,这样在下一次读取时,咱们就能从本地读取。具体实现时,咱们将文件在HDFS中的门路作为key。这一过程中,缓存命中率对于整体的性能也有着十分重要的影响。 此外,为了判断缓存是否在Presto worker中,咱们还利用了Soft Affinity Scheduling。简而言之,这一性能能够确保将同样的key散发到同一个worker上,这样咱们就能够利用本地的library来确认每一次的数据读取是否命中了缓存。我将在下文对此进行具体介绍。 Uber的数据湖是十分大的,咱们每天解决50PB的数据,而Uber的数据湖相对超过了EB级别。同时,咱们有各种各样的表,比方Hudi表、Hive ETL等。咱们的数据大部分是依照日期的进行分区的。在Hudi中,因为Hudi会对文件的每个分区进行增量更新,因而同一个文件能够有不同的版本;Hive ETL会生成大量的Staging目录,在新的文件分区产生之后,这些staging目录就生效了。因而,随着时间推移,会有大量的冗余文件和文件更新,咱们须要对这一状况进行解决。对于缓存命中率。咱们每天都有大于3PB的非反复数据(distinct data)拜访,并且有约10%的频繁拜访数据(frequently accessed data)和约3%的热拜访数据(hot accessed data)。针对频繁拜访数据和热拜访数据,咱们心愿能构建一个图,来反映有多少不反复的表拜访(distinct table access)和联结表拜访(joint table access)。针对超大数据量所带来的挑战,咱们尝试构建一个过滤器布局(filter layout)——只缓存咱们须要的数据。一开始,咱们只会将热拜访数据放入缓存,在此之后,咱们逐渐扩充缓存空间。下面的图表展现了,在Presto的一次扫描或投影的查问中,因为有些partition/split/task可能十分大,因而有些HDFS节点的提早甚至达到了4至5秒。在生产环境中这一提早数据还会更大。这就使得数据节点提早产生了随机性(random latency)。这会给咱们生产环境中的查问带来重大的影响。如果咱们应用了缓存,HDFS缓存的数据就如上图所示。如果缓存可能命中,咱们就能获得更低的、更稳固的提早数据。试验中,咱们尝试应用本地缓存来获得百分百的缓存命中,来获得一个十分稳固的提早性能。另外,在上述的试验过程中,咱们也修复了一个Namenode listing相干的bug。目前在Presto中,Soft Affinity Scheduling是基于一个简略的“取模”算法来实现的,这一做法的害处是,如果呈现了节点的增删,那么整个缓存的键空间都须要进行更新。针对这一问题,当初曾经有了一种开源的解决方案,如果预约义的节点很多而出问题的节点很少的话,这一计划能够很好地解决该问题。然而在Uber,咱们遇到了新的问题:在咱们集群中,节点的数量不是固定的。所以咱们引入了基于一致性哈希的调度策略。咱们一共有400个节点,并为每个节点调配10个虚构节点。因而所有缓存的键就散布在一个有4000个节点的一致性哈希环上。对于这一改良机制,咱们曾经向开源社区提交了一个pull request,感兴趣的敌人能够试用此性能。初期的测试曾经实现,而且数据很不错。结果表明,如果数据在缓存中,对于那些依赖于SFP性能的查问而言,它们的性能能够失去大幅度晋升。咱们目前正在进行的工作包含: 工作一:在TPCDS benchmark上进行sf10k测试; 工作二:尝试从历史数据中剖析表或分区的拜访模式,找出最热的数据,从而能更好地设置缓存过滤器; 工作三:集成一些Dashboard和监控性能。其一,是对于所谓的“stale cache”的问题,即缓存空间中可能存储了旧的数据。只管咱们将缓存数据放在了Presto的本地SSD中,但真正的数据实际上寄存在GCS或者HDFS等,这些数据可能被其他人批改。比方,在应用Hudi table状况下,咱们常常能够看到,数据文件的“最初批改工夫戳”始终在变动。因而,如果咱们缓存了旧的数据,这就会导致查问的后果不精确。更坏状况下,因为新旧的page被混合在一起,当Presto传送Parquet或者ORC文件时,Presto中可能出现异常(Exception)。 其二,每天从HDFS中读取的不反复数据可能很大,但咱们没有足够的缓存空间来缓存所有数据。这就意味着在Uber的缓存过滤器之外,Alluxio须要eviction或allevation策略。此外,咱们还能够引入quota治理。咱们为每个table设置一个quota,对于那些热拜访的表,咱们设置一个更大的quota,而对于冷拜访的、不须要缓存的表,咱们能够设置一个十分小的甚至是0的quota。 其三,只管咱们曾经在本地缓存中寄存了元数据,但它仅仅在内存中而不在磁盘中。这就导致,当服务器启动时,无奈复原元数据。比方,Presto的服务器宕机重启后,服务器能够从新获取到数据,然而其中没有元数据,这可能导致quota治理被毁坏。因而,咱们提出了文件级元数据(File Level Metadata),其中保留了最初批改工夫和每个数据文件的scope。咱们须要将这些数据保留在磁盘中,使得Presto worker能在启动时获取这些数据。 ...

February 17, 2022 · 1 min · jiezi

关于uber:译-解密-Lyft-的AB实验最佳实践

网络效应与AB试验科技公司致力做出数据驱动的产品决策的趋势下,Lyft 也不能免俗。 正因为如此,在线试验,或者说 a / b 测试,变得无处不在。 AB测试太火了,以至于你可能会认为它是一个齐全解决的问题。 在这篇文章中,咱们将解释为什么理论状况相去甚远,在 Lyft 的拼车市场一样,零碎是依据网络动静倒退的。 正如咱们将看到的,天真地将用户划分为实验组和控制组可能会影响您所关怀的成果预计。 在试验完结后要求[数据科学家]对后果进行剖析。 [她]兴许能说出这个试验失败的起因。— paraphrasing R. A. Fisher, 1938. 简略地说,Fisher 的意思是,实验设计很重要。以至于一个大意的实验设计有时会导致无法回答感兴趣的问题的数据。 例如: 峰时定价补贴设想一下,如下图所示,整个 Lyft 网络被渺小的正方形区域所封装。 当用户 a 和 b 关上 Lyft 应用程序(大概在同一时间) ,左近只有一个驱动程序可用。 咱们称这种状况为供给有余。 图1. 典型的供给有余状况: 两名乘客和一名可用司机。 在这个例子中,两位乘客都可能接触到峰时价格 在这种状况下,Lyft 有时会采纳峰时定价来维持驾驶员的可用性。 峰时定价是以百分比示意的价格附加费,依据供给有余的水平(+ 25% ,+ 50% 等)能够有不同的价值。 为了简略起见,在这个例子中咱们假如峰时定价是二进制的 -- 要么有(在某个固定值) ,要么没有。 咱们还假如峰时定价的供应效应产生在一个比需要效应更慢的时间尺度上,因而咱们能够疏忽它们。 换句话说,乘客对峰时定价的反馈比司机快。 假如咱们想要评估 Lyft 补贴峰时定价的成果,即代表乘客领取峰时定价,甚至不向乘客展现。 咱们将在随后的图片中用绿色标记示意取得补贴的乘客。 这里有一个乏味的比喻是对于两个平行宇宙的。 咱们感兴趣的是事实世界和非事实世界之间的区别,前者是用户在供不应求的状况下取得峰时定价,后者是 Lyft 补贴峰时定价。 这两个宇宙如下图所示。 请留神,如果没有任何干涉,咱们只能察看到整体状况,咱们称之为全局管制。 另一方面,全局性的施策相当于对所有乘客给予峰时定价补贴。 ...

July 26, 2020 · 2 min · jiezi

关于uber:译-解密-Lyft-的AB实验最佳实践

网络效应与AB试验科技公司致力做出数据驱动的产品决策的趋势下,Lyft 也不能免俗。 正因为如此,在线试验,或者说 a / b 测试,变得无处不在。 AB测试太火了,以至于你可能会认为它是一个齐全解决的问题。 在这篇文章中,咱们将解释为什么理论状况相去甚远,在 Lyft 的拼车市场一样,零碎是依据网络动静倒退的。 正如咱们将看到的,天真地将用户划分为实验组和控制组可能会影响您所关怀的成果预计。 在试验完结后要求[数据科学家]对后果进行剖析。 [她]兴许能说出这个试验失败的起因。— paraphrasing R. A. Fisher, 1938. 简略地说,Fisher 的意思是,实验设计很重要。以至于一个大意的实验设计有时会导致无法回答感兴趣的问题的数据。 例如: 峰时定价补贴设想一下,如下图所示,整个 Lyft 网络被渺小的正方形区域所封装。 当用户 a 和 b 关上 Lyft 应用程序(大概在同一时间) ,左近只有一个驱动程序可用。 咱们称这种状况为供给有余。 图1. 典型的供给有余状况: 两名乘客和一名可用司机。 在这个例子中,两位乘客都可能接触到峰时价格 在这种状况下,Lyft 有时会采纳峰时定价来维持驾驶员的可用性。 峰时定价是以百分比示意的价格附加费,依据供给有余的水平(+ 25% ,+ 50% 等)能够有不同的价值。 为了简略起见,在这个例子中咱们假如峰时定价是二进制的 -- 要么有(在某个固定值) ,要么没有。 咱们还假如峰时定价的供应效应产生在一个比需要效应更慢的时间尺度上,因而咱们能够疏忽它们。 换句话说,乘客对峰时定价的反馈比司机快。 假如咱们想要评估 Lyft 补贴峰时定价的成果,即代表乘客领取峰时定价,甚至不向乘客展现。 咱们将在随后的图片中用绿色标记示意取得补贴的乘客。 这里有一个乏味的比喻是对于两个平行宇宙的。 咱们感兴趣的是事实世界和非事实世界之间的区别,前者是用户在供不应求的状况下取得峰时定价,后者是 Lyft 补贴峰时定价。 这两个宇宙如下图所示。 请留神,如果没有任何干涉,咱们只能察看到整体状况,咱们称之为全局管制。 另一方面,全局性的施策相当于对所有乘客给予峰时定价补贴。 ...

July 26, 2020 · 2 min · jiezi

大数据剖析思科IBM甲骨文Uber相继裁员寒冬将至

作者 | 硅谷洞察来源 | guigudiyixian小探听说思科(Cisco)中国又大裁员? 不过,就在这则新闻被刷屏的同时还真相未明的时候,唯一可以确认的是:Cisco已经向加州监管部门提交了文件,该公司裁减硅谷近500个工作职位。 其实,除了老牌巨头思科之外,IBM、Oracle等企业,此前裁员新闻也不断涌现: “今年6月,我被 IBM 裁了……我从 2010 年起就在 IBM 工作了,这家公司是它们 1987 年就收购的一家公司。” “我总是得到很好的评价,我得到了一个月遣散费,我怀疑我的辞退跟年龄有关……” 在http://thelayoff.com (裁员网)上,IBM 裁员的帖子随处可见像 61岁、60岁、57岁等两个月被裁掉的员工。这些员工的表现,却并非是“差生”。 知名科技媒体The Information 本月发布报告称,今年到目前为止,美国科技和媒体公司裁员人数远远超过 2018 年同期。从 IBM 高达 1700 人,到甲骨文的900人,乃至新上市的 Uber 都裁掉了 400 人,6 月裁员最多的 10 家公司中,有 7 家都属于科技企业。莫非是互联网又要遭遇下一个寒冬了吗?今天硅谷洞察就来说说,到底这些企业裁员背后的原因为何。 (6月在科技和媒体行业裁员总数最多的十家公司,来源:The Information) IBM:对云业务重组从而影响裁员 从总的裁员人数来看,无疑IBM 这个蓝色巨头裁员人数是最多的,今年 6 月整体裁员人数高达 1700 人。据消息人士称,这次高达 1700 名的裁员人数将占员工总数的 0.5%,这意味着IBM 的员工总数已达到 340000 人。 到底IBM 如此广泛裁员的原因是什么呢?众说纷纭,但从匿名员工、公司官方的说法来看,无疑跟云业务重组有关。 “因为IBM 没有投资自己的云技术,也没有倾听或关注市场对云消费模式的需求。这是降低成本以实现回报目标。” 这是某位匿名员工在 IBM 相关裁员的帖子下面,对IBM 的裁员原因进行了推测。这里指的是 IBM 前一阵子完成的对 Red Hat 云业务的收购。 ...

August 21, 2019 · 2 min · jiezi

Uber RPC 框架TChannel源码分析——多路复用的实现

原文:Uber RPC 框架TChannel源码分析——多路复用的实现声明tchannel-go版本为v1.12.0阅读本篇文章需要go语言,HTTP2——多路复用基础前言 UBER的RPC框架TChannel有一个闪亮点————多路复用。对于多路复用是如何实现一直都很好奇,所以抽了点时间看了TChannel多路复用的实现源码,并整理成这篇文章。文章主要从客户端【发起请求】到服务端【响应请求】一条完整请求来看多路复用整个生命周期的实现。客户端发起调用客户端调用我们把这个过程分成4个步骤: 1. 出站握手 2. 复用链接 3. 消息交换 4. 有序写入——发起请求出站握手github.com/uber/tchannel-go/preinit_connection.go #35func (ch *Channel) outboundHandshake(ctx context.Context, c net.Conn, outboundHP string, events connectionEvents) (_ Connection, err error) { …… msg := &initReq{initMessage: ch.getInitMessage(ctx, 1)} if err := ch.writeMessage(c, msg); err != nil { return nil, err } …… res := &initRes{} id, err := ch.readMessage(c, res) if err != nil { return nil, err } …… return ch.newConnection(c, 1 / initialID */, outboundHP, remotePeer, remotePeerAddress, events), nil} 在开始请求前,TChannel有一次握手,这次握手不是TCP/IP的三次握手,是为了确认服务端能够正常响应。 如果服务端能够正常响应,则这条TCP链接将会被复用。func (ch *Channel) newConnection(conn net.Conn, initialID uint32, outboundHP string, remotePeer PeerInfo, remotePeerAddress peerAddressComponents, events connectionEvents) *Connection { …… connID := nextConnID.Inc() …… c := &Connection{ channelConnectionCommon: ch.channelConnectionCommon, connID: connID, conn: conn, opts: opts, state: connectionActive, sendCh: make(chan *Frame, opts.SendBufferSize), …… inbound: newMessageExchangeSet(log, messageExchangeSetInbound), outbound: newMessageExchangeSet(log, messageExchangeSetOutbound), …… } …… // Connections are activated as soon as they are created. c.callOnActive() go c.readFrames(connID) go c.writeFrames(connID) return c} 当握手成功,这条链接随后会被放入Peer,以备其他请求使用。同时会启动2个协程,“readFrames” 用于读取服务端的响应,“writeFrames”把数据写入TCP链接里面,关于这2个协程的作用下面会详细介绍。复用链接github.com/uber/tchannel-go/peer.go #361func (p *Peer) getActiveConnLocked() (*Connection, bool) { allConns := len(p.inboundConnections) + len(p.outboundConnections) if allConns == 0 { return nil, false } // We cycle through the connection list, starting at a random point // to avoid always choosing the same connection. startOffset := peerRng.Intn(allConns) for i := 0; i < allConns; i++ { connIndex := (i + startOffset) % allConns if conn := p.getConn(connIndex); conn.IsActive() { return conn, true } } return nil, false} 复用链接是多路复用很关键的一步,和HTTP的复用不同,HTTP链接需要响应成功后才能被复用,而多路复用链接只要被创建了就能被复用。消息交换 —— 无序响应github.com/uber/tchannel-go/mex.go #306func (mexset *messageExchangeSet) newExchange(ctx context.Context, framePool FramePool, msgType messageType, msgID uint32, bufferSize int) (*messageExchange, error) { …… mex := &messageExchange{ msgType: msgType, msgID: msgID, ctx: ctx, //请求会等待Frame的写入 recvCh: make(chan *Frame, bufferSize), errCh: newErrNotifier(), mexset: mexset, framePool: framePool, } mexset.Lock() //保存messageExchange addErr := mexset.addExchange(mex) mexset.Unlock() …… mexset.onAdded() …… return mex, nil} 在客户端发起多个请求的时候,由于只有一个TCP链接,如何知道哪个响应是对应哪个请求?为了能够正确响应,TChannel使用了MessageExchange,一个请求对应一个MessageExchange。客户端会以stream id 为下标索引,保存所有的MessageExchange。当有一个请求时,它会阻塞在MessageExchange.recvCh, 响应回来会根据响应的stream id获取对应的MessageExchange, 并把帧放到 MessageExchange.recvCh 从而实现无序响应。有序写入——发起请求先写入队列github.com/uber/tchannel-go/reqres.go #139func (w *reqResWriter) flushFragment(fragment *writableFragment) error { …… frame := fragment.frame.(*Frame) …… select { …… case w.conn.sendCh <- frame: return nil }}获取队列数据,写入TCP链接github.com/uber/tchannel-go/connection.go #706func (c *Connection) writeFrames( uint32) { for { select { case f := <-c.sendCh: …… err := f.WriteOut(c.conn) …… } }} 在多路复用中,只有一条TCP链接,为了避免客户端同时写入链接里,TChannel先把帧写入队列“sendCh”,再使用一个消费者获取队列数据,然后有序写入链接里面。帧结构github.com/uber/tchannel-go/frame.go #107// A Frame is a header and payloadtype Frame struct { buffer []byte // full buffer, including payload and header headerBuffer []byte // slice referencing just the header // The header for the frame Header FrameHeader // The payload for the frame Payload []byte}// FrameHeader is the header for a frame, containing the MessageType and sizetype FrameHeader struct { // The size of the frame including the header size uint16 // The type of message represented by the frame messageType messageType // Left empty reserved1 byte // The id of the message represented by the frame ID uint32 //指Stream ID // Left empty reserved [8]byte} 帧被分为2部分,一部分是Header Frame(只有16字节);另一部分是Data Frame。这2部分数据按照一定格式标准转成二进制数据进行传输。服务端响应服务端响应我们把这个过程分成3个步骤: 1. 入站握手 2. 读取请求数据 3. 有序写入——响应结果入站握手github.com/uber/tchannel-go/preinit_connection.go #69func (ch *Channel) inboundHandshake(ctx context.Context, c net.Conn, events connectionEvents) (_ Connection, err error) { id := uint32(math.MaxUint32) …… req := &initReq{} id, err = ch.readMessage(c, req) if err != nil { return nil, err } …… res := &initRes{initMessage: ch.getInitMessage(ctx, id)} if err := ch.writeMessage(c, res); err != nil { return nil, err } return ch.newConnection(c, 0 / initialID /, "" / outboundHP */, remotePeer, remotePeerAddress, events), nil} 入站握手是对客户端出站握手的响应,当握手成功,服务端这边也会调用newConnection,启动“readFrames” 和 “writeFrames”协程,等待客户端请求。读取请求数据github.com/uber/tchannel-go/connection.go #615func (c *Connection) readFrames(_ uint32) { headerBuf := make([]byte, FrameHeaderSize) …… for { …… //先读头部 if _, err := io.ReadFull(c.conn, headerBuf); err != nil { handleErr(err) return } frame := c.opts.FramePool.Get() if err := frame.ReadBody(headerBuf, c.conn); err != nil { handleErr(err) c.opts.FramePool.Release(frame) return } //handle frame …… }} 在服务端会监听握手成功的链接,如果客户端发送了请求,就会读取链接里面的数据。读取分2步:先读取Header Frame(16字节) Header Frame 的长度固定为16字节,这里面有stream Id 和 Data Frame的长度再读取Data Frame 从Header Frame获取到 Data Frame的长度后,根据长度从链接读取指定的字节长度,就获取到正确的Data Frame。有序写入——响应结果 服务端的有序写入和客户端的有序写入是一样的功能,只是所处的角色不一样,这里不再重复。客户端获取响应结果客户端获取响应结果我们把这个过程分成2个步骤: 1. 读取响应结果 2. 找到MessageExchange响应读取响应结果 客户端获取响应结果和服务端的读取请求数据也是相同的功能,这里不再重复。找到MessageExchange响应github.com/uber/tchannel-go/mex.go #429func (mexset *messageExchangeSet) forwardPeerFrame(frame *Frame) error { …… mexset.RLock() mex := mexset.exchanges[frame.Header.ID] mexset.RUnlock() …… //把帧交给MessageExchange.recvCh if err := mex.forwardPeerFrame(frame); err != nil { …… return err } return nil} 在客户端发起调用时介绍过,它会阻塞在MessageExchange.recvCh,当响应回来时会根据stream Id(上面的frame.Header.ID) 找到对应的MessageExchange,并把frame放入recvCh,完成响应。这一步就体现在上面的代码。结语 至此UBER的RPC框架TChannel————多路复用介绍完,感谢UBER团队的贡献,让我收益很多。 ...

December 30, 2018 · 3 min · jiezi

[原] 解密 Uber 数据团队的大规模地理数据可视化神器:Deck.gl 与 H3

背景如何大规模可视化地理数据一直都是一个业界的难点,随着2015年起 Uber 在这一领域的发力,构建了基于 Deck.gl + H3 (deckgl,h3r) 的大规模数据可视化方案。一方面,极大地满足了大规模地理数据可视化的需求。另一方面,也极大地方便了数据科学家的可视化工作。在大规模空间轨迹分析、交通流量与供需预测等领域得到广泛应用,突破了原来leaflet架构中数据量(通常不会超过10W个原始点)的瓶颈问题,实现百万点绘制无压力,并且可以结合GPU实现加速渲染。地理单元:H3随着互联网出行公司的全球化扩张,越来越多的公司涌现出对地理单元划分的需求。一方面,传统的地理单元比如 S2和geohash,在不同纬度的地区会出现地理单元单位面积差异较大的情况,这导致业务指标和模型输入的特征存在一定的分布倾斜和偏差,使用六边形地理单元可以减少指标和特征normalization的成本。另一方面,在常用的地理范围查询中,基于矩形的查询方法,存在8邻域到中心网格的距离不相等的问题,也就是说六边形网格与周围网格的距离有且仅有一个,而四边形存在两类距离,而六边形的周围邻居到中心网格的距离却是相等的,从形状上来说更加接近于圆形。所以,基于hexagon的地理单元已经成为各大厂家的首选,比如 Uber 和 Didi 的峰时定价服务。在这样的背景下 Uber 基于六边形网格的地理单元开源解决方案 H3 应运而生,它使得部署 Hexagon 方案的成本非常低,通过UDF、R pacakge等方式可以以非常低的成本大规模推广。H3 的前身其实是 DDGS(Discrete global grid systems) 中的 ISEA3H,其原理是把无限的不规则但体积相等的六棱柱从二十面体中心延伸,这样任何半径的球体都会穿过棱镜形成相等的面积cell,基于该标准使得每一个地理单元的面积大小就可以保证几乎相同。然而原生的 ISEA3H 方案在任意级别中都存在12个五边形,H3 的主要改进是通过坐标系的调整将其中的五边形都转移到水域上,这样就不影响大多数业务的开展。下面是 ISEA3H 五边形问题的示例:#Include librarieslibrary(dggridR)library(dplyr)#Construct a global grid with cells approximately 1000 miles acrossdggs <- dgconstruct(spacing=1000, metric=FALSE, resround=‘down’)#Load included test data setdata(dgquakes)#Get the corresponding grid cells for each earthquake epicenter (lat-long pair)dgquakes$cell <- dgGEO_to_SEQNUM(dggs,dgquakes$lon,dgquakes$lat)$seqnum#Converting SEQNUM to GEO gives the center coordinates of the cellscellcenters <- dgSEQNUM_to_GEO(dggs,dgquakes$cell)#Get the number of earthquakes in each cellquakecounts <- dgquakes %>% group_by(cell) %>% summarise(count=n())#Get the grid cell boundaries for cells which had quakesgrid <- dgcellstogrid(dggs,quakecounts$cell,frame=TRUE,wrapcells=TRUE)#Update the grid cells’ properties to include the number of earthquakes#in each cellgrid <- merge(grid,quakecounts,by.x=“cell”,by.y=“cell”)#Make adjustments so the output is more visually interestinggrid$count <- log(grid$count)cutoff <- quantile(grid$count,0.9)grid <- grid %>% mutate(count=ifelse(count>cutoff,cutoff,count))#Get polygons for each country of the worldcountries <- map_data(“world”)#Plot everything on a flat mapp<- ggplot() + geom_polygon(data=countries, aes(x=long, y=lat, group=group), fill=NA, color=“black”) + geom_polygon(data=grid, aes(x=long, y=lat, group=group, fill=count), alpha=0.4) + geom_path (data=grid, aes(x=long, y=lat, group=group), alpha=0.4, color=“white”) + geom_point (aes(x=cellcenters$lon_deg, y=cellcenters$lat_deg)) + scale_fill_gradient(low=“blue”, high=“red”)p转化坐标系后:#Replot on a spherical projectionp+coord_map(“ortho”, orientation = c(-38.49831, -179.9223, 0))+ xlab(’’)+ylab(’’)+ theme(axis.ticks.x=element_blank())+ theme(axis.ticks.y=element_blank())+ theme(axis.text.x=element_blank())+ theme(axis.text.y=element_blank())+ ggtitle(‘Your data could look like this’)H3 中还提供了类似 S2 的六边形压缩技术,使得数据的存储空间可以极大压缩,在处理大规模稀疏数据时将体现出优势:地理数据可视化:Deck.gl在使用 Deck.gl 之前,业界通用的解决方案通常是另一个开源的轻量级地理数据可视化框架 Leaflet。Leaflet 经过十余年的积累已经拥有足够成熟的生态,支持各式各样的插件扩展。不过随着 Leaflet 也暴露出一些新的问题,比如如何大规模渲染地理数据,支持诸如 轨迹、风向、六边形网格的可视化。好在近年来 Mapbox 和 Deck.gl 正在着手改变这一现状。下面是一个具体的例子,如何可视化Hexagon:# 初始化devtools::install_github(“crazycapivara/deckgl”)library(deckgl)# 设置 Mapbox token,过期需要免费在 Mapbox 官网申请Sys.setenv(MAPBOX_API_TOKEN = “pk.eyJ1IjoidWJlcmRhdGEiLCJhIjoiY2poczJzeGt2MGl1bTNkcm1lcXVqMXRpMyJ9.9o2DrYg8C8UWmprj-tcVpQ”)# 数据集合sample_data <- paste0( “https://raw.githubusercontent.com/", “uber-common/deck.gl-data/”, “master/website/sf-bike-parking.json”)properties <- list( pickable = TRUE, extruded = TRUE, cellSize = 200, elevationScale = 4, getPosition = JS(“data => data.COORDINATES”), getTooltip = JS(“object => object.count”))# 可视化deckgl(zoom = 11, pitch = 45) %>% add_hexagon_layer(data = sample_data, properties = properties) %>% add_mapbox_basemap(style = “mapbox://styles/mapbox/light-v9”) 除了六边形之外 Deck.gl 也支持其他常见几何图形,比如 Grid、Arc、Contour、Polygon 等等。更多信息可以见官方文档: https://crazycapivara.github….地理仪表盘:结合 ShinyDeck.gl 结合 Shiny 后,可将可视化结果输出到仪表盘上:library(mapdeck)library(shiny)library(shinydashboard)library(jsonlite)ui <- dashboardPage( dashboardHeader() , dashboardSidebar() , dashboardBody( mapdeckOutput( outputId = ‘myMap’ ), sliderInput( inputId = “longitudes” , label = “Longitudes” , min = -180 , max = 180 , value = c(-90, 90) ) , verbatimTextOutput( outputId = “observed_click” ) ))server <- function(input, output) { set_token(‘pk.eyJ1IjoidWJlcmRhdGEiLCJhIjoiY2poczJzeGt2MGl1bTNkcm1lcXVqMXRpMyJ9.9o2DrYg8C8UWmprj-tcVpQ’) ## 如果token 过期了,需要去Mapbox官网免费申请一个 origin <- capitals[capitals$country == “Australia”, ] destination <- capitals[capitals$country != “Australia”, ] origin$key <- 1L destination$key <- 1L df <- merge(origin, destination, by = ‘key’, all = T) output$myMap <- renderMapdeck({ mapdeck(style = mapdeck_style(‘dark’)) }) ## plot points & lines according to the selected longitudes df_reactive <- reactive({ if(is.null(input$longitudes)) return(NULL) lons <- input$longitudes return( df[df$lon.y >= lons[1] & df$lon.y <= lons[2], ] ) }) observeEvent({input$longitudes}, { if(is.null(input$longitudes)) return() mapdeck_update(map_id = ‘myMap’) %>% add_scatterplot( data = df_reactive() , lon = “lon.y” , lat = “lat.y” , fill_colour = “country.y” , radius = 100000 , layer_id = “myScatterLayer” ) %>% add_arc( data = df_reactive() , origin = c(“lon.x”, “lat.x”) , destination = c(“lon.y”, “lat.y”) , layer_id = “myArcLayer” , stroke_width = 4 ) }) ## observe clicking on a line and return the text observeEvent(input$myMap_arc_click, { event <- input$myMap_arc_click output$observed_click <- renderText({ jsonlite::prettify( event ) }) })}shinyApp(ui, server)参考资料Uber H3 原理分析http://strimas.com/spatial/he…https://cran.r-project.org/we...https://en.wikipedia.org/wiki...http://www.pyxisinnovation.co...Large Scale Data Visualisation with Deck.gl and Shinyhttps://uber.github.io/h3/https://eng.uber.com/shan-he/https://eng.uber.com/keplergl/[译] 解密 Uber 数据部门的数据可视化最佳实践作为分享主义者(sharism),本人所有互联网发布的图文均遵从CC版权,转载请保留作者信息并注明作者 Harry Zhu 的 FinanceR专栏:https://segmentfault.com/blog…,如果涉及源代码请注明GitHub地址:https://github.com/harryprince。微信号: harryzhustudio商业使用请联系作者。 ...

October 22, 2018 · 3 min · jiezi