精华内容
下载资源
问答
  • 文章目录第十八章_后端架构选型、离线及实时计算18.1 为什么需要分布式计算?18.2 目前有哪些深度学习分布式计算框架?18.2.1 PaddlePaddle18.2.2 Deeplearning4j18.2.3 Mahout18.2.4 Spark MLllib18.2.5 Ray18.2.6 ...

    第十八章_后端架构选型、离线及实时计算

    Markdown Revision 1;
    Date: 2018/11/11
    Editor: 梁志成
    Contact: superzhicheng@foxmail.com
    

    18.1 为什么需要分布式计算?

      在这个数据爆炸的时代,产生的数据量不断地在攀升,从GB,TB,PB,ZB.挖掘其中数据的价值也是企业在不断地追求的终极目标。但是要想对海量的数据进行挖掘,首先要考虑的就是海量数据的存储问题,比如Tb量级的数据。

      谈到数据的存储,则不得不说的是磁盘的数据读写速度问题。早在上个世纪90年代初期,普通硬盘的可以存储的容量大概是1G左右,硬盘的读取速度大概为4.4MB/s.读取一张硬盘大概需要5分钟时间,但是如今硬盘的容量都在1TB左右了,相比扩展了近千倍。但是硬盘的读取速度大概是100MB/s。读完一个硬盘所需要的时间大概是2.5个小时。所以如果是基于TB级别的数据进行分析的话,光硬盘读取完数据都要好几天了,更谈不上计算分析了。那么该如何处理大数据的存储,计算分析呢?

      一个很简单的减少数据读写时间的方法就是同时从多个硬盘上读写数据,比如,如果我们有100个硬盘,每个硬盘存储1%的数据 ,并行读取,那么不到两分钟就可以完成之前需要2.5小时的数据读写任务了。这就是大数据中的分布式存储的模型。当然实现分布式存储还需要解决很多问题,比如硬件故障的问题,使用多台主机进行分布式存储时,若主机故障,会出现数据丢失的问题,所以有了副本机制:系统中保存数据的副本。一旦有系统发生故障,就可以使用另外的副本进行替换(著名的RAID冗余磁盘阵列就是按这个原理实现的)。其次比如一个很大的文件如何进行拆分存储,读取拆分以后的文件如何进行校验都是要考虑的问题。比如我们使用Hadoop中的HDFS也面临这个问题,只是框架给我们实现了这些问题的解决办法,开发中开发者不用考虑这些问题,底层框架已经实现了封装。

      同样假如有一个10TB的文件,我们要统计其中某个关键字的出现次数,传统的做法是遍历整个文件,然后统计出关键字的出现次数,这样效率会特别特别低。基于分布式存储以后,数据被分布式存储在不同的服务器上,那么我们就可以使用分布式计算框架(比如MapReduce,Spark等)来进行并行计算(或者说是分布式计算),即:每个服务器上分别统计自己存储的数据中关键字出现的次数,最后进行一次汇总,那么假如数据分布在100台服务器上,即同时100台服务器同时进行关键字统计工作,效率一下子可以提高几十倍。

    18.2 目前有哪些深度学习分布式计算框架?

    18.2.1 PaddlePaddle

      PaddlePaddle【1】是百度开源的一个深度学习平台。PaddlePaddle为深度学习研究人员提供了丰富的API,可以轻松地完成神经网络配置,模型训练等任务。
    官方文档中简易介绍了如何使用框架在

    • 线性回归
    • 识别数字
    • 图像分类
    • 词向量
    • 个性化推荐
    • 情感分析
    • 语义角色标注
    • 机器翻译

    等方面的应用

      Github地址:https://github.com/PaddlePaddle/Paddle

    18.2.2 Deeplearning4j

      DeepLearning4J(DL4J)【2】是一套基于Java语言的神经网络工具包,可以构建、定型和部署神经网络。DL4J与Hadoop和Spark集成,支持分布式CPU和GPU。

      Deeplearning4j包括了分布式、多线程的深度学习框架,以及普通的单线程深度学习框架。定型过程以集群进行,也就是说,Deeplearning4j可以快速处理大量数据。Deeplearning4j在开放堆栈中作为模块组件的功能,使之成为为微服务架构打造的深度学习框架。

      Deeplearning4j从各类浅层网络出发,设计深层神经网络。这一灵活性使用户可以根据所需,在分布式、生产级、能够在分布式CPU或GPU的基础上与Spark和Hadoop协同工作的框架内,整合受限玻尔兹曼机、其他自动编码器、卷积网络或递归网络。

      Deeplearning4j在已建立的各个库及其在系统整体中的所处位置

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QFPSbsJa-1575791675394)(./img/18-2-2.png)]

      Github地址:https://github.com/deeplearning4j/deeplearning4j

    18.2.3 Mahout

      Mahout【3】是基于Hadoop的机器学习和数据挖掘的一个分布式框架。Mahout用MapReduce实现了部分数据挖掘算法,解决了并行挖掘的问题。

      Mahout包含许多实现,包括聚类、分类、推荐过滤、频繁子项挖掘等。

      Mahout算法库:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o4i3wYdN-1575791675395)(./img/18-2-3-1.png)]

      Mahout应用场景:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hYo7jlSP-1575791675397)(./img/18-2-3-2.png)]

      Github地址:https://github.com/apache/mahout

    18.2.4 Spark MLllib

      MLlib(Machine Learnig lib) 【4】是Spark对常用的机器学习算法的实现库,同时包括相关的测试和数据生成器。

      MLlib是MLBase一部分,其中MLBase分为四部分:MLlib、MLI、ML Optimizer和MLRuntime。

    • ML Optimizer会选择它认为最适合的已经在内部实现好了的机器学习算法和相关参数,来处理用户输入的数据,并返回模型或别的帮助分析的结果;
    • MLI 是一个进行特征抽取和高级ML编程抽象的算法实现的API或平台;
    • MLlib是Spark实现一些常见的机器学习算法和实用程序,包括分类、回归、聚类、协同过滤、降维以及底层优化,该算法可以进行可扩充; MLRuntime 基于Spark计算框架,将Spark的分布式计算应用到机器学习领域。

      MLlib主要包含三个部分:

    • 底层基础:包括Spark的运行库、矩阵库和向量库
    • 算法库:包含广义线性模型、推荐系统、聚类、决策树和评估的算法
    • 实用程序:包括测试数据的生成、外部数据的读入等功能

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZjfPTZE7-1575791675399)(./img/18-2-4-1.png)]

    架构图

      MLlib目前支持4种常见的机器学习问题: 分类、回归、聚类和协同过滤,MLlib在Spark整个生态系统中的位置如图下图所示。

    18.2.5 Ray

      Ray【5】是加州大学伯克利分校实时智能安全执行实验室(RISELab)的研究人员针对机器学习领域开发的一种新的分布式计算框架,该框架旨在让基于Python的机器学习和深度学习工作负载能够实时执行,并具有类似消息传递接口(MPI)的性能和细粒度。

      增强学习的场景,按照原理定义,因为没有预先可用的静态标签信息,所以通常需要引入实际的目标系统(为了加快训练,往往是目标系统的模拟环境)来获取反馈信息,用做损失/收益判断,进而完成整个训练过程的闭环反馈。典型的步骤是通过观察特定目标系统的状态,收集反馈信息,判断收益,用这些信息来调整参数,训练模型,并根据新的训练结果产出可用于调整目标系统的行为Action,输出到目标系统,进而影响目标系统状态变化,完成闭环,如此反复迭代,最终目标是追求某种收益的最大化(比如对AlphoGo来说,收益是赢得一盘围棋的比赛)。

      在这个过程中,一方面,模拟目标系统,收集状态和反馈信息,判断收益,训练参数,生成Action等等行为可能涉及大量的任务和计算(为了选择最佳Action,可能要并发模拟众多可能的行为)。而这些行为本身可能也是千差万别的异构的任务,任务执行的时间也可能长短不一,执行过程有些可能要求同步,也有些可能更适合异步。

      另一方面,整个任务流程的DAG图也可能是动态变化的,系统往往可能需要根据前一个环节的结果,调整下一个环节的行为参数或者流程。这种调整,可能是目标系统的需要(比如在自动驾驶过程中遇到行人了,那么我们可能需要模拟计算刹车的距离来判断该采取的行动是刹车还是拐弯,而平时可能不需要这个环节),也可能是增强学习特定训练算法的需要(比如根据多个并行训练的模型的当前收益,调整模型超参数,替换模型等等)。

      此外,由于所涉及到的目标系统可能是具体的,现实物理世界中的系统,所以对时效性也可能是有强要求的。举个例子,比如你想要实现的系统是用来控制机器人行走,或者是用来打视频游戏的。那么整个闭环反馈流程就需要在特定的时间限制内完成(比如毫秒级别)。

      总结来说,就是增强学习的场景,对分布式计算框架的任务调度延迟,吞吐量和动态修改DAG图的能力都可能有很高的要求。按照官方的设计目标,Ray需要支持异构计算任务,动态计算链路,毫秒级别延迟和每秒调度百万级别任务的能力。

      Ray的目标问题,主要是在类似增强学习这样的场景中所遇到的工程问题。那么增强学习的场景和普通的机器学习,深度学习的场景又有什么不同呢?简单来说,就是对整个处理链路流程的时效性和灵活性有更高的要求。

    Ray框架优点

    • 海量任务调度能力
    • 毫秒级别的延迟
    • 异构任务的支持
    • 任务拓扑图动态修改的能力

      Ray没有采用中心任务调度的方案,而是采用了类似层级(hierarchy)调度的方案,除了一个全局的中心调度服务节点(实际上这个中心调度节点也是可以水平拓展的),任务的调度也可以在具体的执行任务的工作节点上,由本地调度服务来管理和执行。
    与传统的层级调度方案,至上而下分配调度任务的方式不同的是,Ray采用了至下而上的调度策略。也就是说,任务调度的发起,并不是先提交给全局的中心调度器统筹规划以后再分发给次级调度器的。而是由任务执行节点直接提交给本地的调度器,本地的调度器如果能满足该任务的调度需求就直接完成调度请求,在无法满足的情况下,才会提交给全局调度器,由全局调度器协调转发给有能力满足需求的另外一个节点上的本地调度器去调度执行。

      架构设计一方面减少了跨节点的RPC开销,另一方面也能规避中心节点的瓶颈问题。当然缺点也不是没有,由于缺乏全局的任务视图,无法进行全局规划,因此任务的拓扑逻辑结构也就未必是最优的了。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtpuCcGo-1575791675400)(./img/18-2-5-1.png)]

    架构图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kraL5RCL-1575791675401)(./img/18-2-5-2.png)]

    任务调度图

      Ray架构现状:

    • API层以上 的部分还比较薄弱,Core模块核心逻辑估需要时间打磨。
    • 国内目前除了蚂蚁金服和RISELab有针对性的合作以外,关注程度还很低,没有实际的应用实例看到,整体来说还处于比较早期的框架构建阶段。

      Github地址:https://github.com/ray-project/ray

    18.2.6 Spark stream

      随着大数据的发展,人们对大数据的处理要求也越来越高,原有的批处理框架MapReduce适合离线计算,却无法满足实时性要求较高的业务,如实时推荐、用户行为分析等。 Spark Streaming是建立在Spark上的实时计算框架,通过它提供的丰富的API、基于内存的高速执行引擎,用户可以结合流式、批处理和交互试查询应用。

      Spark是一个类似于MapReduce的分布式计算框架,其核心是弹性分布式数据集,提供了比MapReduce更丰富的模型,可以在快速在内存中对数据集进行多次迭代,以支持复杂的数据挖掘算法和图形计算算法。Spark Streaming【6】是一种构建在Spark上的实时计算框架,它扩展了Spark处理大规模流式数据的能力。

      Spark Streaming的优势在于:

    • 能运行在100+的结点上,并达到秒级延迟。
    • 使用基于内存的Spark作为执行引擎,具有高效和容错的特性。
    • 能集成Spark的批处理和交互查询。
    • 为实现复杂的算法提供和批处理类似的简单接口。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wur7O7Z6-1575791675402)(./img/18-2-6-1.png)]

    Spark Streaming架构图

      Spark Streaming把实时输入数据流以时间片Δt (如1秒)为单位切分成块。Spark Streaming会把每块数据作为一个RDD,并使用RDD操作处理每一小块数据。每个块都会生成一个Spark Job处理,最终结果也返回多块。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R0pqAPiC-1575791675405)(./img/18-2-6-2.png)]

    Spark Streaming基本原理图

      正如Spark Streaming最初的目标一样,它通过丰富的API和基于内存的高速计算引擎让用户可以结合流式处理,批处理和交互查询等应用。因此Spark Streaming适合一些需要历史数据和实时数据结合分析的应用场合。当然,对于实时性要求不是特别高的应用也能完全胜任。另外通过RDD的数据重用机制可以得到更高效的容错处理。

    18.2.7 Horovod

      Horovod【7】 是 Uber 开源的又一个深度学习工具,它的发展吸取了 Facebook「一小时训练 ImageNet 论文」与百度 Ring Allreduce 的优点,可为用户实现分布式训练提供帮助。

      Horovod 支持通过用于高性能并行计算的低层次接口 – 消息传递接口 (MPI) 进行分布式模型训练。有了 MPI,就可以利用分布式 Kubernetes 集群来训练 TensorFlow 和 PyTorch 模型。

      分布式 TensorFlow 的参数服务器模型(parameter server paradigm)通常需要对大量样板代码进行认真的实现。但是 Horovod 仅需要几行。下面是一个分布式 TensorFlow 项目使用 Horovod 的示例:

    import  tensorflow as tf
    import horovod.tensorflow as hvd
    # Initialize Horovod
    hvd.init()
    # Pin GPU to be used to process local rank (one GPU per process)
    config = tf.ConfigProto()
    config.gpu_options.visible_device_list = str(hvd.local_rank())
    # Build model…
    loss = …
    opt = tf.train.AdagradOptimizer(0.01)
    # Add Horovod Distributed Optimizer
    opt = hvd.DistributedOptimizer(opt)
    # Add hook to broadcast variables from rank 0 to all other processes during
    # initialization.
    hooks = [hvd.BroadcastGlobalVariablesHook(0)]
    # Make training operation
    train_op = opt.minimize(loss)
    # The MonitoredTrainingSession takes care of session initialization,
    # restoring from a checkpoint, saving to a checkpoint, and closing when done
    # or an error occurs.
    with tf.train.MonitoredTrainingSession(checkpoint_dir=“/tmp/train_logs”,
                                          config=config,
                                          hooks=hooks) as mon_sess:
     while not mon_sess.should_stop():
       # Perform synchronous training.
       mon_sess.run(train_op)
    

      在该示例中,粗体文字指进行单个 GPU 分布式项目时必须做的改变:

    • hvd.init() 初始化 Horovod。
    • config.gpu_options.visible_device_list = str(hvd.local_rank()) 向每个 TensorFlow 流程分配一个 GPU。
    • opt=hvd.DistributedOptimizer(opt) 使用 Horovod 优化器包裹每一个常规 TensorFlow 优化器,Horovod 优化器使用 ring-allreduce 平均梯度。
    • hvd.BroadcastGlobalVariablesHook(0) 将变量从第一个流程向其他流程传播,以实现一致性初始化。如果该项目无法使用 MonitoredTrainingSession,则用户可以运行 hvd.broadcast_global_variables(0)。

      之后,可以使用 mpirun 命令使该项目的多个拷贝在多个服务器中运行:

    $ mpirun -np 16 -x LD_LIBRARY_PATH -H 
    server1:4,server2:4,server3:4,server4:4 python train.py
    

      mpirun 命令向四个节点分布 train.py,然后在每个节点的四个 GPU 上运行 train.py。

      Github地址:https://github.com/uber/horovod

    18.2.8 BigDL

      BigDL【9】是一种基于Apache Spark的分布式深度学习框架。它可以无缝的直接运行在现有的Apache Spark和Hadoop集群之上。BigDL的设计吸取了Torch框架许多方面的知识,为深度学习提供了全面的支持;包括数值计算和高级神经网络;借助现有的Spark集群来运行深度学习计算,并简化存储在Hadoop中的大数据集的数据加载。

      BigDL优点:

    • 丰富的深度学习支持。模拟Torch之后,BigDL为深入学习提供全面支持,包括数字计算(通过Tensor)和高级神经网络 ; 此外,用户可以使用BigDL将预先训练好的Caffe或Torch模型加载到Spark程序中。
    • 极高的性能。为了实现高性能,BigDL在每个Spark任务中使用英特尔MKL和多线程编程。因此,在单节点Xeon(即与主流GPU 相当)上,它比开箱即用开源Caffe,Torch或TensorFlow快了数量级。
    • 有效地横向扩展。BigDL可以通过利用Apache Spark(快速分布式数据处理框架),以及高效实施同步SGD和全面减少Spark的通信,从而有效地扩展到“大数据规模”上的数据分析

      BigDL缺点:

    • 对机器要求高 jdk7上运行性能差 在CentOS 6和7上,要将最大用户进程增加到更大的值(例如514585); 否则,可能会看到错误,如“无法创建新的本机线程”。
    • 训练和验证的数据会加载到内存,挤占内存

      BigDL满足的应用场景:

    • 直接在Hadoop/Spark框架下使用深度学习进行大数据分析(即将数据存储在HDFS、HBase、Hive等数据库上);
    • 在Spark程序中/工作流中加入深度学习功能;
    • 利用现有的 Hadoop/Spark 集群来运行深度学习程序,然后将代码与其他的应用场景进行动态共享,例如ETL(Extract、Transform、Load,即通常所说的数据抽取)、数据仓库(data warehouse)、功能引擎、经典机器学习、图表分析等。

    18.2.9 Petastorm

      Petastorm是一个由 Uber ATG 开发的开源数据访问库。这个库可以直接基于数 TB Parquet 格式的数据集进行单机或分布式训练和深度学习模型评估。Petastorm 支持基于 Python 的机器学习框架,如 Tensorflow、Pytorch 和 PySpark,也可以直接用在 Python 代码中。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Je3GkFN-1575791675406)(./img/18-2-9-1.png)]

    深度学习集群

      即使是在现代硬件上训练深度模型也很耗时,而且在很多情况下,很有必要在多台机器上分配训练负载。典型的深度学习集群需要执行以下几个步骤:

    • 一台或多台机器读取集中式或本地数据集。
    • 每台机器计算损失函数的值,并根据模型参数计算梯度。在这一步通常会使用 GPU。
    • 通过组合估计的梯度(通常由多台机器以分布式的方式计算得出)来更新模型系数。

      通常,一个数据集是通过连接多个数据源的记录而生成的。这个由 Apache Spark 的 Python 接口 PySpark 生成的数据集稍后将被用在机器学习训练中。Petastorm 提供了一个简单的功能,使用 Petastorm 特定的元数据对标准的 Parquet 进行了扩展,从而让它可以与 Petastorm 兼容。
    有了 Petastorm,消费数据就像在 HDFS 或文件系统中创建和迭代读取对象一样简单。Petastorm 使用 PyArrow 来读取 Parquet 文件。

      将多个数据源组合到单个表格结构中,从而生成数据集。可以多次使用相同的数据集进行模型训练和评估。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3gMwvCHH-1575791675408)(./img/18-2-9-2.png)]

    深度学习集群

      为分布式训练进行分片
    在分布式训练环境中,每个进程通常负责训练数据的一个子集。一个进程的数据子集与其他进程的数据子集正交。Petastorm 支持将数据集的读时分片转换为正交的样本集。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LwE2vXXe-1575791675408)(./img/18-2-9-3.png)]

    Petastorm 将数据集的非重叠子集提供给参与分布式训练的不同机器

      本地缓存
    Petastorm 支持在本地存储中缓存数据。当网络连接速度较慢或带宽很昂贵时,这会派上用场。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CF1lGF97-1575791675410)(./img/18-2-9-4.png)]

    Github地址:https://github.com/uber/petastorm

    18.2.10 TensorFlowOnSpark

      TensorFlowOnSpark【10】为 Apache Hadoop 和 Apache Spark 集群带来可扩展的深度学习。 通过结合深入学习框架 TensorFlow 和大数据框架 Apache Spark 、Apache Hadoop 的显着特征,TensorFlowOnSpark 能够在 GPU 和 CPU 服务器集群上实现分布式深度学习。

      满足的应用场景:
    为了利用TensorFlow在现有的Spark和Hadoop集群上进行深度学习。而不需要为深度学习设置单独的集群。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TXiudywP-1575791675411)(./img/18-2-10-1.png)]

    架构图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aYJTPCL7-1575791675412)(./img/18-2-10-2.png)]

    运行流程图

      优点:

    • 轻松迁移所有现有的TensorFlow程序,<10行代码更改;
    • 支持所有TensorFlow功能:同步/异步训练,模型/数据并行,推理和TensorBoard;
    • 服务器到服务器的直接通信在可用时实现更快的学习;
    • 允许数据集在HDFS和由Spark推动的其他来源或由TensorFlow拖动;
    • 轻松集成您现有的数据处理流水线和机器学习算法(例如,MLlib,CaffeOnSpark);
    • 轻松部署在云或内部部署:CPU和GPU,以太网和Infiniband。
    • TensorFlowOnSpark是基于google的TensorFlow的实现,而TensorFlow有着一套完善的教程,内容丰富。

      劣势:

    • 开源时间不长,未得到充分的验证。

      Github 地址:https://github.com/yahoo/TensorFlowOnSpark

    18.3 如何选择合适的分布式计算框架进行模型训练?

    18.4 如何进行实时计算?

    18.4.1 什么是实时流计算?

      所谓实时流计算,就是近几年由于数据得到广泛应用之后,在数据持久性建模不满足现状的情况下,急需数据流的瞬时建模或者计算处理。这种实时计算的应用实例有金融服务、网络监控、电信数据管理、 Web 应用、生产制造、传感检测,等等。在这种数据流模型中,单独的数据单元可能是相关的元组(Tuple),如网络测量、呼叫记录、网页访问等产生的数据。但是,这些数据以大量、快速、时变(可能是不可预知)的数据流持续到达,由此产生了一些基础性的新的研究问题——实时计算。实时计算的一个重要方向就是实时流计算。

    18.4.2 实时流计算过程

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BksFSNXN-1575791675413)(./img/18-4-1.png)]

      我们以热卖产品的统计为例,看下传统的计算手段:

    • 将用户行为、log等信息清洗后保存在数据库中.
    • 将订单信息保存在数据库中.
    • 利用触发器或者协程等方式建立本地索引,或者远程的独立索引.
    • join订单信息、订单明细、用户信息、商品信息等等表,聚合统计20分钟内热卖产品,并返回top-10.
    • web或app展示.

      这是一个假想的场景,但假设你具有处理类似场景的经验,应该会体会到这样一些问题和难处:

    • 水平扩展问题(scale-out)
      显然,如果是一个具有一定规模的电子商务网站,数据量都是很大的。而交易信息因为涉及事务,所以很难直接舍弃关系型数据库的事务能力,迁移到具有更好的scale-out能力的NoSQL数据库中。

      那么,一般都会做sharding。历史数据还好说,我们可以按日期来归档,并可以通过批处理式的离线计算,将结果缓存起来。
    但是,这里的要求是20分钟内,这很难。

    • 性能问题
      这个问题,和scale-out是一致的,假设我们做了sharding,因为表分散在各个节点中,所以我们需要多次入库,并在业务层做聚合计算。

      问题是,20分钟的时间要求,我们需要入库多少次呢?
    10分钟呢?
    5分钟呢?
    实时呢?

      而且,业务层也同样面临着单点计算能力的局限,需要水平扩展,那么还需要考虑一致性的问题。
    所以,到这里一切都显得很复杂。

    • 业务扩展问题

      假设我们不仅仅要处理热卖商品的统计,还要统计广告点击、或者迅速根据用户的访问行为判断用户特征以调整其所见的信息,更加符合用户的潜在需求等,那么业务层将会更加复杂。
    也许你有更好的办法,但实际上,我们需要的是一种新的认知:
    这个世界发生的事,是实时的。
    所以我们需要一种实时计算的模型,而不是批处理模型。
    我们需要的这种模型,必须能够处理很大的数据,所以要有很好的scale-out能力,最好是,我们都不需要考虑太多一致性、复制的问题。

      那么,这种计算模型就是实时计算模型,也可以认为是流式计算模型。
    现在假设我们有了这样的模型,我们就可以愉快地设计新的业务场景:

    • 转发最多的微博是什么?
    • 最热卖的商品有哪些?
    • 大家都在搜索的热点是什么?
    • 我们哪个广告,在哪个位置,被点击最多?
      或者说,我们可以问:
        这个世界,在发生什么?

      最热的微博话题是什么?
    我们以一个简单的滑动窗口计数的问题,来揭开所谓实时计算的神秘面纱。
    假设,我们的业务要求是:
    统计20分钟内最热的10个微博话题。

      解决这个问题,我们需要考虑:

    • 数据源

      这里,假设我们的数据,来自微博长连接推送的话题。

    • 问题建模

      我们认为的话题是#号扩起来的话题,最热的话题是此话题出现的次数比其它话题都要多。
    比如:@foreach_break : 你好,#世界#,我爱你,#微博#。
    “世界”和“微博”就是话题。

    • 计算引擎采用storm

    • 定义时间

      时间的定义是一件很难的事情,取决于所需的精度是多少。
    根据实际,我们一般采用tick来表示时刻这一概念。
    在storm的基础设施中,executor启动阶段,采用了定时器来触发“过了一段时间”这个事件。
    如下所示:

    (defn setup-ticks! [worker executor-data]
      (let [storm-conf (:storm-conf executor-data)
            tick-time-secs (storm-conf TOPOLOGY-TICK-TUPLE-FREQ-SECS)
            receive-queue (:receive-queue executor-data)
            context (:worker-context executor-data)]
        (when tick-time-secs
          (if (or (system-id? (:component-id executor-data))
                  (and (= false (storm-conf TOPOLOGY-ENABLE-MESSAGE-TIMEOUTS))
                       (= :spout (:type executor-data))))
            (log-message "Timeouts disabled for executor " (:component-id executor-data) ":" (:executor-id executor-data))
            (schedule-recurring
              (:user-timer worker)
              tick-time-secs
              tick-time-secs
              (fn []
                (disruptor/publish
                  receive-queue
                  [[nil (TupleImpl. context [tick-time-secs] Constants/SYSTEM_TASK_ID Constants/SYSTEM_TICK_STREAM_ID)]]
                  )))))))
    

    之前的博文中,已经详细分析了这些基础设施的关系,不理解的童鞋可以翻看前面的文章。
    每隔一段时间,就会触发这样一个事件,当流的下游的bolt收到一个这样的事件时,就可以选择是增量计数还是将结果聚合并发送到流中。
    bolt如何判断收到的tuple表示的是“tick”呢?
    负责管理bolt的executor线程,从其订阅的消息队列消费消息时,会调用到bolt的execute方法,那么,可以在execute中这样判断:

    public static boolean isTick(Tuple tuple) {
        return tuple != null
               && Constants.SYSTEM_COMPONENT_ID  .equals(tuple.getSourceComponent())
               && Constants.SYSTEM_TICK_STREAM_ID.equals(tuple.getSourceStreamId());
    }
    

    结合上面的setup-tick!的clojure代码,我们可以知道SYSTEM_TICK_STREAM_ID在定时事件的回调中就以构造函数的参数传递给了tuple,那么SYSTEM_COMPONENT_ID是如何来的呢?
    可以看到,下面的代码中,SYSTEM_TASK_ID同样传给了tuple:
    ;; 请注意SYSTEM_TASK_ID和SYSTEM_TICK_STREAM_ID
    (TupleImpl. context [tick-time-secs] Constants/SYSTEM_TASK_ID Constants/SYSTEM_TICK_STREAM_ID)
    然后利用下面的代码,就可以得到SYSTEM_COMPONENT_ID:

        public String getComponentId(int taskId) {
            if(taskId==Constants.SYSTEM_TASK_ID) {
                return Constants.SYSTEM_COMPONENT_ID;
            } else {
                return _taskToComponent.get(taskId);
            }
        }
    

    滑动窗口
    有了上面的基础设施,我们还需要一些手段来完成“工程化”,将设想变为现实。
    这里,我们看看Michael G. Noll的滑动窗口设计。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZeYZq0wj-1575791675415)(./img/18-4-2.png)]

    Topology

        String spoutId = "wordGenerator";
        String counterId = "counter";
        String intermediateRankerId = "intermediateRanker";
        String totalRankerId = "finalRanker";
        // 这里,假设TestWordSpout就是我们发送话题tuple的源
        builder.setSpout(spoutId, new TestWordSpout(), 5);
        // RollingCountBolt的时间窗口为9秒钟,每3秒发送一次统计结果到下游
        builder.setBolt(counterId, new RollingCountBolt(9, 3), 4).fieldsGrouping(spoutId, new Fields("word"));
        // IntermediateRankingsBolt,将完成部分聚合,统计出top-n的话题
        builder.setBolt(intermediateRankerId, new IntermediateRankingsBolt(TOP_N), 4).fieldsGrouping(counterId, new Fields(
            "obj"));
            // TotalRankingsBolt, 将完成完整聚合,统计出top-n的话题
        builder.setBolt(totalRankerId, new TotalRankingsBolt(TOP_N)).globalGrouping(intermediateRankerId);
    

    上面的topology设计如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W9B5MLAU-1575791675416)(./img/18-4-3.png)]

    将聚合计算与时间结合起来
    前文,我们叙述了tick事件,回调中会触发bolt的execute方法,那可以这么做:

    RollingCountBolt:
      @Override
      public void execute(Tuple tuple) {
        if (TupleUtils.isTick(tuple)) {
          LOG.debug("Received tick tuple, triggering emit of current window counts");
          // tick来了,将时间窗口内的统计结果发送,并让窗口滚动
          emitCurrentWindowCounts();
        }
        else {
          // 常规tuple,对话题计数即可
          countObjAndAck(tuple);
        }
      }
    
      // obj即为话题,增加一个计数 count++
      // 注意,这里的速度基本取决于流的速度,可能每秒百万,也可能每秒几十.
      // 内存不足? bolt可以scale-out.
      private void countObjAndAck(Tuple tuple) {
        Object obj = tuple.getValue(0);
        counter.incrementCount(obj);
        collector.ack(tuple);
      }
      
      // 将统计结果发送到下游
      private void emitCurrentWindowCounts() {
        Map<Object, Long> counts = counter.getCountsThenAdvanceWindow();
        int actualWindowLengthInSeconds = lastModifiedTracker.secondsSinceOldestModification();
        lastModifiedTracker.markAsModified();
        if (actualWindowLengthInSeconds != windowLengthInSeconds) {
          LOG.warn(String.format(WINDOW_LENGTH_WARNING_TEMPLATE, actualWindowLengthInSeconds, windowLengthInSeconds));
        }
        emit(counts, actualWindowLengthInSeconds);
      }
    

    上面的代码可能有点抽象,看下这个图就明白了,tick一到,窗口就滚动:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sc8sgVkj-1575791675417)(./img/18-4-4.png)]

    IntermediateRankingsBolt & TotalRankingsBolt:
      public final void execute(Tuple tuple, BasicOutputCollector collector) {
        if (TupleUtils.isTick(tuple)) {
          getLogger().debug("Received tick tuple, triggering emit of current rankings");
          // 将聚合并排序的结果发送到下游
          emitRankings(collector);
        }
        else {
          // 聚合并排序
          updateRankingsWithTuple(tuple);
        }
      }
    

      其中,IntermediateRankingsBolt和TotalRankingsBolt的聚合排序方法略有不同:

    IntermediateRankingsBolt的聚合排序方法:

      @Override
      void updateRankingsWithTuple(Tuple tuple) {
        // 这一步,将话题、话题出现的次数提取出来
        Rankable rankable = RankableObjectWithFields.from(tuple);
        // 这一步,将话题出现的次数进行聚合,然后重排序所有话题
        super.getRankings().updateWith(rankable);
      }
    

    TotalRankingsBolt的聚合排序方法:

      @Override
      void updateRankingsWithTuple(Tuple tuple) {
      // 提出来自IntermediateRankingsBolt的中间结果
        Rankings rankingsToBeMerged = (Rankings) tuple.getValue(0);
      // 聚合并排序
        super.getRankings().updateWith(rankingsToBeMerged);
      // 去0,节约内存
        super.getRankings().pruneZeroCounts();
      }
    

    而重排序方法比较简单粗暴,因为只求前N个,N不会很大:

      private void rerank() {
        Collections.sort(rankedItems);
        Collections.reverse(rankedItems);
      }
    

      结语

      下图可能就是我们想要的结果,我们完成了t0 - t1时刻之间的热点话题统计.
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xqwOYtKC-1575791675417)(./img/18-4-5.png)]

    18.5 如何进行离线计算?

    18.6 如何使用分布式框架提高模型训练速度?

    18.7 深度学习分布式计算框架如何在移动互联网中应用?

    18.8 如何在个性化推荐中应用深度学习分布式框架?

    18.9 如何评价个性化推荐系统的效果?

    18.9.1 准确率与召回率(Precision & Recall)

      准确率和召回率是广泛用于信息检索和统计学分类领域的两个度量值,用来评价结果的质量。其中精度是检索出相关文档数与检索出的文档总数的比率,衡量的是检索系统的查准率;召回率是指检索出的相关文档数和文档库中所有的相关文档数的比率,衡量的是检索系统的查全率。

      一般来说,Precision就是检索出来的条目(比如:文档、网页等)有多少是准确的,Recall就是所有准确的条目有多少被检索出来了。

      正确率、召回率和 F 值是在鱼龙混杂的环境中,选出目标的重要评价指标。不妨看看这些指标的定义先:

    正确率 = 提取出的正确信息条数 /  提取出的信息条数 
    
    召回率 = 提取出的正确信息条数 /  样本中的信息条数    
    

      两者取值在0和1之间,数值越接近1,查准率或查全率就越高。

    F值  = 正确率 * 召回率 * 2 / (正确率 + 召回率) (F 值即为正确率和召回率的调和平均值)
    

      不妨举这样一个例子:某池塘有1400条鲤鱼,300只虾,300只鳖。现在以捕鲤鱼为目的。撒一大网,逮着了700条鲤鱼,200只虾,100只鳖。那么,这些指标分别如下:

    正确率 = 700 / (700 + 200 + 100) = 70%
    
    召回率 = 700 / 1400 = 50%
    
    F值 = 70% * 50% * 2 / (70% + 50%) = 58.3%
    

      不妨看看如果把池子里的所有的鲤鱼、虾和鳖都一网打尽,这些指标又有何变化:

    正确率 = 1400 / (1400 + 300 + 300) = 70%
    
    召回率 = 1400 / 1400 = 100%
    
    F值 = 70% * 100% * 2 / (70% + 100%) = 82.35%        
    

      由此可见,正确率是评估捕获的成果中目标成果所占得比例;召回率,顾名思义,就是从关注领域中,召回目标类别的比例;而F值,则是综合这二者指标的评估指标,用于综合反映整体的指标。

      当然希望检索结果Precision越高越好,同时Recall也越高越好,但事实上这两者在某些情况下有矛盾的。比如极端情况下,我们只搜索出了一个结果,且是准确的,那么Precision就是100%,但是Recall就很低;而如果我们把所有结果都返回,那么比如Recall是100%,但是Precision就会很低。因此在不同的场合中需要自己判断希望Precision比较高或是Recall比较高。如果是做实验研究,可以绘制Precision-Recall曲线来帮助分析。

    18.9.2 综合评价指标(F-Measure)

      P和R指标有时候会出现的矛盾的情况,这样就需要综合考虑他们,最常见的方法就是F-Measure(又称为F-Score)。

      F-Measure是Precision和Recall加权调和平均:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gFdiunt5-1575791675418)(./img/18-9-2-1.png)]

      当参数α=1时,就是最常见的F1,也即

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rRTnB1aP-1575791675419)(./img/18-9-2-2.png)]

      可知F1综合了P和R的结果,当F1较高时则能说明试验方法比较有效。

    18.9.3 E值

      E值表示查准率P和查全率R的加权平均值,当其中一个为0时,E值为1,其计算公式:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q8tbTOQU-1575791675420)(./img/18-9-3-1.png)]

      b越大,表示查准率的权重越大。

    18.9.4 平均正确率(Average Precision)

      平均正确率表示不同查全率的点上的正确率的平均。

    18.10 参考文献

    【1】http://www.paddlepaddle.org/documentation/book/zh/0.11.0/05.recommender_system/index.cn.html

    【2】https://deeplearning4j.org/cn/compare-dl4j-torch7-pylearn.html

    【3】http://mahout.apache.org/

    【4】http://spark.apache.org/docs/1.1.0/mllib-guide.html

    【5】https://ray.readthedocs.io/en/latest/tutorial.html

    【6】http://spark.apache.org/streaming/

    【7】https://github.com/uber/horovod

    【8】https://software.intel.com/en-us/articles/bigdl-distributed-deep-learning-on-apache-spark

    【9】https://eng.uber.com/petastorm/

    【10】https://yahoo.github.io/TensorFlowOnSpark/#

    未完待续!

    展开全文
  • Web前端和后端有哪些区别?需要掌握的技术有什么区别?下面和千锋广州小编一起来看看吧! Web前端分为网页设计师、网页美工、Web前端开发工程师。 首先网页设计师是对网页的架构、色彩以及网站的整体页面代码负责。 ...

    Web前端和后端有哪些区别?需要掌握的技术有什么区别?下面和千锋广州小编一起来看看吧!

    Web前端分为网页设计师、网页美工、Web前端开发工程师。

    首先网页设计师是对网页的架构、色彩以及网站的整体页面代码负责。

    网页美工只针对UI这块儿的东西,比如网站是否做的漂亮。

    Web前端开发工程师是负责交互设计的,需要和程序猿进行交互设计的配合。

    Web前端需要掌握的有脚本技术javascript DIV+CSS现下最流行的页面搭建技术,ajax和jquery以及简单的后端程序等。 后端的话可供开发的语言有asp、php、jsp、.NET 这些后端开发语言的话搭建环境都不一样,具体如果你想学的话看是想从事前端部分还是后端程序部分。后端开发如果有一定的条件的话可以转为软件开发。不过要有一定的语言基础,类似java语言、C++等。关键是看你的兴趣爱好。

    这个到后期不会区分这么细,做前端到后期也会懂一些后端的技术,反之,后端也是。

    在实际的开发过程中,我们当前这样定位前端、后端开发人员。

    1)前端开发人员:精通JS,能熟练应用JQuery,懂CSS,能熟练运用这些知识,进行交互效果的开发。

    2)后端开发人员:会写Java代码,会写SQL语句,能做简单的数据库设计,会Spring和iBatis,懂一些设计模式等。

    现在来看,对前后端的要求还是蛮低的,尤其是后端,新员工经过实习之后都是可以参与到后端开发的,没有太高的技术门槛,唯一需要做的就是先变成熟练工种,这个阶段没有涉及到设计模式、架构、效率等一些列问题。在约的专家对我的主要建议就是从这里入手。

    Web前端: 顾名思义是来做Web的前端的。我们这里所说的前端泛指Web前端,也就是在Web应用中用户可以看得见碰得着的东西。包括Web页面的结构、Web的外观视觉表现以及Web层面的交互实现。

    Web后端:后端更多的是与数据库进行交互以处理相应的业务逻辑。需要考虑的是如何实现功能、数据的存取、平台的稳定性与性能等。

    通过企业对前后端人员招聘的要求,分析企业对前端、后端的技术要求:

    Web前端:

    1)精通HTML,能够书写语义合理,结构清晰,易维护的HTML结构。

    2)精通CSS,能够还原视觉设计,并兼容业界承认的主流浏览器。

    3)熟悉JavaScript,了解ECMAScript基础内容,掌握1~2种js框架,如JQuery

    4)对常见的浏览器兼容问题有清晰的理解,并有可靠的解决方案。

    5)对性能有一定的要求,了解yahoo的性能优化建议,并可以在项目中有效实施。

    Web后端:

    1)精通jsp,servlet,java bean,JMS,EJB,Jdbc,Flex开发,或者对相关的工具、类库以及框架非常熟悉,如Velocity,Spring,Hibernate,iBatis,OSGI等,对Web开发的模式有较深的理解

    2)练使用oracle、sqlserver、mysql等常用的数据库系统,对数据库有较强的设计能力

    3)熟悉maven项目配置管理工具,熟悉tomcat、jboss等应用服务器,同时对在高并发处理情况下的负载调优有相关经验者优先考虑

    4)精通面向对象分析和设计技术,包括设计模式、UML建模等

    5)熟悉网络编程,具有设计和开发对外API接口经验和能力,同时具备跨平台的API规范设计以及API高效调用设计能力

    以上就是今天分享的内容,希望对大家有帮助哦!

    展开全文
  • Web前端和后端有哪些区别?需要掌握的技术有什么区别?下面和千锋重庆web前端的小编一起来看看吧! Web前端分为网页设计师、网页美工、Web前端开发工程师。 首先网页设计师是对网页的架构、色彩以及网站的整体页面代码...

    Web前端和后端有哪些区别?需要掌握的技术有什么区别?下面和千锋重庆web前端的小编一起来看看吧!

    Web前端分为网页设计师、网页美工、Web前端开发工程师。

    首先网页设计师是对网页的架构、色彩以及网站的整体页面代码负责。

    网页美工只针对UI这块儿的东西,比如网站是否做的漂亮。

    Web前端开发工程师是负责交互设计的,需要和程序猿进行交互设计的配合。

    Web前端需要掌握的有脚本技术javascript DIV+CSS现下最流行的页面搭建技术,ajax和jquery以及简单的后端程序等。 后端的话可供开发的语言有asp、php、jsp、.NET 这些后端开发语言的话搭建环境都不一样,具体如果你想学的话看是想从事前端部分还是后端程序部分。后端开发如果有一定的条件的话可以转为软件开发。不过要有一定的语言基础,类似java语言、C++等。关键是看你的兴趣爱好。

    这个到后期不会区分这么细,做前端到后期也会懂一些后端的技术,反之,后端也是。

    在实际的开发过程中,我们当前这样定位前端、后端开发人员。

    1)前端开发人员:精通JS,能熟练应用JQuery,懂CSS,能熟练运用这些知识,进行交互效果的开发。

    2)后端开发人员:会写Java代码,会写SQL语句,能做简单的数据库设计,会Spring和iBatis,懂一些设计模式等。

    现在来看,对前后端的要求还是蛮低的,尤其是后端,新员工经过实习之后都是可以参与到后端开发的,没有太高的技术门槛,唯一需要做的就是先变成熟练工种,这个阶段没有涉及到设计模式、架构、效率等一些列问题。在约的专家对我的主要建议就是从这里入手。

    Web前端: 顾名思义是来做Web的前端的。我们这里所说的前端泛指Web前端,也就是在Web应用中用户可以看得见碰得着的东西。包括Web页面的结构、Web的外观视觉表现以及Web层面的交互实现。

    Web后端:后端更多的是与数据库进行交互以处理相应的业务逻辑。需要考虑的是如何实现功能、数据的存取、平台的稳定性与性能等。

    通过企业对前后端人员招聘的要求,分析企业对前端、后端的技术要求:

    Web前端:

    1)精通HTML,能够书写语义合理,结构清晰,易维护的HTML结构。

    2)精通CSS,能够还原视觉设计,并兼容业界承认的主流浏览器。

    3)熟悉JavaScript,了解ECMAScript基础内容,掌握1~2种js框架,如JQuery

    4)对常见的浏览器兼容问题有清晰的理解,并有可靠的解决方案。

    5)对性能有一定的要求,了解yahoo的性能优化建议,并可以在项目中有效实施。

    Web后端:

    1)精通jsp,servlet,java bean,JMS,EJB,Jdbc,Flex开发,或者对相关的工具、类库以及框架非常熟悉,如Velocity,Spring,Hibernate,iBatis,OSGI等,对Web开发的模式有较深的理解

    2)练使用oracle、sqlserver、mysql等常用的数据库系统,对数据库有较强的设计能力

    3)熟悉maven项目配置管理工具,熟悉tomcat、jboss等应用服务器,同时对在高并发处理情况下的负载调优有相关经验者优先考虑

    4)精通面向对象分析和设计技术,包括设计模式、UML建模等

    5)熟悉网络编程,具有设计和开发对外API接口经验和能力,同时具备跨平台的API规范设计以及API高效调用设计能力

    展开全文
  • 1.1 后端基础设施使用Java后端技术的目的就是构建业务应用,为用户提供在线或者离线服务。因此,一个业务应用需要哪些技术、依赖哪些基础设施就决定了需要掌握的后端技术有哪些。纵观整个互...

    1.1 后端基础设施

    使用Java后端技术的目的就是构建业务应用,为用户提供在线或者离线服务。因此,一个业务应用需要哪些技术、依赖哪些基础设施就决定了需要掌握的后端技术有哪些。纵观整个互联网技术体系再结合公司的目前状况,笔者认为必不可少或者非常关键的后端基础技术/设施如下图所示:

    这里的后端基础设施主要指的是应用在线上稳定运行需要依赖的关键组件或者服务。开发或者搭建好以上的后端基础设施,一般情况下是能够支撑很长一段时间内的业务的。此外,对于一个完整的架构来说,还有很多应用感知不到的系统基础服务,如负载均衡、自动化部署、系统安全等,并没有包含在本章的描述范围内。

    1.1.1 统一请求入口-API网关

    在移动APP的开发过程中,通常后端提供的接口需要以下功能的支持:

    • 负载均衡

    • API访问权限控制

    • 用户鉴权

    一般的做法,使用Nginx做负载均衡,然后在每个业务应用里做API接口的访问权限控制和用户鉴权,更优化一点的方式则是把后两者做成公共类库供所有业务调用。

    但从总体上来看,这三种特性都属于业务的公共需求,更可取的方式则是集成到一起作为一个服务,既可以动态地修改权限控制和鉴权机制,也可以减少每个业务集成这些机制的成本。这种服务就是API网关,可以选择自己实现。也可以使用开源软件实现,如Kong和Netflix Zuul。API网关一般架构如下图所示:

    但是以上方案的一个问题是由于所有API请求都要经过网关,它很容易成为系统的性能瓶颈。因此,可以采取的方案是:去掉API网关,让业务应用直接对接统一认证中心,在基础框架层面保证每个API调用都需要先通过统一认证中心的认证,这里可以采取缓存认证结果的方式避免对统一认证中心产生过大的请求压力。

    1.1.2 业务应用和后端基础框架

    业务应用分为:在线业务应用和内部业务应用。

    在线业务应用:直接面向互联网用户的应用、接口等,典型的特点就是:请求量大、高并发、对故障的容忍度低。

    内部业务应用:主要面向公司内部用户的应用。比如,内部数据管理平台、广告投放平台等。相比起在线业务应用,其特点: 数据保密性高、压力小、并发量小、允许故障的发生。

    业务应用基于后端的基础框架开发,针对Java后端来说,应该有以下几个框架:

    MVC框架:统一开发流程、提高开发效率、屏蔽一些关键细节的Web/后端框架。典型的如SpringMVC、Jersey以及国人开发的JFinal以及阿里的WebX。

    IOC框架:实现依赖注入/控制反转的框架。Java中最为流行的Spring框架的核心就是IOC功能。

    ORM框架:能够屏蔽底层数据库细节,提供统一的数据访问接口的数据库操作框架,额外地能够支持客户端主从、分库、分表等分布式特性。MyBatis是目前最为流行的ORM框架。

    此外,Spring ORM中提供的JdbcTemplate也很不错。当然,对于分库分表、主从分离这些需求,一般就需要自己实现,开源的则有阿里的TDDL、当当的sharding-jdbc(从datasource层面解决了分库分表、读写分离的问题,对应用透明、零侵入)。

    此外,为了在服务层面统一解决分库分表、读写分离、主备切换、缓存、故障恢复等问题,很多公司都是有自己的数据库中间件的,比如阿里的Cobar、360的Atlas(基于MySQL-Proxy)、网易的DDB等;开源的则有MyCat(基于Cobar)和Kingshard,其中Kingshard已经有一定的线上使用规模。MySQL官方也提供了MySQL Proxy, 可以使用lua脚本自定义主从、读写分离、分区这些逻辑,但其性能较差,目前使用较少。

    缓存框架:对Redis、Memcached这些缓存软件操作的统一封装,能够支持客户端分布式方案、主从等。一般使用Spring的RedisTemplate即可,也可以使用Jedis做自己的封装,支持客户端分布式方案、主从等。

    JavaEE应用性能检测框架:对于线上的JavaEE应用,需要有一个统一的框架集成到每一个业务中检测每一个请求、方法调用、JDBC连接、Redis连接等的耗时、状态等。Jwebap是一个可以使用的性能检测工具,但由于其已经很多年没有更新,有可能的话建议基于此项目做二次开发。

    一般来说,以上几个框架即可以完成一个后端应用的雏形。

    1.1.3 缓存、数据库、搜索引擎、消息队列

    缓存、数据库、搜索引擎、消息队列这四者都是应用依赖的后端基础服务,他们的性能直接影响到了应用的整体性能,有时候你代码写的再好也许就是因为这些服务导致应用性能无法提升上去。

    缓存: 缓存通常被用来解决热点数据的访问问题,是提高数据查询性能的强大武器。在高并发的后端应用中,将数据持久层的数据加载到缓存中,能够隔离高并发请求与后端数据库,避免数据库被大量请求击垮。

    目前常用的除了在内存中的本地缓存,比较普遍的集中缓存软件有Memcached和Redis。其中Redis已经成为最主流的缓存软件。

    数据库:数据库可以说是后端应用最基本的基础设施。基本上绝大多数业务数据都是持久化存储在数据库中的。

    主流的数据库包括传统的关系型数据库(MySQL、PostgreSQL)以及最近几年开始流行的NoSQL(MongoDB、HBase)。其中HBase是用于大数据领域的列数据库,受限于其查询性能,一般并不用来做业务数据库。

    搜索引擎:搜索引擎是针对全文检索以及数据各种维度查询设计的软件。目前用的比较多的开源软件是Solr和Elasticsearch,都是基于Lucence来实现的,不同之处主要在于termIndex的存储、分布式架构的支持等。Elasticsearch由于对集群的良好支持以及高性能的实现,已经逐渐成为搜索引擎的主流开源方案。

    消息队列:数据传输的一种方式就是通过消息队列。目前用的比较普遍的消息队列包括为日志设计的Kafka以及重事务的RabbitMQ等。在对消息丢失不是特别敏感且并不要求消息事务的场景下,选择Kafka能够获得更高的性能;否则,RabbitMQ则是更好的选择。

    此外,ZeroMQ则是一种实现消息队列的网络编程Pattern库,位于Socket之上,MQ之下。

    1.1.4 文件存储

    不管是业务应用、依赖的后端服务还是其他的各种服务,最终还是要依赖于底层文件存储的。

    通常来说,文件存储需要满足的特性有:可靠性、容灾性、稳定性,即要保证存储的数据不会轻易丢失,即使发生故障也能够有回滚方案,也要保证高可用。

    在底层可以采用传统的RAID作为解决方案,再上一层,目前Hadoop的HDFS则是最为普遍的分布式文件存储方案,当然还有NFS、Samba这种共享文件系统也提供了简单的分布式存储的特性。

    此外,如果文件存储确实成为了应用的瓶颈或者必须提高文件存储的性能从而提升整个系统的性能时,那么最为直接和简单的做法就是抛弃传统机械硬盘,用SSD硬盘替代。

    像现在很多公司在解决业务性能问题的时候,最终的关键点往往就是SSD。这也是用钱换取时间和人力成本最直接和最有效的方式。在数据库部分描述的SSDB就是对LevelDB封装之后,利用SSD硬盘的特性的一种高性能KV数据库。

    至于HDFS,如果要使用上面的数据,是需要通过Hadoop的。类似xx on Yarn的一些技术就是将非Hadoop技术跑在HDFS上的解决方案。

    1.1.5 统一认证中心

    统一认证中心,主要是对APP用户、内部用户、APP等的认证服务,包括

    • 用户的注册、登录验证、Token鉴权

    • 内部信息系统用户的管理和登录鉴权

    • APP的管理,包括APP的secret生成,APP信息的验证(如验证接口签名)等。

    之所以需要统一认证中心,就是为了能够集中对这些所有APP都会用到的信息进行管理,也给所有应用提供统一的认证服务。尤其是在有很多业务需要共享用户数据的时候,构建一个统一认证中心是非常必要的。

    此外,通过统一认证中心构建移动APP的单点登录也是水到渠成的事情:模仿Web的机制,将认证后的信息加密存储到本地存储中供多个APP使用。

    1.1.6 单点登录系统

    目前很多大的在线Web网站都是有单点登录系统的,通俗的来说就是只需要一次用户登录,就能够进入多个业务应用(权限可以不相同),非常方便用户的操作。而在移动互联网公司中,内部的各种管理、信息系统甚至外部应用同样也需要单点登录系统。

    目前,比较成熟的、用的最多的单点登录系统应该是耶鲁大学开源的CAS, 可以基于 https://github.com/apereo/cas/tree/master/cas-server-webapp 来定制开发的。

    基本上,单点登录的原理都类似下图所示:

    1.1.7 统一配置中心

    在Java后端应用中,一种读写配置比较通用的方式就是将配置文件写在Propeties、YAML、HCON等文件中,修改的时候只需要更新文件重新部署即可,可以做到不牵扯代码层面改动的目的。

    统一配置中心,则是基于这种方式之上的统一对所有业务或者基础后端服务的相关配置文件进行管理的统一服务, 具有以下特性:

    • 能够在线动态修改配置文件并生效

    • 配置文件可以区分环境(开发、测试、生产等)

    • 在Java中可以通过注解、XML配置的方式引入相关配置

    百度开源的Disconf和携程的Apollo是可以在生产环境使用的方案,也可以根据自己的需求开发自己的配置中心,一般选择Zookeeper作为配置存储。

    1.1.8 服务治理框架

    对于外部API调用或者客户端对后端API的访问,可以使用HTTP协议或者RESTful(当然也可以直接通过最原始的socket来调用)。但对于内部服务间的调用,一般都是通过RPC机制来调用的。

    目前主流的RPC协议有:

    • RMI

    • Hessian

    • Thrift

    • Dubbo

    这些RPC协议各有优劣点,需要针对业务需求做出最好的选择。

    这样,当你的系统服务在逐渐增多,RPC调用链越来越复杂,很多情况下,需要不停的更新文档来维护这些调用关系。一个对这些服务进行管理的框架可以大大减少因此带来的繁琐的人力工作。

    传统的ESB(企业服务总线)本质就是一个服务治理方案,但ESB作为一种proxy的角色存在于Client和Server之间,所有请求都需要经过ESB,使得ESB很容易成为性能瓶颈。因此,基于传统的ESB,更好的一种设计如下图所示:

    如图,以配置中心为枢纽,调用关系只存在于Client和提供服务的Server之间,就避免了传统ESB的性能瓶颈问题。

    对于这种设计,ESB应该支持的特性如下:

    • 服务提供方的注册、管理

    • 服务消费者的注册、管理

    • 服务的版本管理、负载均衡、流量控制、服务降级、资源隔离

    • 服务的容错、熔断

    阿里开源的Dubbo则对以上做了很好的实现,也是目前很多公司都在使用的方案;当当网的扩展项目Dubbox则在Dubbo之上加入了一些新特性。

    目前,Dubbo已经被阿里贡献给Apache,处于incubating状态。在运维监控方面,Dubbo本身提供了简单的管理控制台dubbo-admin和监控中心dubbo-monitor-simple。Github上的dubboclub/dubbokeeper则是在其之上开发的更为强大的集管理与监控于一身的服务管理以及监控系统。

    此外,Netflix的Eureka也提供了服务注册发现的功能,其配合Ribbon可以实现服务的客户端软负载均衡,支持多种灵活的动态路由和负载均衡策略。

    1.1.9 统一调度中心

    在很多业务中,定时调度是一个非常普遍的场景,比如定时去抓取数据、定时刷新订单的状态等。通常的做法就是针对各自的业务依赖Linux的Cron机制或者Java中的Quartz。

    统一调度中心则是对所有的调度任务进行管理,这样能够统一对调度集群进行调优、扩展、任务管理等。Azkaban和Yahoo的Oozie是Hadoop的流式工作管理引擎,也可以作为统一调度中心来使用。当然,你也可以使用Cron或者Quartz来实现自己的统一调度中心。

    • 根据Cron表达式调度任务

    • 动态修改、停止、删除任务

    • 支持任务分片执行

    • 支持任务工作流:比如一个任务完成之后再执行下一个任务

    • 任务支持脚本、代码、url等多种形式

    • 任务执行的日志记录、故障报警

    对于Java的Quartz这里需要说明一下:这个Quartz需要和Spring Quartz区分,后者是Spring对Quartz框架的简单实现也是目前使用的最多的一种调度方式。但其并没有做高可用集群的支持。而Quartz虽然有集群的支持,但是配置起来非常复杂。现在很多方案都是使用Zookeeper来实现Spring Quartz的分布式集群。

    此外,当当网开源的elastic-job则在基础的分布式调度之上又加入了弹性资源利用等更为强大的功能。

    1.1.10 统一日志服务

    日志是开发过程必不可少的东西。打印日志的时机、技巧是很能体现出工程师编码水平的。毕竟,日志是线上服务能够定位、排查异常最为直接的信息。

    通常的,将日志分散在各个业务中非常不方便对问题的管理和排查。统一日志服务则使用单独的日志服务器记录日志,各个业务通过统一的日志框架将日志输出到日志服务器上。

    可以通过实现Log4j或者Logback的Appender来实现统一日志框架,然后通过RPC调用将日志打印到日志服务器上。

    1.1.11 数据基础设施

    数据是最近几年非常火的一个领域。从《精益数据分析》到《增长黑客》,都是在强调数据的非凡作用。很多公司也都在通过数据推动产品设计、市场运营、研发等。

    这里需要说明的一点是,只有当你的数据规模真的到了单机无法处理的规模才应该上大数据相关技术,千万不要为了大数据而大数据。很多情况下使用单机程序+MySQL就能解决的问题非得上Hadoop即浪费时间又浪费人力。

    这里需要补充一点的是,对于很多公司,尤其是离线业务并没有那么密集的公司,在很多情况下大数据集群的资源是被浪费的。因此诞了 xx on Yarn 一系列技术让非Hadoop系的技术可以利用大数据集群的资源,能够大大提高资源的利用率,如Dockeron Yarn。

    数据高速公路

    接着上面讲的统一日志服务,其输出的日志最终是变成数据到数据高速公路上供后续的数据处理程序消费的。这中间的过程包括日志的收集和传输。

    收集:统一日志服务将日志打印在日志服务上之后,需要日志收集机制将其集中起来。目前,常见的日志收集方案有:Scribe、Chukwa、Kakfa和Flume。对比如下图所示:

    此外,Logstash也是一个可以选择的日志收集方案,不同于以上的是,它更倾向于数据的预处理,且配置简单、清晰,经常以ELK(Elasticsearch + Logstash + Kibana)的架构用于运维场景中。

    传输:通过消息队列将数据传输到数据处理服务中。对于日志来说,通常选择Kafka这个消息队列即可。

    此外,这里还有一个关键的技术就是数据库和数据仓库间的数据同步问题,即将需要分析的数据从数据库中同步到诸如Hive这种数据仓库时使用的方案。

    可以使用Apache Sqoop进行基于时间戳的数据同步,此外,阿里开源的Canal实现了基于binlog增量同步,更加适合通用的同步场景,但是基于Canal还是需要做不少的业务开发工作。

    离线数据分析

    离线数据分析是可以有延迟的,一般针对的是非实时需求的数据分析工作,产生的也是延迟一天的报表。目前最常用的离线数据分析技术除了Hadoop还有Spark。

    相比Hadoop,Spark性能上有很大优势,当然对硬件资源要求也高。其中,Hadoop中的Yarn作为资源管理调度组件除了服务于MR还可以用于Spark(Spark on Yarn),Mesos则是另一种资源管理调度系统。

    对于Hadoop,传统的MR编写很复杂,也不利于维护,可以选择使用Hive来用SQL替代编写MR。而对于Spark,也有类似Hive的Spark SQL。

    此外,对于离线数据分析,还有一个很关键的就是数据倾斜问题。所谓数据倾斜指的是region数据分布不均,造成有的结点负载很低,而有些却负载很高,从而影响整体的性能。处理好数据倾斜问题对于数据处理是很关键的。

    实时数据分析

    相对于离线数据分析,实时数据分析也叫在线数据分析,针对的是对数据有实时要求的业务场景,如广告结算、订单结算等。目前,比较成熟的实时技术有Storm和Spark Streaming。相比起Storm,Spark Streaming其实本质上还是基于批量计算的。

    如果是对延迟很敏感的场景,还是应该使用Storm。除了这两者,Flink则是最近很火的一个分布式实时计算框架,其支持Exactly Once的语义,在大数据量下具有高吞吐低延迟的优势,并且能够很好的支持状态管理和窗口统计,但其文档、API管理平台等都还需要完善。

    实时数据处理一般情况下都是基于增量处理的,相对于离线来说并非可靠的,一旦出现故障(如集群崩溃)或者数据处理失败,是很难对数据恢复或者修复异常数据的。因此结合离线+实时是目前最普遍采用的数据处理方案。Lambda架构就是一个结合离线和实时数据处理的架构方案。

    此外,实时数据分析中还有一个很常见的场景:多维数据实时分析,即能够组合任意维度进行数据展示和分析。

    目前有两种解决此问题的方案:ROLAP和MOLAP。

    • ROLAP:使用关系型数据库或者扩展的关系型数据库来管理数据仓库数据,以Hive、Spark SQL、Presto为代表。

    • MOLAP:基于数据立方体的多位存储引擎,用空间换时间,把所有的分析情况都物化为物理表或者视图。以Druid、Pinot和Kylin为代表,不同于ROLAP(Hive、Spark SQL), 其原生的支持多维的数据查询。

    如上一小节所述,ROLAP的方案大多数情况下用户离线数据分析,满足不了实时的需求,因此MOLAP是多维数据实时分析的常用方案。对于其中常用的三个框架,对比如下:

    .使用场景语言协议特点
    Druid实时处理分析JavaJSON实时聚合
    Pinot实时处理分析JavaJSON实时聚合
    KylinOLAP分析引擎JavaJDBC/OLAP预处理、cache

    其中,Druid相对比较轻量级,用的人较多,比较成熟。

    数据即席分析

    离线和实时数据分析产生的一些报表是给数据分析师、产品经理参考使用的,但是很多情况下,线上的程序并不能满足这些需求方的需求。这时候就需要需求方自己对数据仓库进行查询统计。

    针对这些需求方,SQL上手容易、易描述等特点决定了其可能是一个最为合适的方式。因此提供一个SQL的即席查询工具能够大大提高数据分析师、产品经理的工作效率。

    Presto、Impala、Hive都是这种工具。如果想进一步提供给需求方更加直观的ui操作界面,可以搭建内部的Hue。

    1.1.12 故障监控

    对于面向用户的线上服务,发生故障是一件很严重的事情。因此,做好线上服务的故障检测告警是一件非常重要的事情。可以将故障监控分为以下两个层面的监控:

    系统监控:主要指对主机的带宽、CPU、内存、硬盘、IO等硬件资源的监控。可以使用Nagios、Cacti等开源软件进行监控。目前,市面上也有很多第三方服务能够提供对于主机资源的监控,如监控宝等。

    对于分布式服务集群(如Hadoop、Storm、Kafka、Flume等集群)的监控则可以使用Ganglia。此外,小米开源的OpenFalcon也很不错,涵盖了系统监控、JVM监控、应用监控等,也支持自定义的监控机制。

    业务监控:是在主机资源层面以上的监控,比如APP的PV、UV数据异常、交易失败等。需要业务中加入相关的监控代码,比如在异常抛出的地方,加一段日志记录。

    监控还有一个关键的步骤就是告警。告警的方式有很多种:邮件、IM、短信等。考虑到故障的重要性不同、告警的合理性、便于定位问题等因素,有以下建议:

    • 告警日志要记录发生故障的机器ID,尤其是在集群服务中,如果没有记录机器ID,那么对于后续的问题定位会很困难。

    • 要对告警做聚合,不要每一个故障都单独进行告警,这样会对工程师造成极大的困扰。

    • 要对告警做等级划分,不能对所有告警都做同样的优先级处理。

    • 使用微信做为告警软件,能够在节省短信成本的情况下,保证告警的到达率。

    故障告警之后,那么最最关键的就是应对了。对于创业公司来说,24小时待命是必备的素质,当遇到告警的时候,需要尽快对故障做出反应,找到问题所在,并能在可控时间内解决问题。

    对于故障问题的排查,基本上都是依赖于日志的。只要日志打的合理,一般情况下是能够很快定位到问题所在的,但是如果是分布式服务,并且日志数据量特别大的情况下,如何定位日志就成为了难题。

    这里有几个方案:

    建立ELK(Elasticsearch + Logstash + Kibana)日志集中分析平台,便于快速搜索、定位日志。搭配Yelp开源的Elastalert可以实现告警功能。

    建立分布式请求追踪系统(也可以叫全链路监测系统),对于分布式系统尤是微服务架构,能够极大的方便在海量调用中快速定位并收集单个异常请求信息,也能快速定位一条请求链路的性能瓶颈。

    唯品会的Mercury、阿里的鹰眼、新浪的WatchMan、Twitter开源的Zipkin基本都是基于Google的Dapper论文而来,大众点评的实时应用监控平台CAT则在支持分布式请求追踪(代码侵入式)的基础上加入了细粒度的调用性能数据统计。

    此外,Apache正在孵化中的HTrace则是针对大的分布式系统诸如HDFS文件系统、HBase存储引擎而设计的分布式追踪方案。而如果你的微服务实现使用了Spring Cloud,那么Spring Cloud Sleuth则是最佳的分布式跟踪方案。

    还需要提到的是,Apache孵化中的SkyWalking是基于分布式追踪的一个完备的APM(应用性能监测)系统,其最大的一个特点就是基于Java agent + instrument api,对业务代码无任何侵入,Pinpoint则是类似的另一个已经用于生产环境的APM系统。

    展开全文
  • web前端分为网页设计师、网页美工、web前端开发工程师。 首先网页设计师是对网页的架构、...web前端需要掌握的脚本技术javascript DIV+CSS现下最流行的页面搭建技术,ajax和jquery以及简单的后端程序等。 后端的话...
  • 下述整理的180道Java后端常问的面试体系汇总,整理出一份知识点复习笔记和Java后端高频知识考点专题文档答案免费分享给大家! 由于篇幅原因,在这只把部分的题目列举出来,答案就不做全部展示了,这些题我已经...
  • 接着第一天的尾,继续来学习性能测试,上一次说到性能要大致经历哪些阶段,那么我们也来看下行业的做法:  行业两种做法,一个是TPC,另一个是SPEC; TPC:指定业务类型,获得该指定业务的性能指标,也就是说...
  • 书架主要针对Java后端和全栈开发用的 书籍介绍 《Spring Boot 2.0企业级应用开发实战》 本书深入浅岀地讲解了 Spring与 Spring Boot所涉及的重要知识点。更特色的是,针对一个博客系统的开发过程,来描述所涉及的...
  • 架构师 请设计一个中继服务器,转发客户端A->客户端B的请求,并想办法缩短TCP 3次的握手时间,并保证安全性和...PHP进程死锁造成的原因有哪些,怎么自动检测和自动恢复? MongoDB集群的数据聚合原理是什么,有...
  • 商品中心的数据应用场景也非常多,从前端来说,所有展示给用户的关于商品的信息,均为商品中心所提供,比如商详,订单,营销,等提供所有的数据支撑,从后端来说,商品中心为订单,仓库管理,供应商管理,渠道管理,...
  • Web开发行业中两个重要的两个术语:前端和后端,它们彼此非常不同。那么它们之间什么差异?本篇文章就来带大家了解一下web前端与后端的区别,希望对大家有所帮助,下面和千锋重庆web前端的小编一起来看看吧! ​...
  • 史上最全的后端技术大全,你都了解哪些技术呢? 2019年09月03日 08:38:00运维之美阅读数 469 | 导语工欲善其事,必先利其器;士欲宣其义,必先读其书。后台开发作为互联网技术领域的掌上明珠,一直都是开发者们...
  • Node后端数据渲染

    千次阅读 2017-05-08 09:39:56
    对于前端开发者来说,在大型Web应用开发中,很多时候并不需要完全重新设计...本文带我们学习通常前后端分离的开发模式下有哪些问题,利用Node端的服务又是如何帮助我们解决这些问题的。 本文选自《现代前端技术解析》。
  • 最近要做个视频社交移动应用产品,我主要负责后端架构这方面。先列了几个选项,分别谈一谈,断断续续写的,想到哪些记下来 几个后端方案的选型:SpringBoot、Jersey、Play、Django、Go、Node.js、C&C++。 ...
  • 点击上方 "后端架构师"关注,星标或置顶一起成长后台回复“大礼包”惊喜礼包!关注订阅号「后端架构师」,收看更多精彩内容每日英文Mistake is temporary...
  • 本文将从后台开发所涉及到的技术术语出发,基于系统开发、架构设计、网络通信等几个方面让大家对后台开发一个清晰的了解,讲解全面易懂。 目录 一、系统开发 1. 高内聚/低耦合 2. 过度设计 3. ...
  • 本系统技术栈用到了Dubbo、Zookeeper、SpringBoot、Oauth2、Swagger、Nginx,项目刚开始起步,每完成一个大功能都会专门写一篇博文来记录技术细节以及遇到的技术难点,如项目中有哪些设计或者架构不太正确的地方,请...
  • 2020再见,后端

    2020-06-13 14:37:45
    前言 虽然 2020 开局不顺,但生活工作还是要往前看的。目前在互联网行业内,尤其是大厂之间对人才的抢夺愈演愈烈。如何在后疫情时代,快速提升自身实力,尽快达到心仪企业的用人...具体学习哪些技术分享,图中都.
  • 谈谈互联网后端基础设施

    千次阅读 2016-09-09 10:06:25
    「运维之美」专注于运维领域各类相关技术与内容的分享,每天都技术干货文章推荐。文章主要涉及Linux/Unix相关内容,包括:工具资源、使用技巧、集群架构等,欢迎大家关注。   对于一个互联网企业,后端...
  • 第1章 理解高性能Python读完本章之后你将能够回答下列问题计算机架构有哪些元素?常见的计算机架构有哪些?计算机架构在Python中的抽象表达是什么?实现高性能Python代码的障碍在哪里?性能问题有哪些种类?计算机...
  • 转载自 架构师之路:从码农到架构师你差了哪些 Web应用,最常见的研发语言是Java和PHP。 后端服务,最常见的研发语言是Java和C/C++。 大数据,最常见的研发语言是Java和Python。 可以说,Java是现...
  • 4、有哪些接口 5、用户管理模块有哪些表 6、有没有建索引 7、说一下MYSQL索引 8、最左前缀索引 9、用的什么存储引擎,为什么用InnoDB 10、什么业务需要事物 11、有没有用外键关联,为什么用,解决了什么问题 12、有...

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 368
精华内容 147
关键字:

后端架构有哪些