精华内容
下载资源
问答
  • 便利 方便的Docker镜像,用于在云原生环境下进行调试和检查
  • 一张图理解Flutter中Dart与原生环境通信 Flutter中提供了Dart与原生环境通信的机制Platform Channels。通过该机制可以扩展Flutter,实现调用原生系统Api的能力。官方介绍图如下: [外链图片转存失败(img-oseSHSo7-...

    一张图理解Flutter中Dart与原生环境通信

    Flutter中提供了Dart与原生环境通信的机制Platform Channels。通过该机制可以扩展Flutter,实现调用原生系统Api的能力。官方介绍图如下:

    那么Flutter是怎么实现这套机制的?在设计这套机制时有哪些值得关注的重点?
    这里以Android为例,以一张图解释整个通信流程。
    废话不多说,先上图:

    其中Java与Dart两个语言环境通过C++层做消息中转。Java与C++通信的技术叫做JNI,Dart与C++的通信与JNI类似,可以叫做NativeBinding。

    在设计整个机制时,需要注意一下几点。

    编码与解码

    由于不同语言中的数据类型是不同的,所以在数据传递过程中,需要将其转换成大家都能理解的数据类型。Flutter中支持的数据类型对应关系如下:

    Dart Android iOS
    null null nil (NSNull when nested)
    bool java.lang.Boolean NSNumber numberWithBool:
    int java.lang.Integer NSNumber numberWithInt:
    int, if 32 bits not enough java.lang.Long NSNumber numberWithLong:
    double java.lang.Double NSNumber numberWithDouble:
    String java.lang.String NSString
    Uint8List byte[] FlutterStandardTypedData typedDataWithBytes:
    Int32List int[] FlutterStandardTypedData typedDataWithInt32:
    Int64List long[] FlutterStandardTypedData typedDataWithInt64:
    Float64List double[] FlutterStandardTypedData typedDataWithFloat64:
    List java.util.ArrayList NSArray
    Map java.util.HashMap NSDictionary

    Android环境的编解码是由MessageCodec接口定义的:

    package io.flutter.plugin.common;
    
    public interface MessageCodec<T> {
        @Nullable
        ByteBuffer encodeMessage(@Nullable T var1);
    
        @Nullable
        T decodeMessage(@Nullable ByteBuffer var1);
    }
    

    为了实现不同语言的数据类型对应与转换,需要寻找一种大家都认识的数据类型,也就是计算机世界的最基本的数据类型—byte字节。
    所以Flutter中的标准编解码器,将不同的数据类型高效的编码成字节序列。下面以编解码一个int类型为例做说明:

    int编码

    //字节数组输出流
    ByteArrayOutputStream stream;
    //Int类型标识
    private static final byte INT = 3;
    
    //先写入int类型标识,表明接下来的四个字节要组成一个int整型。
    stream.write(3);
    
    protected static final void writeInt(ByteArrayOutputStream stream, int value) {
    //依次写入int低8位
    //这次要区分系统平台的字节序,分为大端序和小端序
       if (LITTLE_ENDIAN) {
           stream.write(value);
           stream.write(value >>> 8);
           stream.write(value >>> 16);
           stream.write(value >>> 24);
       } else {
           stream.write(value >>> 24);
           stream.write(value >>> 16);
           stream.write(value >>> 8);
           stream.write(value);
       }
    }
    

    int解码

    protected final Object readValue(ByteBuffer buffer) {
       if (!buffer.hasRemaining()) {
           throw new IllegalArgumentException("Message corrupted");
       } else {
           //先读取一个字节,判断是什么类型的数据
           byte type = buffer.get();
           return this.readValueOfType(type, buffer);
       }
    }
    
    protected Object readValueOfType(byte type, ByteBuffer buffer) {
        //如果是int整型数据,则一次性读取四个字节,然后返回一个int整型
        case 3:
           result = buffer.getInt();
           break;
    }
    

    通过上面的编码,就可以将Java层中的数据传递给C++层,C++层转发给Dart后,Dart层在按照相同的规则解码成Dart语言中对应的数据类型。

    除了标准的编解码方式StandardMethodCodec,Flutter还提供了其他三种方式:

    • BinaryCodec
    • StringCodec
    • JSONMessageCodec

    BinaryCodec 用于直接传输字节数组,没有做任何操作

    StandardMethodCodec 用于PlatformViewsChannel

    StringCodec用于字符串和字节数组的转换,例如Flutter中生命周期渠道LifecycleChannel、

    JSONMessageCodec用于大部分场景,如键盘事件KeyEventChannel、页面导航事件NavigationChannel、平台事件PlatformChannel、文本编辑事件TextInputChannel等

    返回值回调

    从发送端到目的端的一次通信过程很简单,但是如果发送端需要获得目的端的响应结果,类似于一个有返回值的方法调用,那么这个返回值如何正确的响应给发送端?
    下面看一下Flutter中的做法:

    package io.flutter.embedding.engine.dart;
    
    class DartMessenger implements BinaryMessenger, PlatformMessageHandler {
        private final Map<Integer, BinaryReply> pendingReplies;
        private int nextReplyId = 1;
        
        // 当发送消息时,可以指定BinaryReply类型的回调
       public void send(@NonNull String channel, @Nullable ByteBuffer message, @Nullable BinaryReply callback) {
           Log.v("DartMessenger", "Sending message with callback over channel '" + channel + "'");
           // 为callback生成唯一标识,存储到Map容器pendingReplies中
           int replyId = 0;
           if (callback != null) {
               replyId = this.nextReplyId++;
               this.pendingReplies.put(replyId, callback);
           }
        
           if (message == null) {
               this.flutterJNI.dispatchEmptyPlatformMessage(channel, replyId);
           } else {
               this.flutterJNI.dispatchPlatformMessage(channel, message, message.position(), replyId);
           }
        
        }
        
        //消息处理完成后,根据回调标识replyId从Map容器pendingReplies中取出对应回调BinaryReply实例并执行
       public void handlePlatformMessageResponse(int replyId, @Nullable byte[] reply) {
           Log.v("DartMessenger", "Received message reply from Dart.");
           BinaryReply callback = (BinaryReply)this.pendingReplies.remove(replyId);
           if (callback != null) {
               try {
                   Log.v("DartMessenger", "Invoking registered callback for reply from Dart.");
                   callback.reply(reply == null ? null : ByteBuffer.wrap(reply));
               } catch (Exception var5) {
                   Log.e("DartMessenger", "Uncaught exception in binary message reply handler", var5);
               }
           }
        
        }
    }
    

    通过上面源码分析可以知道,当需要返回值时需要传出一个回调callback实例,但是这个callback实例不会随着消息传递给Dart层,而是生成一个整型标识与之对应。通过传递这个整型标识来决定由哪个回调来处理返回值。

    区分不同的应用场景

    通过前面的编解码部分,我们了解了Flutter中提供了四种编解码方式,这四种编解码方式提供了对不同数据类型处理的能力,包含基础数据类型、String、JSON、字节数组,他们应用在了不同的通信渠道场景中。
    那么所有的通信渠道场景都是基于三种基础通信渠道衍生出来的。

    • BasicMessageChannel
    • EventChannel
    • MethodChannel

    这三种通信模式不关心具体编解码方式,而是依据特定的使用场景添加了额外的操作功能。

    BasicMessageChannel

    用于使用基本的异步消息传递与Flutter应用程序通信的命名通道。

    @UiThread
    public void send(@Nullable T message, @Nullable BasicMessageChannel.Reply<T> callback) {
       this.messenger.send(this.name, this.codec.encodeMessage(message), callback == null ? null : new BasicMessageChannel.IncomingReplyHandler(callback));
    }
    

    这种通信方式实现了最基本的信息发送和接收,只是添加了一步编解码操作。

    EventChannel

    用于和平台插件以事件流方式通信的命名通道。例如监听手机电量、GPS位置等,需要原生系统不停的向Flutter应用发送变化后的数据。

    既然是事件流,就必须提供连个操作接口:
    添加监听
    取消监听

    如下代码所示:

    public interface StreamHandler {
       void onListen(Object var1, EventChannel.EventSink var2);
    
       void onCancel(Object var1);
    }
    

    当Dart层需要对某个EventChannel的事件流发起监听时,需要调用listen方法,对应到StreamHandler的onListen。当有新的事件发生时,通过EventSink将消息封装好后,传递给Dart层的事件接口函数_onEvent,该函数名是固定的。

    当Dart层不再需要接受新的事件时,需要调用cancel方法,对应StreamHandler的onCancel。之后原生平台就不会发送新事件,并且释放本地的资源。

    MethodChannel

    用于和平台插件进行异步方法调用通信的命名管道。

    @UiThread
    public void invokeMethod(String method, @Nullable Object arguments, MethodChannel.Result callback) {
       this.messenger.send(this.name,
        this.codec.encodeMethodCall(new MethodCall(method, arguments)), 
       callback == null ? null : new MethodChannel.IncomingResultHandler(callback));
    }
    

    MethodChannel对外提供了invokeMethod方法,可以指定方法名称、参数、返回值回调,整个数据流转流程和我们在一开始给出的图中是一样的。
    其内部实现就是把所有东西封装成一个消息。

    总结

    通过对Flutter中PlatformChannel源码的梳理可以知道,Flutter中跨语言通信的原理就是将需要传递的内容编码成字节数组通过C++层传递到Dart层。各个层对应的数据类型分别是ByteBuffer(Java) -> uint8_t*(C++) -> ByteData(Dart)。
    同时,为了方便开发者使用,还针对不同的使用场景做了封装,如方法调用MethodChannel、事件流EventChannel。

    展开全文
  • <div><p>场景: 做了个地域选择级联&#...Picker却打开在了原生环境下。("react-native-picker": "^4.0.2") 不确定原因,看看有人碰到类似情况没有。 这里有个参考: ...
  • Fluid 本质上是一个云原生环境下的数据密集型应用的高效支撑平台。本文将向大家介绍 Fluid 项目是如何将数据密集型应用更高效地运行于 K8s 环境中的。 作者 | 顾荣 南京大学PASALab(注:本文基于作者公开演讲...

    简介: 为了解决大数据、AI 等数据密集型应用在云原生计算存储分离场景下,存在的数据访问延时高、联合分析难、多维管理杂等痛点问题,南京大学 PASALab、阿里巴巴、Alluxio 在 2020 年 9 月份联合发起了开源项目 Fluid。Fluid 本质上是一个云原生环境下的数据密集型应用的高效支撑平台。本文将向大家介绍 Fluid 项目是如何将数据密集型应用更高效地运行于 K8s 环境中的。

    头图.png

    作者 | 顾荣  南京大学 PASALab
    (注:本文基于作者公开演讲报告内容整理完成)
    来源 | 阿里巴巴云原生公众号

    得益于计算成本低、易于扩展、部署便捷、运维高效等多方面的优势,云计算平台吸引了越来越多的数据密集型应用在上面运行。如今,以 Kubernetes 为代表的云原生架构,因其灵活的资源可负载性以及高效的应用编排调度,在很多AI/大数据等数据密集型场景中应用广泛。然而,云原生环境和数据密集应用计算框架在早先设计理念和机制上存在天然分歧。因此,如何帮助数据密集型应用在云原生场景下高效、安全、便捷地访问数据,是一个既有理论意义又具应用价值的重要问题。

    为了解决大数据、AI 等数据密集型应用在云原生计算存储分离场景下,存在的数据访问延时高、联合分析难、多维管理杂等痛点问题,南京大学 PASALab、阿里巴巴、Alluxio 在 2020 年 9 月份联合发起了开源项目 Fluid。Fluid 本质上是一个云原生环境下的数据密集型应用的高效支撑平台。本文将向大家介绍 Fluid 项目是如何将数据密集型应用更高效地运行于 K8s 环境中的。

    项目背景简介

    1. 技术发展背景

    过去十年云计算、大数据、人工智能等技术发展突飞猛进。

    • 云计算平台领域:以 Docker、Kubernetes 为代表的容器及其编排的云原生技术,在应用服务部署自动化运维的浪潮当中得到了长足的发展。
    • 大数据处理领域:以 Hadoop、Spark、Alluxio 为代表的大数据并行计算与分布式存储技术,在众多行业领域大数据处理与存储的应用落地中几乎形成了主流生态。
    • 人工智能框架领域:PyTorch、Tensorflow、Caffe 等知名 AI 训练框架,在广大 AI 应用开发者反复使用和参与当中,发展日益成熟。

    其中,大数据应用和 AI 应用通常需要围绕大规模数据展开计算分析,是典型的数据密集型应用,而云计算平台得益于其计算成本和易于规模扩展的优势,以及容器化在高效部署和敏捷迭代方面的长处,吸引了越来越多的数据密集型应用在上面部署运行。

    大数据应用、AI、云计算三者的融合正在成为下一个重要的发展趋势。Gartner 预测,到 2023 年,70% 以上的 AI workloads 都将以应用容器化的方式部署运行,然后通过 Serverless 编程模型在云原生环境下进行构建。Spark 3.0.1 版本也开始支持 Kubernetes scheduler,拥抱云原生环境。

    • 详情见 Gartner 报告:

    https://www.gartner.com/en/conferences/emea/data-analytics-switzerland/featured-topics/topic-ai-machine-learning

    • Spark3.0.1 runs on K8s:

    https://spark.apache.org/docs/latest/running-on-kubernetes.html

    2. 面临的问题

    从用户的实际体验来看,现有云原生编排框架对数据密集型应用支持不够友好,主要体现在运行效率低下和数据管理复杂两方面。

    1.jpg

    运行效率低下:如上图所示,训练一个 RestNet50 神经网络,如果基于本地内存运行,大概每秒钟能训练近 1 万张图片;然而,在云原生环境下运行,基于 Cloud Storage 存储架构每秒训练的图片只能达到约 3000 张/秒,性能下降比较明显。

    数据管理复杂数据版本的多变、数据接口的多样、数据类型的抽象以及数据存储的异构,都给云原生环境下面向数据密集型应用支撑带来了挑战。

    3. 问题的原因分析

    云原生环境和数据密集处理框架在设计理念和机制上存在天然分歧,这两部分技术的早先产生和发展过程是相互独立的。我们可以看到,为了兼顾资源扩展的灵活性和使用成本,计算和存储分离的基本架构在云原生环境中大行其道;反观之,以大数据!

    2.jpg

    和 AI 训练为代表的数据密集型应用框架,为了减少数据传输,设计理念更多需要考虑数据本地化架构,两者在设计上存在分歧。

    另外,我们发现在云原生环境中,应用通常是以无状态(stateless)微服务化的方式进行部署,通过 FaaS(Function as a Service)方式串联。而在数据密集型框架应用中,是以数据抽象为中心开展,并进行任务分配执行,比如在 Spark 里都是围绕 RDD 构建整个大数据处理应用,中间加上算子。然而,无状态微服务并不是以数据为中心,这也存在设计上的分歧。

    3.jpg

    以上问题导致以 Kubernetes 为代表的云原生编排框架对于数据密集型应用,尤其是 AI 和大数据应用的支持还不够友好,具体体现在前面所述的运行效率低下、数据操作管理复杂等方面。

    我们纵观 Fluid 出现之前的云原生基金会(CNCF)全景图,涵盖了从应用交付 - 运维管理 - 底层存储的方方面面,但是缺少数据高效支撑组件这块重要拼图(注:Fluid近期刚进入CNCF 全景图,侧面反映本文理念得到了认可)。然而,这块拼图的缺失,就会造成大数据密集型应用在云原生环境下运行时,面临数据访问低效、数据隔离性弱、多数据源联合访问复杂方面的技术挑战。

    4. 云原生环境下的数据支撑挑战

    具体地,云原生环境下数据支撑的挑战主要分为三个方面

    • 第一:云平台计算存储分离架构导致数据访问延时高。为了监控资源灵活性满足本地无依赖的要求,云原生应用大多采用计算存储分离架构。但是从访问效率的角度来看,要求用云网络传输带宽,当数据密集型应用在云上运行时,会造成数据访问瓶颈、性能下降。
    • 第二:混合云场景下跨存储系统的联合分析困难。大多公司/组织通常基于不同存储管理数据支撑多样化应用,具备其各自的特点。Ceph、GlusterFS、HDFS 都会被广泛使用,数据也通常会散落在这些异构存储当中。然而,当需要联合数据进行综合性分析时,会增加数据移动成本,必然导致在云原生环境下需要面对网络费用、等待延时、人工操作等比较复杂的问题。
    • 第三:云环境中数据安全治理与多维度管理复杂。数据是很多公司的生命线,数据泄露、误操作、生命周期管理不当都会造成巨大损失。如何在云原生环境中保障数据的隔离,保护好用户的数据生命周期,都存在较大挑战。

    5. Kubernetes 生态中缺失的一块抽象

    综上所述,我们可以总结出一种现象:Kubernetes 生态中目前缺少数据密集型应用高效支撑的这块拼图。现有 Kubernetes 环境能对很多资源进行很好的抽象,包括将资源对象计算抽象成 Pod、将存储抽象成了 PV/PVC、将网络抽象成了 Service。云原生领域还有一些存储抽象主要面向数据持久化进行工作,提供对象和文件的持久化存储管理。但这些软件的功能缺乏以应用为中心的数据抽象及相关生命周期管理。

    6. 商店购物模式演变的联想

    为了更好地理解这些问题,我们可以做一些联想性的思考。如下图所示,引入商品购物模式,我们将商品、超市、客户类比为数据、存储、应用

    4.jpg

    • 商品数据都会被消费,商品会被消费者购买掉,数据会被应用读走,两者有一定类似性。
    • 超市存储类似,都起到贮藏与供应的功能。商品平时会贮藏在超市的货架上,当购买时扮演到供应的角色;对于存储而言,我们平时贮藏的数据都会被持久化到存储设备里,当应用需要时提供给用户。
    • 客户应用类似,客户会到商店消费购买商品。类似的,应用会到存储读取数据。

    商品、超市(商铺) 、客户模式,在过去几千年里发展得非常成熟,非常稳定。直到 2000 年之后发生了颠覆性的变化,这就是电商的产生。电商发明了线上购物模式,其特点体现在不再以店铺为中心而是以客户为中心,商品贮藏在仓库,客户可以在线上虚拟商铺挑选商品,最后由现代化物流将商品交付到客户,交易过程高效便捷、交易量更大。商品直接放在仓库里,仓库可以进行规范化、独立化管理,之后客户到电商平台上购买货物,会非常便捷、方便。客户不需要到店铺,在地铁上、车上、办公室、家里都可以用手机、电脑进行购物,而且不会存在商品寻找低效的情况,因为客户是在互联网上购物,都可以通过检索方式查找海量商品;线上购物的另一个优势是交易频次变得更高,交易量变得更大;客户也不需要必须去店里提货,快递可以直接送货上门,非常方便。

    5.jpg

    电商模式的成功有很多因素,其中有两大因素非常关键,一是如支付宝这样的第三方数字化支付工具的出现,二是如菜鸟这样专业化的物流系统产生,构建起四通八达的物流网络,使快速的商品寄送模式得以实现。反观回到现在计算机系统中,在现代云架构下,数据贮存在云存储系统中,数据密集型应用也以pod等各种各样资源描述符的方式在云原生环境下运行,但中间却缺乏一个高效的数据交付、数据递送的方式。也就是说,在云原生架构下面,数据贮藏在云存储系统当中,应用还是根据需要去访问数据,但由于类似的数据“物流系统”的缺失,导致数据密集型应用消费访问数据在云平台上比较低效

    6.jpg

    Fluid 核心理念

    基于以上的分析,以及从观察中得到的联想,下面来介绍 Fluid 的核心理念。

    1. Fluid 扮演云原生的“数据物流系统”角色

    7.jpg

    我们可以将 Fluid 所扮演角色理解为云原生环境下“数据物流系统”。回顾一下,在早先的大数据平台中,数据的访问尽量都是通过本地化进行。当用户写一个 MapReduce Job,Job 里包含很多 Task, 其中关注比较多的就是 MapTask 处理数据时是尽量将 Task 调度到用户要处理的数据所在的节点上运行。这种情况下,当用户访问数据时,尽管该数据是在 HDFS 这个分布式系统中,但本质上相当于从分布式系统中的本地节点上获取,我们称之为 Data Fetch。

    随着大数据生态系统的迅速发展,其上的应用框架变得越来越多,底层存储系统也变得越来越丰富,各种上层应用要访问不同种类、多样化系统的痛点越来越明显,于是出现了 Alluxio 这样一个优秀的开源项目,来统一管理底层不同存储系统,为上层提供统一化的标准接口,对上层应用屏蔽不同存储的差异。而且 Alluxio 提供内存缓存,加速数据访问。这个过程就解耦了本地化的情况,存储就可以实现分离。这种分离架构在部署好之后通常还是静态的,实现从 Data Fetch 变成 Data Access 的过程。

    Fluid 是在 Alluxio 基础之上,在云原生环境的调度层面上进行进一步的研究和拓展,希望获取云原生环境下数据节点以及应用的动态变化信息,让这一类静态的缓存等中间件动态、灵活地调动起来,从而让应用灵活性变得更强,实现数据智能化递送到应用的效果,即动态弹性(Data Delivery) 。

    在进行项目设计时,我们希望 Fluid 从视角、思路、理念三个层次带来一些革新:

    • 新视角:从云原生资源调度结合与数据密集型处理两个方面,重新综合审视云原生场景的数据抽象与支撑访问。
    • 新思路:针对容器编排缺乏数据感知,数据编排缺乏对云上架构变化的感知,提出了协同编排、多维管理、智能感知的一系列理念和创新方法;从而形成一套云原生环境下数据密集型应用的高效支撑平台。
    • 新理念:通过 Fluid 这个项目,希望让数据可以像流体一样在云平台中、在资源编排层和数据处理层之间能够灵活高效地被访问、转换和管理。

    2. 核心理念

    简单来说,Fluid 的核心理念,可以分为“一个抽象”和“两个编排”。

    首先在云原生环境里,抽象出了数据集的概念,它能够提供一个对底层存储的包装,对上层也能提供各种各样的支撑和访问能力,从而通过 API 的方式来简单地在 K8s 下实现对数据的操作。 

    在这个基础之上,Fluid 提供了两个编排的能力:

    首先是对于数据集进行编排,具体是指基于容器调度管理的数据进行编排。传统的方式只对数据本身进行管理,而 Fluid 的数据集编排则转为对承载数据的引擎进行编排和管理。通过对数据引擎进行合理的扩容、缩容和调度操作,和数据引擎的交互,从而实现对数据的迁移、缓存以及数据在 K8s 平台下灵活调度的管理和变化。

    第二个编排是对使用和消费这类数据集的应用进行编排。我们需要处理这些应用的调度,在调度时尽量使其感知缓存数据集,这样就可以在这调度应用的时候合理选择节点,从而高效地进行相关计算。

    总结来讲,Fluid 具有以下三大功能:

    1)提供云平台数据集抽象的原生支持

    数据密集型应用所需基础支撑能力功能化,实现数据高效访问并降低多维成本。

    2)基于容器调度管理的数据集编排

    通过数据集缓存引擎与 Kubernetes 容器调度和扩缩容能力的相互配合,实现数据集可迁移性。

    3)面向云上数据本地化的应用调度

    Kubernetes 调度器通过与缓存引擎交互获得节点的数据缓存信息,将使用该数据的应用以透明的方式调度到包含数据缓存的节点,最大化缓存本地性的优势。

    Fluid 架构功能

    1. Fluid 系统架构

    8.jpg

    Fluid 是构建在 K8s 上的系统,对原生 K8s 具备良好的兼容性,无需修改任意代码。如上图所示,用户需要定义两个 CRD,分别是 Dataset 和 Runtime。Dataset 是数据集的通用定义,这是我们提供的 K8s 资源对象,需要写 YAML 文件来定义数据集从哪儿来,以及想要放到哪儿去;Runtime 是存储这些数据集的缓存引擎,目前使用的是开源的分布式缓存系统 Alluxio。这里要注意的是 Dataset 和 Runtime 定义的时候,它通常是要具有相同 Namespace,从而实现很好的绑定。

    Fluid Operator 是 Fluid 项目的核心,它分为两部分。第一部分是 Fluid-controller-manager,包含很多 Controller;另一部分为 Fluid-Scheduler。这两个组件完成了编排调度的操作。Fluid-controller-manager 做的工作就是对数据进行编排,包括三个 Controller。这三个 Controller 从逻辑上它们是独立的,可以去做单进程。但为了降低复杂性,很多 Controller 的功能编译时被合并成一个和多个可执行文件,所以在真正运行起来时,也是一个进程。

    • 数据集的 Dataset Controller 负责整个数据集的生命周期管理,包括数据集的创建,以及要和哪个 Runtime 进行绑定。
    • Runtime Controller 负责数据集如何在云原生平台上被调度与缓存,应该放在哪些节点上,要有多少副本。
    • Volume Controller:由于 Fluid 是基于 K8s 运行,因此需要和 K8s 进行对接,这里我们使用的是 PVC(数据持久卷)协议,这是 K8s 本地存储栈的协议,使用非常广泛,Fluid 与 PVC 的对接非常流畅。

    最下面为 Cache Runtime Engine,是真正完成缓存数据具体工作的地方。
    图中右边部分的 Fluid-Scheduler 主要是基于定义好的 dataset、runtime controller 等具体信息,对 K8s 的调度器做一些扩展。这里面包含两个 Plugin:

    • Cache co-locality Plugin:Cache co-locality Plugin 做的事就是结合前面数据编排的信息,把应用调度到最合适的节点上,然后尽量能够让用户去读到缓存节点里面的信息。
    • Prefetch Plugin:当用户集群还没有缓存流入数据情况之下,且知道应用肯定是要读哪一类数据时,尤其在应用调度和编排运行之前,可以做 Prefetch 的调度,将这个数据从最底下的存储卷当中缓存到数据缓存里面,可以手动触发。

    再往下就是标准 K8s。通过 K8s 可以对接底层不同的存储,具体的对接方式可通过 K8s 的 PVC 完成。由于通过 Alluxio 进行了抽象,可以直接支持 Alluxio 本身支持的存储类型。

    2. Fluid 的功能概念

    Fluid 不是全存储加速和管理,而是以应用为中心数据集加速和管理。

    三个重要概念

    • Dataset:数据集是逻辑上相关的一组数据的集合,不同数据集的特性和优化都是不一样的,所以对于数据集是要分开管理的,一致的文件特性,会被同一运算引擎使用。
    • Runtime:真正实现数据集安全性,版本管理和数据加速等能力的执行引擎的接口,包括如何创建、生命周期如何管理等等,定义了一系列生命周期的方法。
    • AlluxioRuntime:来自 Alluxio 社区,是支撑 Dataset 数据管理和缓存的执行引擎高效实现。

    通过以上概念与架构,实现了以下功能:

    1)加速

    • Observation: know the cache capacity easily.
    • Portableand Scalable: adjust the cache capacity on demand.
    • Co-locality:  bring data close to compute, and bring compute close to data.

    通过 K8s 提供了这个很好的可观测性,我们能够知道我们的缓存容量和当前状态,进一步地我们就可以很灵活的去迁移和扩展缓存,然后按需增加缓存容量。并且在扩展和迁移过程当中会充分考虑 co-locality,即本地性。将数据和计算在编排和调度时放在一起,从而实现加速目的。

    2)数据卷接口,统一访问不同存储

    从对接上面,支持数据卷接口,从而统一访问不同的存储,且 K8s 的任何数据卷都可以包装成 Fluid-Dataset 来进行使用加速。

    3)隔离

    隔离机制使得对数据集的访问可以在不同存储加速间进行隔离,并且实现权限控制管理。

    3. 如何使用 Fluid

    9.jpg

    以上图为例,用户在使用场景中需要使用来自两个不同地方的数据,假设一个来自阿里云,另外一个是本地存储 Ceph。在 Fluid 里面我们可以很容易地描述这样的数据集,通过创建一个自定义 K8s 资源对象 Dataset,对应的 mountPoint 可以加载两个,分别是阿里云和 Ceph。

    创建好就可以运行,这个过程中 Fluid 会创建一个 Dataset,并自动将它变成一个 PVC。当用户需要用这个数据时创建一个 Pod,以 PVC 挂载的方式,将 Dataset 关联到运行中的 Pod 中对数据进行访问。甚至 Pod 根本都不知道 PVC 后台运行的是 Fluid,而不是其他的存储,例如 NFS。整个过程和背后的原理对用户都是透明的,这使得对遗留程序的对接非常友好。

    4. 如何检查和观测 dataset 状态

    10.jpg

    当真正运行起来时有很多可观测的东西,我们在 Dataset CRD 里定义了很多 metrics。如上图所以,缓存总容量为 200GB,实际需要的容量为 84.29GB,无需扩容,后续可根据实际需求灵活扩容。通过这个工具,用户可以有效查询存储容量与使用量,从而实现可观测性。

    5. 根据数据集本地性调度作业

    11.jpg

    对于使用数据集应用的编排也很容易,只需要使用 PVC 模式把 Fluid 数据集挂载到应用当中,然后 K8s 调度器就会和 Fluid 调度器进行交互。

    如上图例子所示,挂载之后进行交互,根据调度策略安排 Pod 在对应的节点上运行。K8s 调度器和 Fluid 调度器交互时会看见三个节点,其中有两个有 Alluxio 缓存节点。我们知道经典的 K8s 调度包括两个很重要的阶段,一个是过滤阶段,另一个是优选阶段。在过滤阶段就会将第三个节点直接过滤掉,而在优选阶段可以利用一些内置优选的策略来选择更合适的节点,例如缓存空间量大小,这里面有很多未来可以拓展优化实现的空间。

    Fluid 性能评估

    12.jpg

    如上图所示,我们发现卡数量越来越多的时候,使用 Fluid 会带来巨大的性能提升。这其中的本质原因是当 GPU 数量变得越来越多(或 GPU 算力越来越强)时,访问大规模数据已经成为整个训练任务的瓶颈。从上图是训练结果来看,使用 Fluid 训练的端到端的性能最后提升约1倍,减少成本并提升了用户体验。

    13.jpg

    原文链接

    本文为阿里云原创内容,未经允许不得转载。

    展开全文
  • Fluid 本质上是一个云原生环境下的数据密集型应用的高效支撑平台。本文将向大家介绍 Fluid 项目是如何将数据密集型应用更高效地运行于 K8s 环境中的。 作者 | 顾荣 南京大学PASALab(注:本文基于作者公开演讲...

    简介: 为了解决大数据、AI 等数据密集型应用在云原生计算存储分离场景下,存在的数据访问延时高、联合分析难、多维管理杂等痛点问题,南京大学 PASALab、阿里巴巴、Alluxio 在 2020 年 9 月份联合发起了开源项目 Fluid。Fluid 本质上是一个云原生环境下的数据密集型应用的高效支撑平台。本文将向大家介绍 Fluid 项目是如何将数据密集型应用更高效地运行于 K8s 环境中的。

    头图.png

    作者 | 顾荣  南京大学 PASALab
    (注:本文基于作者公开演讲报告内容整理完成)
    来源 | 阿里巴巴云原生公众号

    得益于计算成本低、易于扩展、部署便捷、运维高效等多方面的优势,云计算平台吸引了越来越多的数据密集型应用在上面运行。如今,以 Kubernetes 为代表的云原生架构,因其灵活的资源可负载性以及高效的应用编排调度,在很多AI/大数据等数据密集型场景中应用广泛。然而,云原生环境和数据密集应用计算框架在早先设计理念和机制上存在天然分歧。因此,如何帮助数据密集型应用在云原生场景下高效、安全、便捷地访问数据,是一个既有理论意义又具应用价值的重要问题。

    为了解决大数据、AI 等数据密集型应用在云原生计算存储分离场景下,存在的数据访问延时高、联合分析难、多维管理杂等痛点问题,南京大学 PASALab、阿里巴巴、Alluxio 在 2020 年 9 月份联合发起了开源项目 Fluid。Fluid 本质上是一个云原生环境下的数据密集型应用的高效支撑平台。本文将向大家介绍 Fluid 项目是如何将数据密集型应用更高效地运行于 K8s 环境中的。

    项目背景简介

    1. 技术发展背景

    过去十年云计算、大数据、人工智能等技术发展突飞猛进。

    • 云计算平台领域:以 Docker、Kubernetes 为代表的容器及其编排的云原生技术,在应用服务部署自动化运维的浪潮当中得到了长足的发展。
    • 大数据处理领域:以 Hadoop、Spark、Alluxio 为代表的大数据并行计算与分布式存储技术,在众多行业领域大数据处理与存储的应用落地中几乎形成了主流生态。
    • 人工智能框架领域:PyTorch、Tensorflow、Caffe 等知名 AI 训练框架,在广大 AI 应用开发者反复使用和参与当中,发展日益成熟。

    其中,大数据应用和 AI 应用通常需要围绕大规模数据展开计算分析,是典型的数据密集型应用,而云计算平台得益于其计算成本和易于规模扩展的优势,以及容器化在高效部署和敏捷迭代方面的长处,吸引了越来越多的数据密集型应用在上面部署运行。

    大数据应用、AI、云计算三者的融合正在成为下一个重要的发展趋势。Gartner 预测,到 2023 年,70% 以上的 AI workloads 都将以应用容器化的方式部署运行,然后通过 Serverless 编程模型在云原生环境下进行构建。Spark 3.0.1 版本也开始支持 Kubernetes scheduler,拥抱云原生环境。

    • 详情见 Gartner 报告:

    https://www.gartner.com/en/conferences/emea/data-analytics-switzerland/featured-topics/topic-ai-machine-learning

    • Spark3.0.1 runs on K8s:

    https://spark.apache.org/docs/latest/running-on-kubernetes.html

    2. 面临的问题

    从用户的实际体验来看,现有云原生编排框架对数据密集型应用支持不够友好,主要体现在运行效率低下和数据管理复杂两方面。

    1.jpg

    运行效率低下:如上图所示,训练一个 RestNet50 神经网络,如果基于本地内存运行,大概每秒钟能训练近 1 万张图片;然而,在云原生环境下运行,基于 Cloud Storage 存储架构每秒训练的图片只能达到约 3000 张/秒,性能下降比较明显。

    数据管理复杂数据版本的多变、数据接口的多样、数据类型的抽象以及数据存储的异构,都给云原生环境下面向数据密集型应用支撑带来了挑战。

    3. 问题的原因分析

    云原生环境和数据密集处理框架在设计理念和机制上存在天然分歧,这两部分技术的早先产生和发展过程是相互独立的。我们可以看到,为了兼顾资源扩展的灵活性和使用成本,计算和存储分离的基本架构在云原生环境中大行其道;反观之,以大数据!

    2.jpg

    和 AI 训练为代表的数据密集型应用框架,为了减少数据传输,设计理念更多需要考虑数据本地化架构,两者在设计上存在分歧。

    另外,我们发现在云原生环境中,应用通常是以无状态(stateless)微服务化的方式进行部署,通过 FaaS(Function as a Service)方式串联。而在数据密集型框架应用中,是以数据抽象为中心开展,并进行任务分配执行,比如在 Spark 里都是围绕 RDD 构建整个大数据处理应用,中间加上算子。然而,无状态微服务并不是以数据为中心,这也存在设计上的分歧。

    3.jpg

    以上问题导致以 Kubernetes 为代表的云原生编排框架对于数据密集型应用,尤其是 AI 和大数据应用的支持还不够友好,具体体现在前面所述的运行效率低下、数据操作管理复杂等方面。

    我们纵观 Fluid 出现之前的云原生基金会(CNCF)全景图,涵盖了从应用交付 - 运维管理 - 底层存储的方方面面,但是缺少数据高效支撑组件这块重要拼图(注:Fluid近期刚进入CNCF 全景图,侧面反映本文理念得到了认可)。然而,这块拼图的缺失,就会造成大数据密集型应用在云原生环境下运行时,面临数据访问低效、数据隔离性弱、多数据源联合访问复杂方面的技术挑战。

    4. 云原生环境下的数据支撑挑战

    具体地,云原生环境下数据支撑的挑战主要分为三个方面

    • 第一:云平台计算存储分离架构导致数据访问延时高。为了监控资源灵活性满足本地无依赖的要求,云原生应用大多采用计算存储分离架构。但是从访问效率的角度来看,要求用云网络传输带宽,当数据密集型应用在云上运行时,会造成数据访问瓶颈、性能下降。
    • 第二:混合云场景下跨存储系统的联合分析困难。大多公司/组织通常基于不同存储管理数据支撑多样化应用,具备其各自的特点。Ceph、GlusterFS、HDFS 都会被广泛使用,数据也通常会散落在这些异构存储当中。然而,当需要联合数据进行综合性分析时,会增加数据移动成本,必然导致在云原生环境下需要面对网络费用、等待延时、人工操作等比较复杂的问题。
    • 第三:云环境中数据安全治理与多维度管理复杂。数据是很多公司的生命线,数据泄露、误操作、生命周期管理不当都会造成巨大损失。如何在云原生环境中保障数据的隔离,保护好用户的数据生命周期,都存在较大挑战。

    5. Kubernetes 生态中缺失的一块抽象

    综上所述,我们可以总结出一种现象:Kubernetes 生态中目前缺少数据密集型应用高效支撑的这块拼图。现有 Kubernetes 环境能对很多资源进行很好的抽象,包括将资源对象计算抽象成 Pod、将存储抽象成了 PV/PVC、将网络抽象成了 Service。云原生领域还有一些存储抽象主要面向数据持久化进行工作,提供对象和文件的持久化存储管理。但这些软件的功能缺乏以应用为中心的数据抽象及相关生命周期管理。

    6. 商店购物模式演变的联想

    为了更好地理解这些问题,我们可以做一些联想性的思考。如下图所示,引入商品购物模式,我们将商品、超市、客户类比为数据、存储、应用

    4.jpg

    • 商品数据都会被消费,商品会被消费者购买掉,数据会被应用读走,两者有一定类似性。
    • 超市存储类似,都起到贮藏与供应的功能。商品平时会贮藏在超市的货架上,当购买时扮演到供应的角色;对于存储而言,我们平时贮藏的数据都会被持久化到存储设备里,当应用需要时提供给用户。
    • 客户应用类似,客户会到商店消费购买商品。类似的,应用会到存储读取数据。

    商品、超市(商铺) 、客户模式,在过去几千年里发展得非常成熟,非常稳定。直到 2000 年之后发生了颠覆性的变化,这就是电商的产生。电商发明了线上购物模式,其特点体现在不再以店铺为中心而是以客户为中心,商品贮藏在仓库,客户可以在线上虚拟商铺挑选商品,最后由现代化物流将商品交付到客户,交易过程高效便捷、交易量更大。商品直接放在仓库里,仓库可以进行规范化、独立化管理,之后客户到电商平台上购买货物,会非常便捷、方便。客户不需要到店铺,在地铁上、车上、办公室、家里都可以用手机、电脑进行购物,而且不会存在商品寻找低效的情况,因为客户是在互联网上购物,都可以通过检索方式查找海量商品;线上购物的另一个优势是交易频次变得更高,交易量变得更大;客户也不需要必须去店里提货,快递可以直接送货上门,非常方便。

    5.jpg

    电商模式的成功有很多因素,其中有两大因素非常关键,一是如支付宝这样的第三方数字化支付工具的出现,二是如菜鸟这样专业化的物流系统产生,构建起四通八达的物流网络,使快速的商品寄送模式得以实现。反观回到现在计算机系统中,在现代云架构下,数据贮存在云存储系统中,数据密集型应用也以pod等各种各样资源描述符的方式在云原生环境下运行,但中间却缺乏一个高效的数据交付、数据递送的方式。也就是说,在云原生架构下面,数据贮藏在云存储系统当中,应用还是根据需要去访问数据,但由于类似的数据“物流系统”的缺失,导致数据密集型应用消费访问数据在云平台上比较低效

    6.jpg

    Fluid 核心理念

    基于以上的分析,以及从观察中得到的联想,下面来介绍 Fluid 的核心理念。

    1. Fluid 扮演云原生的“数据物流系统”角色

    7.jpg

    我们可以将 Fluid 所扮演角色理解为云原生环境下“数据物流系统”。回顾一下,在早先的大数据平台中,数据的访问尽量都是通过本地化进行。当用户写一个 MapReduce Job,Job 里包含很多 Task, 其中关注比较多的就是 MapTask 处理数据时是尽量将 Task 调度到用户要处理的数据所在的节点上运行。这种情况下,当用户访问数据时,尽管该数据是在 HDFS 这个分布式系统中,但本质上相当于从分布式系统中的本地节点上获取,我们称之为 Data Fetch。

    随着大数据生态系统的迅速发展,其上的应用框架变得越来越多,底层存储系统也变得越来越丰富,各种上层应用要访问不同种类、多样化系统的痛点越来越明显,于是出现了 Alluxio 这样一个优秀的开源项目,来统一管理底层不同存储系统,为上层提供统一化的标准接口,对上层应用屏蔽不同存储的差异。而且 Alluxio 提供内存缓存,加速数据访问。这个过程就解耦了本地化的情况,存储就可以实现分离。这种分离架构在部署好之后通常还是静态的,实现从 Data Fetch 变成 Data Access 的过程。

    Fluid 是在 Alluxio 基础之上,在云原生环境的调度层面上进行进一步的研究和拓展,希望获取云原生环境下数据节点以及应用的动态变化信息,让这一类静态的缓存等中间件动态、灵活地调动起来,从而让应用灵活性变得更强,实现数据智能化递送到应用的效果,即动态弹性(Data Delivery) 。

    在进行项目设计时,我们希望 Fluid 从视角、思路、理念三个层次带来一些革新:

    • 新视角:从云原生资源调度结合与数据密集型处理两个方面,重新综合审视云原生场景的数据抽象与支撑访问。
    • 新思路:针对容器编排缺乏数据感知,数据编排缺乏对云上架构变化的感知,提出了协同编排、多维管理、智能感知的一系列理念和创新方法;从而形成一套云原生环境下数据密集型应用的高效支撑平台。
    • 新理念:通过 Fluid 这个项目,希望让数据可以像流体一样在云平台中、在资源编排层和数据处理层之间能够灵活高效地被访问、转换和管理。

    2. 核心理念

    简单来说,Fluid 的核心理念,可以分为“一个抽象”和“两个编排”。

    首先在云原生环境里,抽象出了数据集的概念,它能够提供一个对底层存储的包装,对上层也能提供各种各样的支撑和访问能力,从而通过 API 的方式来简单地在 K8s 下实现对数据的操作。 

    在这个基础之上,Fluid 提供了两个编排的能力:

    首先是对于数据集进行编排,具体是指基于容器调度管理的数据进行编排。传统的方式只对数据本身进行管理,而 Fluid 的数据集编排则转为对承载数据的引擎进行编排和管理。通过对数据引擎进行合理的扩容、缩容和调度操作,和数据引擎的交互,从而实现对数据的迁移、缓存以及数据在 K8s 平台下灵活调度的管理和变化。

    第二个编排是对使用和消费这类数据集的应用进行编排。我们需要处理这些应用的调度,在调度时尽量使其感知缓存数据集,这样就可以在这调度应用的时候合理选择节点,从而高效地进行相关计算。

    总结来讲,Fluid 具有以下三大功能:

    1)提供云平台数据集抽象的原生支持

    数据密集型应用所需基础支撑能力功能化,实现数据高效访问并降低多维成本。

    2)基于容器调度管理的数据集编排

    通过数据集缓存引擎与 Kubernetes 容器调度和扩缩容能力的相互配合,实现数据集可迁移性。

    3)面向云上数据本地化的应用调度

    Kubernetes 调度器通过与缓存引擎交互获得节点的数据缓存信息,将使用该数据的应用以透明的方式调度到包含数据缓存的节点,最大化缓存本地性的优势。

    Fluid 架构功能

    1. Fluid 系统架构

    8.jpg

    Fluid 是构建在 K8s 上的系统,对原生 K8s 具备良好的兼容性,无需修改任意代码。如上图所示,用户需要定义两个 CRD,分别是 Dataset 和 Runtime。Dataset 是数据集的通用定义,这是我们提供的 K8s 资源对象,需要写 YAML 文件来定义数据集从哪儿来,以及想要放到哪儿去;Runtime 是存储这些数据集的缓存引擎,目前使用的是开源的分布式缓存系统 Alluxio。这里要注意的是 Dataset 和 Runtime 定义的时候,它通常是要具有相同 Namespace,从而实现很好的绑定。

    Fluid Operator 是 Fluid 项目的核心,它分为两部分。第一部分是 Fluid-controller-manager,包含很多 Controller;另一部分为 Fluid-Scheduler。这两个组件完成了编排调度的操作。Fluid-controller-manager 做的工作就是对数据进行编排,包括三个 Controller。这三个 Controller 从逻辑上它们是独立的,可以去做单进程。但为了降低复杂性,很多 Controller 的功能编译时被合并成一个和多个可执行文件,所以在真正运行起来时,也是一个进程。

    • 数据集的 Dataset Controller 负责整个数据集的生命周期管理,包括数据集的创建,以及要和哪个 Runtime 进行绑定。
    • Runtime Controller 负责数据集如何在云原生平台上被调度与缓存,应该放在哪些节点上,要有多少副本。
    • Volume Controller:由于 Fluid 是基于 K8s 运行,因此需要和 K8s 进行对接,这里我们使用的是 PVC(数据持久卷)协议,这是 K8s 本地存储栈的协议,使用非常广泛,Fluid 与 PVC 的对接非常流畅。

    最下面为 Cache Runtime Engine,是真正完成缓存数据具体工作的地方。
    图中右边部分的 Fluid-Scheduler 主要是基于定义好的 dataset、runtime controller 等具体信息,对 K8s 的调度器做一些扩展。这里面包含两个 Plugin:

    • Cache co-locality Plugin:Cache co-locality Plugin 做的事就是结合前面数据编排的信息,把应用调度到最合适的节点上,然后尽量能够让用户去读到缓存节点里面的信息。
    • Prefetch Plugin:当用户集群还没有缓存流入数据情况之下,且知道应用肯定是要读哪一类数据时,尤其在应用调度和编排运行之前,可以做 Prefetch 的调度,将这个数据从最底下的存储卷当中缓存到数据缓存里面,可以手动触发。

    再往下就是标准 K8s。通过 K8s 可以对接底层不同的存储,具体的对接方式可通过 K8s 的 PVC 完成。由于通过 Alluxio 进行了抽象,可以直接支持 Alluxio 本身支持的存储类型。

    2. Fluid 的功能概念

    Fluid 不是全存储加速和管理,而是以应用为中心数据集加速和管理。

    三个重要概念

    • Dataset:数据集是逻辑上相关的一组数据的集合,不同数据集的特性和优化都是不一样的,所以对于数据集是要分开管理的,一致的文件特性,会被同一运算引擎使用。
    • Runtime:真正实现数据集安全性,版本管理和数据加速等能力的执行引擎的接口,包括如何创建、生命周期如何管理等等,定义了一系列生命周期的方法。
    • AlluxioRuntime:来自 Alluxio 社区,是支撑 Dataset 数据管理和缓存的执行引擎高效实现。

    通过以上概念与架构,实现了以下功能:

    1)加速

    • Observation: know the cache capacity easily.
    • Portableand Scalable: adjust the cache capacity on demand.
    • Co-locality:  bring data close to compute, and bring compute close to data.

    通过 K8s 提供了这个很好的可观测性,我们能够知道我们的缓存容量和当前状态,进一步地我们就可以很灵活的去迁移和扩展缓存,然后按需增加缓存容量。并且在扩展和迁移过程当中会充分考虑 co-locality,即本地性。将数据和计算在编排和调度时放在一起,从而实现加速目的。

    2)数据卷接口,统一访问不同存储

    从对接上面,支持数据卷接口,从而统一访问不同的存储,且 K8s 的任何数据卷都可以包装成 Fluid-Dataset 来进行使用加速。

    3)隔离

    隔离机制使得对数据集的访问可以在不同存储加速间进行隔离,并且实现权限控制管理。

    3. 如何使用 Fluid

    9.jpg

    以上图为例,用户在使用场景中需要使用来自两个不同地方的数据,假设一个来自阿里云,另外一个是本地存储 Ceph。在 Fluid 里面我们可以很容易地描述这样的数据集,通过创建一个自定义 K8s 资源对象 Dataset,对应的 mountPoint 可以加载两个,分别是阿里云和 Ceph。

    创建好就可以运行,这个过程中 Fluid 会创建一个 Dataset,并自动将它变成一个 PVC。当用户需要用这个数据时创建一个 Pod,以 PVC 挂载的方式,将 Dataset 关联到运行中的 Pod 中对数据进行访问。甚至 Pod 根本都不知道 PVC 后台运行的是 Fluid,而不是其他的存储,例如 NFS。整个过程和背后的原理对用户都是透明的,这使得对遗留程序的对接非常友好。

    4. 如何检查和观测 dataset 状态

    10.jpg

    当真正运行起来时有很多可观测的东西,我们在 Dataset CRD 里定义了很多 metrics。如上图所以,缓存总容量为 200GB,实际需要的容量为 84.29GB,无需扩容,后续可根据实际需求灵活扩容。通过这个工具,用户可以有效查询存储容量与使用量,从而实现可观测性。

    5. 根据数据集本地性调度作业

    11.jpg

    对于使用数据集应用的编排也很容易,只需要使用 PVC 模式把 Fluid 数据集挂载到应用当中,然后 K8s 调度器就会和 Fluid 调度器进行交互。

    如上图例子所示,挂载之后进行交互,根据调度策略安排 Pod 在对应的节点上运行。K8s 调度器和 Fluid 调度器交互时会看见三个节点,其中有两个有 Alluxio 缓存节点。我们知道经典的 K8s 调度包括两个很重要的阶段,一个是过滤阶段,另一个是优选阶段。在过滤阶段就会将第三个节点直接过滤掉,而在优选阶段可以利用一些内置优选的策略来选择更合适的节点,例如缓存空间量大小,这里面有很多未来可以拓展优化实现的空间。

    Fluid 性能评估

    12.jpg

    如上图所示,我们发现卡数量越来越多的时候,使用 Fluid 会带来巨大的性能提升。这其中的本质原因是当 GPU 数量变得越来越多(或 GPU 算力越来越强)时,访问大规模数据已经成为整个训练任务的瓶颈。从上图是训练结果来看,使用 Fluid 训练的端到端的性能最后提升约1倍,减少成本并提升了用户体验。

    13.jpg

    我们在项目 github 主页上提供了许多 Demo 演示,具体详情可以点击观看视频:https://developer.aliyun.com/live/246068,或参见:https://github.com/fluid-cloudnative/fluid#qucik-demo

    加入 Fluid 社区

    想要了解更多关于 Fluid 的信息,请访问 Fluid 项目 Github 地址或查看 Fluid 项目主页。也欢迎大家加入 Fluid 社区交流钉钉群,与更多用户和开发者深入交流项目技术及其实际使用场景。

    展开全文
  • Harbor安装 Docker 安装 安装一些必要的系统工具: sudo yum install -y yum-utils device-mapper-persistent-data lvm2 添加软件源信息: sudo yum-config-manager --add-repo ...安装 Docke

    Harbor安装

    Docker 安装

    安装一些必要的系统工具:
    
    sudo yum install -y yum-utils device-mapper-persistent-data lvm2
    添加软件源信息:
    
    sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    更新 yum 缓存:
    
    sudo yum makecache fast
    安装 Docker-ce:(企业版  社区版)
    
    sudo yum -y install docker-ce
    启动 Docker 后台服务
    
    sudo systemctl start docker
    测试运行 hello-world
    
    docker run hello-world

    docker-compose

    a.下载二进制文件
    # curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
    如果需要安装其他版本的话,请修改上面命令中的版本号。
    
    b.赋予二进制文件可执行权限
    # chmod +x /usr/local/bin/docker-compose
    c.根据自己的情况决定是否安装命令补全功能
    # yum install bash-completion 
    # curl -L https://raw.githubusercontent.com/docker/compose/1.16.1/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose
    重新登陆后就生效了
    
    # docker-compose 
    build    config   down     exec     images   logs     port     pull     restart  run      start    top      up       
    bundle   create   events   help     kill     pause    ps       push     rm       scale    stop     unpause  version  
    d.测试是否安装成功
    # docker-compose --version
    docker-compose version 1.16.1, build 6d1ac21

    pip yum安装

    # yum install python-pip
    # pip install  docker-compose
    测试:
    
    # docker-compose --version
    卸载docker-compose
    对应上面两种安装方法:
    二进制:
    
    # rm  /usr/local/bin/docker-compose
    pip:
    
    # pip uninstall  docker-compose

    卸载

    如果是二进制包方式安装的,删除二进制文件即可:
    sudo rm /usr/local/bin/docker-compose
    如果通过Python pip工具安装的,则执行如下命令删除:
    sudo pip uninstall docker-compose

    Harbor安装

    harbor软件网址:https://github.com/vmware/harbor/releases

      此页面提供源码安装和二进制安装下载地址,不建议方式

      镜像网址:http://harbor.orientsoft.cn/

      此页面只提供离线下载安装包,建议此种方式。

    #下载离线安装软件
    wget http://harbor.orientsoft.cn/harbor-v1.3.0-rc4/harbor-offline-installer-v1.3.0-rc4.tgz
    #解压文件
    tar -zxf harbor-offline-installer-v1.3.0-rc4.tgz
    #解压后的文件夹是harbor

    解压完成后:修改配置文件harbor.conf,如果是测试环境基本不用什么更改配置,主要就是hostname,和port

    http:

       port:80

    端口默认是80,可以改掉。

    harbor_admin_password

    管理员 admin 登录密码 默认是Harbor12345

    [root@c7test_master harbor]# vim harbor.cfg 
    
    ## Configuration file of Harbor
    
    #The IP address or hostname to access admin UI and registry service.
    #DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
    #主机地址,不可以设置为127或者localhost
    
    hostname = 10.10.90.105
    
    #The protocol for accessing the UI and token/notification service, by default it is http.
    #It can be set to https if ssl is enabled on nginx.
    ui_url_protocol = http
    
    #The password for the root user of mysql db, change this before any production use.
    #mysql密码
    db_password = root123
    
    #Maximum number of job workers in job service  
    max_job_workers = 3 
    
    #Determine whether or not to generate certificate for the registry's token.
    #If the value is on, the prepare script creates new root cert and private key 
    #for generating token to access the registry. If the value is off the default key/cert will be used.
    #This flag also controls the creation of the notary signer's cert.
    customize_crt = on
    
    #The path of cert and key files for nginx, they are applied only the protocol is set to https
    ssl_cert = /data/cert/server.crt
    ssl_cert_key = /data/cert/server.key
    
    #The path of secretkey storage
    secretkey_path = /data
    
    #Admiral's url, comment this attribute, or set its value to NA when Harbor is standalone
    admiral_url = NA
    
    #The password of the Clair's postgres database, only effective when Harbor is deployed with Clair.
    #Please update it before deployment, subsequent update will cause Clair's API server and Harbor unable to access Clair's database.
    clair_db_password = password
    
    #Log files are rotated log_rotate_count times before being removed. If count is 0, old versions are removed rather than rotated.
    log_rotate_count = 50
    #Log files are rotated only if they grow bigger than log_rotate_size bytes. If size is followed by k, the size is assumed to be in kilobytes. 
    #If the M is used, the size is in megabytes, and if G is used, the size is in gigabytes. So size 100, size 100k, size 100M and size 100G 
    #are all valid.
    log_rotate_size = 200M
    
    #NOTES: The properties between BEGIN INITIAL PROPERTIES and END INITIAL PROPERTIES
    #only take effect in the first boot, the subsequent changes of these properties 
    #should be performed on web ui
    
    #************************BEGIN INITIAL PROPERTIES************************
    
    #Email account settings for sending out password resetting emails.
    
    #Email server uses the given username and password to authenticate on TLS connections to host and act as identity.
    #Identity left blank to act as username.
    email_identity = 
    
    email_server = smtp.mydomain.com
    email_server_port = 25
    email_username = sample_admin@mydomain.com
    email_password = abc
    email_from = admin <sample_admin@mydomain.com>
    email_ssl = false
    email_insecure = false
    
    ##The initial password of Harbor admin, only works for the first time when Harbor starts. 
    #It has no effect after the first launch of Harbor.
    #Change the admin password from UI after launching Harbor.
    #这里是web登录页面的密码,可以更改
    harbor_admin_password = Harbor12345
    
    ##By default the auth mode is db_auth, i.e. the credentials are stored in a local database.
    #Set it to ldap_auth if you want to verify a user's credentials against an LDAP server.
    auth_mode = db_auth
    
    #The url for an ldap endpoint.
    ldap_url = ldaps://ldap.mydomain.com
    
    #A user's DN who has the permission to search the LDAP/AD server. 
    #If your LDAP/AD server does not support anonymous search, you should configure this DN and ldap_search_pwd.
    #ldap_searchdn = uid=searchuser,ou=people,dc=mydomain,dc=com
    
    #the password of the ldap_searchdn
    #ldap_search_pwd = password
    
    #The base DN from which to look up a user in LDAP/AD
    ldap_basedn = ou=people,dc=mydomain,dc=com
    
    #Search filter for LDAP/AD, make sure the syntax of the filter is correct.
    #ldap_filter = (objectClass=person)
    
    # The attribute used in a search to match a user, it could be uid, cn, email, sAMAccountName or other attributes depending on your LDAP/AD  
    ldap_uid = uid 
    
    #the scope to search for users, 1-LDAP_SCOPE_BASE, 2-LDAP_SCOPE_ONELEVEL, 3-LDAP_SCOPE_SUBTREE
    ldap_scope = 3 
    
    #Timeout (in seconds)  when connecting to an LDAP Server. The default value (and most reasonable) is 5 seconds.
    ldap_timeout = 5
    
    #Turn on or off the self-registration feature
    self_registration = on
    
    #The expiration time (in minute) of token created by token service, default is 30 minutes
    token_expiration = 30
    
    #The flag to control what users have permission to create projects
    #The default value "everyone" allows everyone to creates a project. 
    #Set to "adminonly" so that only admin user can create project.
    project_creation_restriction = everyone
    
    #The follow configurations are for Harbor HA mode only
    
    #the address of the mysql database.
    db_host = mysql
    
    #The port of mysql database host
    db_port = 3306
    
    #The user name of mysql database
    db_user = root
    #************************END INITIAL PROPERTIES************************
    #The following attributes only need to be set when auth mode is uaa_auth
    uaa_endpoint = uaa.mydomain.org
    uaa_clientid= id
    uaa_clientsecret= secret
    uaa_ca_root= /path/to/uaa_ca.pem
    #############
    
    Harbor配置文件
    ## Configuration file of Harbor
        
        # hostname设置访问地址,可以使用ip、域名,不可以设置为127.0.0.1或localhost
        hostname = 10.0.86.193
        
        # 访问协议,默认是http,也可以设置https,如果设置https,则nginx ssl需要设置on
        ui_url_protocol = http
        
        # mysql数据库root用户默认密码root123,实际使用时修改下
        db_password = root123
        
        max_job_workers = 3 
        customize_crt = on
        ssl_cert = /data/cert/server.crt
        ssl_cert_key = /data/cert/server.key
        secretkey_path = /data
        admiral_url = NA
        
        # 邮件设置,发送重置密码邮件时使用
        email_identity = 
        email_server = smtp.mydomain.com
        email_server_port = 25
        email_username = sample_admin@mydomain.com
        email_password = abc
        email_from = admin <sample_admin@mydomain.com>
        email_ssl = false
        
        # 启动Harbor后,管理员UI登录的密码,默认是Harbor12345
        harbor_admin_password = Harbor12345
        
        # 认证方式,这里支持多种认证方式,如LADP、本次存储、数据库认证。默认是db_auth,mysql数据库认证
        auth_mode = db_auth
        
        # LDAP认证时配置项
        #ldap_url = ldaps://ldap.mydomain.com
        #ldap_searchdn = uid=searchuser,ou=people,dc=mydomain,dc=com
        #ldap_search_pwd = password
        #ldap_basedn = ou=people,dc=mydomain,dc=com
        #ldap_filter = (objectClass=person)
        #ldap_uid = uid 
        #ldap_scope = 3 
        #ldap_timeout = 5
        
        # 是否开启自注册
        self_registration = on
        
        # Token有效时间,默认30分钟
        token_expiration = 30
        
        # 用户创建项目权限控制,默认是everyone(所有人),也可以设置为adminonly(只能管理员)
        project_creation_restriction = everyone
        
        verify_remote_cert = on

      启动harbor,修改完配置文件就可以执行该目录下的install.sh文件即可,程序会自动启动相关镜像,因为harbor是用你镜像进行安装的。

    [root@cent7test_master harbor]# ./install.sh 

     

     

     

     

    展开全文
  • PHP原生环境配置 来 让你熟悉为什么

    千次阅读 2017-01-17 13:37:41
    入门环境配置 储备知识 1.PHP是一种典型的脚本语言、开发阶段必要环境配置 2.经典的Apache服务器加MySql数据库就能实现PHP程序运行 3.PHP: 在Web端之所以流行,是因为其兼容性,安全性,及运行效率迅速 ...
  • 被H5逐渐侵蚀的app原生环境

    千次阅读 2016-03-18 15:39:23
    在这个市场大环境下,浪里淘沙的不单单是商业模式、产品定义,技术格局也在以飓风的速度在迭代更新,本来已经日新月异的技术,配合着各式各样产品的出现有着更加惊人的变化。而app和H5的大战,也早在几年前就已经...
  • https://www.cnblogs.com/xjh713/p/9855238.html
  • 声明: 本博客欢迎转发,但请保留原作者信息! 新浪微博:郑振宇_HW 博客地址:... ...内容系本人及本人团队学习、研究和总结,如有雷同,实属荣幸!...支撑团队:华为OpenStack社区团队(西安) ...而在指定
  • 原生代码调用Lua中的方法和变量,控制Lua的业务逻辑 如,Lua中有如下定义 url = " https://vimfung.github.io/LuaScriptCore/ " ; function printUrl ( url ) print (url); end 在原生代码中可以如以下操作Lua变量...
  • Cocos2d-jsb在访问原生语言时,有机率会出现闪退情况 在原生语言回调给cocos的时候,用setTimeout函数延时执行逻辑可很大程度的缓解闪退情况
  • 安装配置原生开发环境(摘自:http://www.cocos.com/docs/creator/publish/setup-native-development.html)除了内置的 Web 版游戏发布功能外,Cocos Creator 使用基于 cocos2d-x 引擎的 JSB 技术实现跨平台发布原生...
  • 原生开发环境初探

    千次阅读 2019-12-12 19:38:33
    在上一篇“云原生的不同解释及正确含义”里,我们讲到了云原生的引申含义,就是开发环境也是云环境,这样就能保证开发环境和生产环境的一致性,使最终的部署顺利进行。本文就通过具体的例子来探讨云原生的开发环境。...
  • 原生ipv6环境下不可用

    2020-11-27 11:02:04
    好像新版支持原生ipv6环境了。但当我在“启动设置”里禁用teredo后,“ipv6状态”fail,”连接尚未建立“,一定要开启隧道后才能连接,是什么问题呢? xndroid版本1.2.5,xxnet...
  • 在进行Cocos creator 进行开发的时候,一般我们用模拟器就可进行原生调试,但是有些问题只是在原生平台才会出现,我们需要对原生进行调试。软件准备step1 安装Android studio[可选]软件准备下载安装Android studio...
  • 原生玩转Flutter环境

    2020-04-21 16:04:31
    项目开发会分博客文章,请点击链接到对应的文章中浏览,建议其实万变不离其中,说到底还是离不开原生,学习之前往补充原生知识,本片主要讲的是Mac、window环境搭建,再次感谢大家能耐心观看...
  • RN环境搭建和原生交互
  • 基于Windows系统搭建micropython原生开发环境 苏勇,suyong_yq@126.com,2021-01 文章目录基于Windows系统搭建micropython原生开发环境引言下载资料安装msys2在msys2中安装make工具在msys2中安装gcc编译器在msys2中...
  • 下面小编就为大家带来一篇老生常谈原生JS执行环境与作用域。小编觉得挺不错的,希望对大家有所帮助。一起跟随小编过来看看吧,祝大家游戏愉快哦
  • 在服务及其消费者无处不在的时代,企业系统和数据的安全风险正在爆炸式增长。来自云服务提供商的安全产品很有前景,...虽然有许多企业的防火墙和VPN设备可用于数据中心或云环境,但重要的是包括访问控制,身份验证和...
  • Cocos Creator2.1安装配置原生开发环境

    千次阅读 2019-08-02 14:48:55
    在使用 Cocos Creator 打包发布到原生平台之前,我们需要先配置好 cocos2d-x 相关的开发环境。 Android 平台相关依赖 要发布到 Android 平台,需要安装以下全部开发环境依赖。 如果您没有发布到 Android 平台的...
  • IDE 插件,无需熟悉 kubectl 命令即可完成云原生环境下的开发 管理人员: • 统一管理微服务应用包,降低应用的维护成本• 统一管理开发环境和集群,提高集群资源的利用率,同时具备隔离特性• 为新员工快速...
  • python3以上自带创建虚拟环境的功能(3.3虚拟环境不支持pip)切换到某个目录python -m venv virtuaenv_namecd virtuaenv_name激活虚拟环境Scripts\activate.bat默认已经安装pippip install requests pip insatll -r ...
  • 安装配置原生开发环境 (摘自:http://www.cocos.com/docs/creator/publish/setup-native-development.html) 除了内置的 Web 版游戏发布功能外,Cocos Creator 使用基于 cocos2d-x 引擎的 JSB 技术实现跨平台...
  • Python 3.4 之后支持原生的虚拟环境配置(3.3的虚拟环境不支持pip),把配置过程记录一下备忘。 1.创建虚拟环境 在控制台中,使用cd目录,切换到需要创建虚拟环境的目录。 使用如下命令,在当前目录创建虚拟环境...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,285
精华内容 3,714
关键字:

原生环境