Flink:什么是 Watermark?

1、什么是 watermark

watermark 网上有翻译成水印,但更应该是水位线,即 Flink 接受的数据就相当于浮在水面的物体, 基于物理知识,水位线的高度只会升高不会降低,那么每当新数据进来,会重新计算水位线的时间,计算结果小于当前水位线时间,则不会更新现有的水位线。 当水位线到达窗口触发时间时才会触发窗口的计算。watermark 的意义在于数据无序传递的时候有一定容错率,如果晚来的数据在容错范围之内,会当做正常传递来处理。

乍一看还是懵逼,那么就看下面的分析。

2、什么是流处理

Flink 被称为真正的流式实时计算框架,其批处理中是流处理的特殊情况。而所谓的流处理,本质特点是在处理数据时,接受一条处理一条。而批处理则是累积数据到一定程度在处理。这是他们本质的区别。

假如我们自己写一个流式框架。我们该如何处理消息。如下,我们看到消息按照顺序一个个发送,接受后按照顺序处理,这是没有什么问题的。

如果消息不按照顺序发送,产生了乱序,这时候该怎么处理?

其实水位线 Watermark 就是其中的解决方案之一。

Read more
推荐系统技术演进趋势:从召回到排序再到重排

推荐系统技术,总体而言,与NLP和图像领域比,发展速度不算太快。不过最近两年,由于深度学习等一些新技术的引入,总体还是表现出了一些比较明显的技术发展趋势。这篇文章试图从推荐系统几个环节,以及不同的技术角度,来对目前推荐技术的比较彰显的技术趋势做个归纳。个人判断较多,偏颇难免,所以还请谨慎参考。

在写技术趋势前,照例还是对推荐系统的宏观架构做个简单说明,以免读者迷失在技术细节中。

实际的工业推荐系统,如果粗分的化,经常讲的有两个阶段。首先是召回,主要根据用户部分特征,从海量的物品库里,快速找回一小部分用户潜在感兴趣的物品,然后交给排序环节,排序环节可以融入较多特征,使用复杂模型,来精准地做个性化推荐。召回强调快,排序强调准。当然,这是传统角度看推荐这个事情。

但是,如果我们更细致地看实用的推荐系统,一般会有四个环节,如下图所示:

http://rna.6aiq.com/image-989fe182f8bf47cfa3c57ba5066a3d4a.jpeg

四个环节分别是:召回、粗排、精排和重排。召回目的如上所述;有时候因为每个用户召回环节返回的物品数量还是太多,怕排序环节速度跟不上,所以可以在召回和精排之间加入一个粗排环节,通过少量用户和物品特征,简单模型,来对召回的结果进行个粗略的排序,在保证一定精准的前提下,进一步减少往后传送的物品数量,粗排往往是可选的,可用可不同,跟场景有关。之后,是精排环节,使用你能想到的任何特征,可以上你能承受速度极限的复杂模型,尽量精准地对物品进行个性化排序。排序完成后,传给重排环节,传统地看,这里往往会上各种技术及业务策略,比如去已读、去重、打散、多样性保证、固定类型物品插入等等,主要是技术产品策略主导或者为了改进用户体验的。

那么,每个环节,从技术发展的角度看,都各自有怎样的发展趋势呢?下面我们分头说明。

Read more
HBase内存管理之MemStore进化论

Java工程中内存管理总是一个绕不过去的知识模块,无论HBase、Flink还是Spark等,如果使用的JVM堆比较大同时对读写延迟等性能有较高要求,一般都会选择自己管理内存,而且一般都会选择使用部分堆外内存。HBase系统中有两块大的内存管理模块,一块是MemStore ,一块是BlockCache,这两块内存的管理在HBase的版本迭代过程中不断进行过各种优化,接下来笔者结合自己的理解,将这两个模块的内存管理迭代过程通过几篇文章梳理一遍,相信很多优化方案在各个系统中都有,举一反三,个人觉得对内核开发有很大的学习意义。本篇文章重点集中介绍MemStore内存管理优化。

基于跳表实现的MemStore基础模型

实现MemStore模型的数据结构是SkipList(跳表),跳表可以实现高效的查询\插入\删除操作,这些操作的期望复杂度都是O(logN)。另外,因为跳表本质上是由链表构成,所以理解和实现都更加简单。这是很多KV数据库(Redis、LevelDB等)使用跳表实现有序数据集合的两个主要原因。跳表数据结构不再赘述,网上有比较多的介绍,可以参考。

JDK原生自带的跳表实现目前只有ConcurrentSkipListMap(简称CSLM,注意:ConcurrentSkipListSet是基于ConcurrentSkipListMap实现的)。ConcurrentSkipListMap是JDK Map的一种实现,所以本质上是一种Map,不过这个Map中的元素是有序的。这个有序的保证就是通过跳表实现的。ConcurrentSkipListMap的结构如下图所示:

基于ConcurrentSkipListMap这样的基础数据结构,按照最简单的思路来看,如果写入一个KeyValue到MemStore中,肯定是如下的写入步骤:

  1. 在JVM堆中为KeyValue对象申请一块内存区域。

  2. 调用ConcurrentSkipListMap的put(K key, V value)方法将这个KeyValue对象作为参数传入。

Read more
从一句情话来了解语言模型的发展

问题定义

一段文字,例如:今夜月色真美。代表的是什么含义?如果在春天温度适宜的 9、10 点站在阳台的人对你脱口而出地说出这句话,你会怎么理解这句话,亦或者你会怎么回应他(她)呢?

这句话是十九世纪末的文学家 夏目漱石对 I love you 的英译日标注结果(今夜は月が綺麗ですね)。根据他的标注 我爱你今夜月色真美 表达了相同的意义。但是计算机这么认为吗?输入 今夜月色真美,它理解这句话和 我爱你 是相似的含义吗?这个可以被归类为自然语言理解(NLU)领域的语义匹配问题。

众所周知在计算机中一切都是数字信号,那么如果想让计算机理解一句话的含义,解决 今夜月色真美我爱你 的语义匹配问题,那么先决问题是将一句话表示为一系列的数字信号。一个理所当然的想法是将语料库中的每一个词w用一个唯一的 n 维向量v=[v1​,v2​,…,vn​]来表达,那么数个向量的序列seq={v1​,v2​,…,vm​}就可以表达一句话,这一类方法就是词嵌入模型。本期文章通过对比这个 case 在 one-hotn-gramword2vecBERT 四种语言模型的结果,分析各个方法的优缺点。

one-hot

一个最简单的想法就是使用 one-hot 向量来表达一个词。具体流程:

  1. 遍历语料库,统计词的集合W,集合大小为K
  2. 将每个词在集合W中的下标的元素为 1,其他位置元素为 0,构建长度为K的 0-1 向量

假设我们对 今夜月色真美 的分词结果为:今夜、月色、真、美。那么使用 one-hot 向量就能将这个句子表示为4×K的 0-1 矩阵。我们假设语料库中一共有 10 个词:{我、爱、你、今夜、月色、真、美、今晚、漂亮、喜欢}。那么V今夜​=[0,0,0,1,0,0,0,0,0],V今晚​=[0,0,0,0,0,0,0,1,0,0],V我​=[1,0,0,0,0,0,0,0,0,0]。

one-hot 词嵌入方法优点在于简单,并且最大程度地保留了每个词的信息。但是缺点也很明显:

  1. 对于从未出现在语料库中的未登录词,无法进行兼容。假如词 需要编码,那么只能编码为零向量,否则需要对所有词向量进行更新,扩展向量维度。
  2. 丢失了词与词之间的相关信息。例如 今夜今晚 本身是相近语义的词,但是通过 one-hot 编码的向量差异并没有比 今夜 小。
Read more
Dataflow 模型

Dataflow 模型:是谷歌在处理无边界数据的实践中,总结的一套 SDK 级别的解决方案,其目标是做到在非有序的,无边界的海量数据上,基于事件时间进行运算,并能根据数据自身的属性进行 window 操作,同时数据处理过程的正确性,延迟,代价可根据需求进行灵活的调整配置。

DataFlow 模型核心

和 Spark 通过 micro batch 模型来处理 Streaming 场景的出发点不同,Dataflow 认为 batch 的处理模式只是 streaming 处理模式的一个子集。在无边界数据集的处理过程中,要及时产出数据结果,无限等待显然是不可能的,所以必然需要对要处理的数据划定一个窗口区间,从而对数据及时的进行分段处理和产出,而各种处理模式(stream,micro batch,session,batch),本质上,只是窗口的大小不同,窗口的划分方式不同而已。Batch 的处理模式就只是一个窗口区间涵盖了整个有边界的数据集这样的一种特例场景而已。一个设计良好的能处理无边界数据集的系统,完全能在准确性和正确性上做到和“Batch”系统一样甚至应该更好。

Read more
来美团3个月总结

来美团也三个月了,也渐渐习惯这边的风格。再流程制度上,有让我觉得很不错的地方,也有一些需要改善的地方。自己的能力模型上,还有哪些需要提高的,接下来自己需要在这些地方进步。

好的地方

  • 文档。在文档这方便做的挺好的,把工作中很多都能记录下来,比如会议纪要,产品PRD,技术方案,月度总结等,以及各个系统的详细文档等。而且也能搜到很多技术方案设计,能力模型等。这样比较详细的学习别人怎样去做的,怎样设计的。
  • 各个基础平台和系统。在这边不用什么都从头开始,公司提供了各种基础平台,比如服务发布的CI/CD工具,微服务的RPC框架,服务治理,熔断降级等系统。以及各种存储,KV存储,es平台,大数据平台等,让自己能够专注于业务,而不需要放很多精力在以来的平台开发运维上面。
  • 流程规范。大公司流程还是比较规范的,如开发上线流程,整套流程每一步都细化,大家按照这套流程开发。极大的规避掉一些因为个人理解偏差和信息对齐上面造成的上线问题,能够保质保量的进行新功能迭代上线。
  • 制定绩效合同,后面绩效根据此打,更大化的做得客观。
  • 因为我原来是做大数据平台的,更多的面向的是公司内部,而现在是面向用户。可以感受到这边对监控,线上问题的也紧要重视。(这个主要是我岗位的变化)
Read more
过去,未来

很快,已经大半年没写博客了,这半年内,一直再准备面试,找工作,终于在7月去了自己还认为不错的公司。也发现自己已经工作四年了。如果要给自己前四年以一个词语做总结的话,我想我会选择“混沌”这个词。

过去

在物理学上,混沌(chaos)是指确定性动力学系统因对初值敏感而表现出的不可预测的、类似随机性的运动。又称浑沌。英语词Chaos源于希腊语,原始 含义是宇宙初开之前的景象,基本含义主要指混乱、无序的状态。

而自己曾经的过往也是这样的随机飘荡。没有为自己制定一个人生目标,也不造为何而追求,是我之前很长一段时间的状态。主要体现在我认为的以下几点:

  • 没有制定人生规划。因为没有大方向,所以很多时候更偏向于随遇而安。
  • 工作单位随意性。和人生规划也有关,所以在面临单位的抉择方便没有去更加的努力。没有想好不同的单位能为我带来什么样的背景和能力。
  • 情感的随意性。在情感方面,自己并没有什么优势,所以更需要自己勇于去争取。而为此,需要去提高自己的设计能力,沟通表达能力,自己却没有过多的在意。
  • 到底想要什么。这个问题思考的不够深刻,因为道路上的一些阻碍,也造成前进方向的左右摇摆。
  • 勇敢去争取的心。无论在工作上,情感上,生活上,如果没有一颗勇敢去争取的心,人很容易颓废,然后陷入自我怀疑。社会因为信息的不对等,所以机会更容易给予勇敢去争取的人,而不去争取的人,却只能抱怨“他不如我,为啥是他”这种无聊的问题。
Read more
python协程

这些天,在标签调度上,可预见性的标签调度会越来越多,如果全由调度系统承载,调度系统压力增大,负责调度系统的同事担心会影响其他任务,遂在讨论下,决策开发一个简版的标签执行服务/脚本(相比现有调度系统,只保留任务执行控制,例如池化,并发控制等,任务编排,启动时间都由调度系统控制,整个执行服务就是调度系统的一个task)。而我对此持保持意见,我认为应该增强调度系统能力,2333。

既然决策已定,加上部门现在主要使用python,而调度系统也使用的是airflow,所以主要开发语言也定为python。对于此执行服务/脚本,希望能够并行的执行任务,并且能够控制每次在跑的任务数。调研了下python的并发模型,以及多线程的知识。很多说python多线程是鸡肋,而自己也不想引入第三方并发的库,又看到python支持协程,且相比线程轻量很多,代码易理解,遂最终选定使用协程来实现这个需求。

协程

网上对协程的解释众说纷纭,有说协程是一种用户态的轻量级线程,协程的调度完全由用户控制。wikipedia的定义:
协程是一个无优先级的子程序调度组件,允许子程序在特点的地方挂起恢复。但大家对协程的作用倒挺统一的:

  • 占用资源少,开个协程只需要K级别内存,而新开个线程则需要M级别
  • 线程之间的上下文切换,性能消耗大,而协程间切换非常快
  • 相比事件驱动模型的回调复杂性,协程易于理解,写协程代码就像写同步代码一样。
  • 协程的调度是协作式调度,需要协程自己主动把控制权转让出去之后,其他协程才能被执行到(很难像抢占式调度那样做到强制的 CPU 控制权切换到其他进程/线程)

历史的宿命

在互联网行业面临C10K问题时,线程方案不足以扛住大量的并发,这时的解决方案是epoll() 式的事件循环,nginx在这波潮流中顺利换掉apache上位。同一时间的开发社区为nginx的成绩感到震撼,出现了很多利用事件循环的应用框架,如tornado/ nodejs,也确实能够跑出更高的分数。而且python/ruby 社区受GIL之累,几乎没有并发支持,这时事件循环是一种并发的解放。然而事件循环的异步控制流对开发者并不友好。业务代码中随处可见的mysql/memcache调用,迅速地膨胀成一坨callback hell。这时社区发现了协程,在用户态实现上下文切换的工具,把epoll()事件循环隐藏起来,而且成本不高:用每个协程一个用户态的栈,代替手工的状态管理。似乎同时得到了事件循环和线程同步控制流的好处,既得到了epoll()的高性能,又易于开发。甚至通过monkey patch,旧的同步代码可以几乎无缝地得到异步的高性能,真是太完美了。

Read more
略微糟糕的2018

不在以流水形式记录,而网易云音乐年报体搞笑却不能展示更多。在朋友圈看了别人的发的年终总结,遂借鉴其模板。

2018年让你印象深刻的5件事情是什么?

  1. 定级答辩,完全暴露了自己的弱点,当大领导说自己的ppt很渣时,很懵逼。自己确实没太上心,做的少。虽然后来又重改了,但最终其实效果都不是很满意,包括答辩。表达能力以及技能包装能力都还需要多加练习。最后感谢领导的细心指导。
  2. 不应该老拿别人的弱点说事或者开玩笑。A之前说了个毫无依据的话被大家笑话,然后就竟然被大家拿出来说,以至于大家一旦把焦点给与他,他便有了种不舒服,即便知道大家也是寻乐。自己也会一直拿别人的弱点寻乐,虽然是玩笑,但别人的感受未必是玩笑。当然自己也会被拿着弱点一直攻击你,当然也是寻乐,但自己确实也有不爽,将心比心,也许有时候会意的鼓励会更好。以后自己应该多注意,少娱乐他人的弱点,多提升自己的弱点。
  3. 接近年底,回家办理贷款手续,正好外婆过生,一大家人和和睦睦,开开心心的氛围真好。希望明年能带外婆来北京玩,外婆那些年一路过来不容易,现在也该享享清福了。

你做的引以为傲的5件事?

  1. 终于还是借着低价买的域名,开通的博客,开始记录技术,生活的感悟,以及看书,电影。零零散散的也写了将近20篇文章,虽然内容还有待提供,以及有些是拼凑的。但还是希望自己沉淀一些知识,以及顺便提高自己的写作能力。
  2. 认知的提升。网络上的人云亦云,股市的追涨杀跌,以及自媒体带节奏的十万加,以及各种app推送的信息。让我意识到现在虽然信息变多了,但都是他们为了满足自己的利益而塞给观看者已经加工过的信息。对此,自己的认知的提升,能够对此消息进行独立思考,而不是跟着他人的情感走是非常重要的。而群体更能泛滥此情绪,相比独立思考,会显得更智力低下。
Read more
spark streaming

之前讲解了Google的Dataflow模型。而spark streaming是以micro batch方式来近似streaming数据进行处理。Spark Streaming从实时数据流接入数据,再将其划分为一个个小批量供后续Spark engine处理,所以实际上,Spark Streaming是按一个个小批量来处理数据流的。

spark streaming

离散数据流(DStream)是Spark Streaming最基本的抽象。它代表了一种连续的数据流,要么从某种数据源提取数据,要么从其他数据流映射转换而来。DStream内部是由一系列连续的RDD组成的,每个RDD都是不可变、分布式的数据集。每个RDD都包含了特定时间间隔内的一批数据,如下图所示:

任何作用于DStream的算子,其实都会被转化为对其内部RDD的操作。例如,在代码

1
val words = lines.flatMap(_.split(" "))

中,我们将lines这个DStream转成words DStream对象,其实作用于lines上的flatMap算子,会施加于lines中的每个RDD上,并生成新的对应的RDD,而这些新生成的RDD对象就组成了words这个DStream对象。其过程如下图所示:

Read more