首页 文章 精选 留言 我的

精选列表

搜索[DUOX技术],共10007篇文章
优秀的个人博客,低调大师

技术系列】浅谈GPU虚拟化技术(第一章)

第一章 GPU虚拟化发展史 GPU的虚拟化发展历程事实上与公有云市场和云计算应用场景的普及息息相关。如果在10年前谈起云计算,大部分人的反应是“不知所云“。但是随着云计算场景的普及,概念的深入人心,慢慢地大家都对云计算有一个较清晰的概念和实例化的理解。自然,随着应用场景从单一依赖CPU的计算单元的应用扩展到多种体系架构,异构计算场景的应用上来后,对GPU,FPGA,TPU等专业计算芯片也提出了虚拟化和上云的强烈要求。尤其是最近几年机器学习、深度学习等领域的快速发展,催生了异构计算场景搬迁上云的高潮。 那么这个异构计算应用场景的市场规模有多大呢?异构计算作为机器学习人工智能的计算载体,先来看看人工智能前景如何?(引用出处:https://bg.qianzhan.com/report/detail/459/180116-3c060b52

优秀的个人博客,低调大师

飞码LowCode前端技术之画布的设计 | 京东云技术团队

简介 本章节从精准定位、分层设计、异步组件、拖拽四个方面分析飞码画布设计。 一、精准定位设计 飞码画布是一个套件,可对外提供画布能力。精准定位有两种情况,一是目标组件无子组件,而是目标组件有子组件。 无子组件:目标组件分为支持与不支持放子组件两种情况。 有子组件:鼠标相对于子组件(目标组件)对角线位置。详见图1 图1 当目标组件不支持放子组件时,需要计算拖拽组件放在目标组件的左侧、上侧、右侧、还是下侧?其计算方法如图2 图2 通过鼠标位置,目标组件,组件对角线坐标位置可推导出图1右侧图拖拽组件与目标组件位置关系。 问题:飞码为何不提供尺度(x、y),这样可以精准知道组件大小? 实际使用过程中,搭建人员并不关心组件的具体x,y。一般关注一行几列与组件宽度。 二、分层设计 低代码画布设计有很多方案,飞码采用的是双层设计模式。该设计模式优势很多,与画布中组件是解耦关系。开发过iOS,安卓native的同学较容易理解。如图3 图3 画布中底层是组件渲染层,根据页面DSL渲染组件布局,在组件渲染层上还有一层canvas-mask视图。当点击某一个组件之后,根据组件会在组件最边框添加颜色,组件右侧上方(根据页面布局自动切换到下方)添加工具条(更多、上移、下移、复制、删除),hover区域。支持组件宽度拖拽调整,组件的最右侧有一个呼吸道效果的线条,鼠标可以对该组件宽度进行拖拽调整。这样极大方便了样式调整操作。 问题:既然支持了组件左右大小调整,为何不支持组件的上下大小调整? 飞码对div,form等容器组件在编辑态中上下大小会根据子组件高度进行自动调整。飞码并不知道组件的宽度大小。 三、异步组件 飞码提供常用的组件能力,飞码搭建业务定制化的组件困难。飞码提供动态加载组件能力,动态组件加载分为编辑态与运行态。编辑态在组件拖到页面的时候会根据组件数据中type判断当前组件类型。若type=2,飞码引擎会创建script下载相关url对应的组件,之后做缓存。运行态思路一致。 四、拖拽设计 拖拽组件的时,每一个组件需要混入一些特定处理,例如form表单的子组件是不是el-form-item等情况。见图4 图4 组件拖拽开始会记录currentTarget获取到组件id,并对dataTransfer进行设置image。这样就可以看到拖拽组件的样式。混入方法使用hoc,增强组件的一个方法。详见图5所示。 图5 四:小结 本章节分析了飞码画布在精准定位、分层设计、异步组件、拖拽四个方面的设计。飞码的目标是:便捷、稳健、0测试,使前端web单页面快速投产。感谢产品同学和服务端同学的大力支持。 作者:京东科技 王光辉 来源:京东云开发者社区 转载请注明来源

优秀的个人博客,低调大师

前端技术探秘-Nodejs的CommonJS规范实现原理 | 京东物流技术团队

了解Node.js Node.js是一个基于ChromeV8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O模型,让JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言。Node中增添了很多内置的模块,提供各种各样的功能,同时也提供许多第三方模块。 模块的问题 为什么要有模块 复杂的前端项目需要做分层处理,按照功能、业务、组件拆分成模块, 模块化的项目至少有以下优点: 便于单元测试 便于同事间协作 抽离公共方法, 开发快捷 按需加载, 性能优秀 高内聚低耦合 防止变量冲突 方便代码项目维护 几种模块化规范 CMD(SeaJS 实现了 CMD) AMD(RequireJS 实现了 AMD) UMD(同时支持 AMD 和 CMD) IIFE (自执行函数) CommonJS (Node 采用了 CommonJS) ES Module 规范 (JS 官方的模块化方案) Node中的模块 Node中采用了 CommonJS 规范 实现原理: Node中会读取文件,拿到内容实现模块化, Require方法 同步引用 tips:Node中任何js文件都是一个模块,每一个文件都是模块 Node中模块类型 内置模块,属于核心模块,无需安装,在项目中不需要相对路径引用, Node自身提供。 文件模块,程序员自己书写的js文件模块。 第三方模块, 需要安装, 安装之后不用加路径。 Node中内置模块 fs filesystem 操作文件都需要用到这个模块 const path = require('path'); // 处理路径 const fs = require('fs'); // file system // // 同步读取 let content = fs.readFileSync(path.resolve(__dirname, 'test.js'), 'utf8'); console.log(content); let exists = fs.existsSync(path.resolve(__dirname, 'test1.js')); console.log(exists); path 路径处理 const path = require('path'); // 处理路径 // join / resolve 用的时候可以混用 console.log(path.join('a', 'b', 'c', '..', '/')) // 根据已经有的路径来解析绝对路径, 可以用他来解析配置文件 console.log(path.resolve('a', 'b', '/')); // resolve 不支持/ 会解析成根路径 console.log(path.join(__dirname, 'a')) console.log(path.extname('1.js')) console.log(path.dirname(__dirname)); // 解析父目录 vm 运行代码 字符串如何能变成 JS 执行呢? 1.eval eval中的代码执行时的作用域为当前作用域。它可以访问到函数中的局部变量。 let test = 'global scope' global.test1 = '123' function b(){ test = 'fn scope' eval('console.log(test)'); //local scope new Function('console.log(test1)')() // 123 new Function('console.log(test)')() //global scope } b() 2.new Function new Function()创建函数时,不是引用当前的词法环境,而是引用全局环境,Function中的表达式使用的变量要么是传入的参数要么是全局的值 Function可以获取全局变量,所以它还是可能会有变量污染的情况出现 function getFn() { let value = "test" let fn = new Function('console.log(value)') return fn } getFn()() global.a = 100 // 挂在到全局对象global上 new Function("console.log(a)")() // 100 3.vm 前面两种方式,我们一直强调一个概念,那就是变量的污染 VM的特点就是不受环境的影响,也可以说他就是一个沙箱环境 在Node中全局变量是在多个模块下共享的,所以尽量不要在global中定义属性 所以,vm.runInThisContext可以访问到global上的全局变量,但是访问不到自定义的变量。而vm.runInNewContext访问不到global,也访问不到自定义变量,他存在于一个全新的执行上下文 const vm = require('vm') global.a = 1 // vm.runInThisContext("console.log(a)") vm.runInThisContext("a = 100") // 沙箱,独立的环境 console.log(a) // 1 vm.runInNewContext('console.log(a)') console.log(a) // a is not defined Node模块化的实现 node中是自带模块化机制的,每个文件就是一个单独的模块,并且它遵循的是CommonJS规范,也就是使用require的方式导入模块,通过module.export的方式导出模块。 node模块的运行机制也很简单,其实就是在每一个模块外层包裹了一层函数,有了函数的包裹就可以实现代码间的作用域隔离。 我们先在一个js文件中直接打印arguments,得到的结果如下图所示,我们先记住这些参数。 console.log(arguments) // exports, require, module, __filename, __dirname Node中通过modules.export 导出,require 引入。其中require依赖node中的fs模块来加载模块文件,通过fs.readFile读取到的是一个字符串。 在javascrpt中可以通过eval或者new Function的方式来将一个字符串转换成js代码来运行。但是前面提到过,他们都有一个致命的问题,就是变量的污染。 实现require模块加载器 首先导入依赖的模块path,fs,vm, 并且创建一个Require函数,这个函数接收一个modulePath参数,表示要导入的文件路径 const path = require('path'); const fs = require('fs'); const vm = require('vm'); // 定义导入类,参数为模块路径 function Require(modulePath) { ... } 在Require中获取到模块的绝对路径,使用fs加载模块,这里读取模块内容使用new Module来抽象,使用tryModuleLoad来加载模块内容,Module和tryModuleLoad稍后实现,Require的返回值应该是模块的内容,也就是module.exports。 // 定义导入类,参数为模块路径 function Require(modulePath) { // 获取当前要加载的绝对路径 let absPathname = path.resolve(__dirname, modulePath); // 创建模块,新建Module实例 const module = new Module(absPathname); // 加载当前模块 tryModuleLoad(module); // 返回exports对象 return module.exports; } Module的实现就是给模块创建一个exports对象,tryModuleLoad执行的时候将内容加入到exports中,id就是模块的绝对路径。 // 定义模块, 添加文件id标识和exports属性 function Module(id) { this.id = id; // 读取到的文件内容会放在exports中 this.exports = {}; } node模块是运行在一个函数中,这里给Module挂载静态属性wrapper,里面定义一下这个函数的字符串,wrapper是一个数组,数组的第一个元素就是函数的参数部分,其中有exports,module,Require,__dirname,__filename, 都是模块中常用的全局变量. 第二个参数就是函数的结束部分。两部分都是字符串,使用的时候将他们包裹在模块的字符串外部就可以了。 // 定义包裹模块内容的函数 Module.wrapper = [ "(function(exports, module, Require, __dirname, __filename) {", "})" ] _extensions用于针对不同的模块扩展名使用不同的加载方式,比如JSON和javascript加载方式肯定是不同的。JSON使用JSON.parse来运行。 javascript使用vm.runInThisContext来运行,可以看到fs.readFileSync传入的是module.id也就是Module定义时候id存储的是模块的绝对路径,读取到的content是一个字符串,使用Module.wrapper来包裹一下就相当于在这个模块外部又包裹了一个函数,也就实现了私有作用域。 使用call来执行fn函数,第一个参数改变运行的this传入module.exports,后面的参数就是函数外面包裹参数exports, module, Require, __dirname, __filename。/ // 定义扩展名,不同的扩展名,加载方式不同,实现js和json Module._extensions = { '.js'(module) { const content = fs.readFileSync(module.id, 'utf8'); const fnStr = Module.wrapper[0] + content + Module.wrapper[1]; const fn = vm.runInThisContext(fnStr); fn.call(module.exports, module.exports, module, Require,__filename,__dirname); }, '.json'(module) { const json = fs.readFileSync(module.id, 'utf8'); module.exports = JSON.parse(json); // 把文件的结果放在exports属性上 } } tryModuleLoad函数接收的是模块对象,通过path.extname来获取模块的后缀名,然后使用Module._extensions来加载模块。 // 定义模块加载方法 function tryModuleLoad(module) { // 获取扩展名 const extension = path.extname(module.id); // 通过后缀加载当前模块 Module._extensions[extension](module); // 策略模式??? } 到此Require加载机制基本就写完了。Require加载模块的时候传入模块名称,在Require方法中使用path.resolve(__dirname, modulePath)获取到文件的绝对路径。然后通过new Module实例化的方式创建module对象,将模块的绝对路径存储在module的id属性中,在module中创建exports属性为一个json对象。 使用tryModuleLoad方法去加载模块,tryModuleLoad中使用path.extname获取到文件的扩展名,然后根据扩展名来执行对应的模块加载机制。 最终将加载到的模块挂载module.exports中。tryModuleLoad执行完毕之后module.exports已经存在了,直接返回就可以了。 接下来,我们给模块添加缓存。就是文件加载的时候将文件放入缓存中,再去加载模块时先看缓存中是否存在,如果存在直接使用,如果不存在再去重新加载,加载之后再放入缓存。 // 定义导入类,参数为模块路径 function Require(modulePath) { // 获取当前要加载的绝对路径 let absPathname = path.resolve(__dirname, modulePath); // 从缓存中读取,如果存在,直接返回结果 if (Module._cache[absPathname]) { return Module._cache[absPathname].exports; } // 创建模块,新建Module实例 const module = new Module(absPathname); // 添加缓存 Module._cache[absPathname] = module; // 加载当前模块 tryModuleLoad(module); // 返回exports对象 return module.exports; } 增加功能:省略模块后缀名。 自动给模块添加后缀名,实现省略后缀名加载模块,其实也就是如果文件没有后缀名的时候遍历一下所有的后缀名看一下文件是否存在。 // 定义导入类,参数为模块路径 function Require(modulePath) { // 获取当前要加载的绝对路径 let absPathname = path.resolve(__dirname, modulePath); // 获取所有后缀名 const extNames = Object.keys(Module._extensions); let index = 0; // 存储原始文件路径 const oldPath = absPathname; function findExt(absPathname) { if (index === extNames.length) { return throw new Error('文件不存在'); } try { fs.accessSync(absPathname); return absPathname; } catch(e) { const ext = extNames[index++]; findExt(oldPath + ext); } } // 递归追加后缀名,判断文件是否存在 absPathname = findExt(absPathname); // 从缓存中读取,如果存在,直接返回结果 if (Module._cache[absPathname]) { return Module._cache[absPathname].exports; } // 创建模块,新建Module实例 const module = new Module(absPathname); // 添加缓存 Module._cache[absPathname] = module; // 加载当前模块 tryModuleLoad(module); // 返回exports对象 return module.exports; } 源代码调试 我们可以通过VSCode 调试Node.js 步骤 创建文件a.js module.exports = 'abc' 1.文件test.js let r = require('./a') console.log(r) 1.配置debug,本质是配置.vscode/launch.json文件,而这个文件的本质是能提供多个启动命令入口选择。 一些常见参数如下: program控制启动文件的路径(即入口文件) name下拉菜单中显示的名称(该命令对应的入口名称) request分为 launch(启动)和 attach(附加)(进程已经启动) skipFiles指定单步调试跳过的代码 runtimeExecutable设置运行时可执行文件,默认是 node,可以设置成 nodemon,ts-node,npm 等 修改launch.json,skipFiles指定单步调试跳过的代码 将test.js 文件中的require方法所在行前面打断点 执行调试,进入源码相关入口方法 梳理代码步骤 1.首先进入到进入到require方法:Module.prototype.require 2.调试到Module._load 方法中,该方法返回module.exports,Module._resolveFilename方法返回处理之后的文件地址,将文件改为绝对地址,同时如果文件没有后缀就加上文件后缀。 3.这里定义了Module类。id为文件名。此类中定义了exports属性 4.接着调试到module.load 方法,该方法中使用了策略模式,Module._extensions[extension](this, filename)根据传入的文件后缀名不同调用不同的方法 5.进入到该方法中,看到了核心代码,读取传入的文件地址参数,拿到该文件中的字符串内容,执行module._compile 6.此方法中执行wrapSafe方法。将字符串前后添加函数前后缀,并用Node中的vm模块中的runInthisContext方法执行字符串,便直接执行到了传入文件中的console.log代码行内容。 至此,整个Node中实现require方法的整个流程代码已经调试完毕,通过对源代码的调试,可以帮助我们学习其实现思路,代码风格及规范,有助于帮助我们实现工具库,提升我们的代码思路,同时我们知道相关原理,也对我们解决日常开发工作中遇到的问题提供帮助。 作者:京东物流 乔盼盼 来源:京东云开发者社区 自猿其说Tech 转载请注明来源

优秀的个人博客,低调大师

技术干货:解密最受欢迎的开源 Serverless 框架弹性技术实现

Knative 是一款基于 Kubernetes 的开源 Serverless 应用编排框架,其目标是制定云原生、跨平台的 Serverless 应用编排标准。Knative 主要功能包括基于请求的自动弹性、缩容到 0、多版本管理、基于流量的灰度发布以及事件驱动等。 弹性是 Serverless 中的核心能力,那么 Knative 作为 CNCF 社区最受欢迎的开源 Serverless 应用框架,提供了哪些与众不同的弹性能力呢?本文将带你深入了解 Knative 的弹性实现。(说明:本文基于 Knative 1.8.0 版本进行分析) Knative 提供了基于请求的自动弹性实现 KPA(Knative Pod Autoscaler),也支持 K8s 中的 HPA,此外 Knative 提供了灵活的弹性扩展机制,可以结合自身业务需要,扩展弹性实现。这里我们也会介绍与 MSE 结合实现精准弹性以及与 AHPA 结合实现基于请求的弹性预测。 首先我们介绍 Knative 原生最具吸引力的弹性:KPA。 基于请求的自动弹性 KPA 基于 CPU 或者 Memory 的弹性,有时候并不能完全反映业务的真实使用情况,而基于并发数或者每秒处理请求数 (QPS/RPS),对于 web 服务来说更能直接反映服务性能,Knative 提供了基于请求的自动弹性能力。要获得当前服务的请求数,Knative Serving 为每个 Pod 注入 QUEUE 代理容器 (queue-proxy),该容器负责收集用户容器并发数 (concurrency) 或请求数 (rps) 指标。Autoscaler 定时获取这些指标之后,会根据相应的算法,调整 Deployment 的 Pod 数量,从而实现基于请求的自动扩缩容。 图片来源:https://knative.dev/docs/serving/request-flow/ 基于请求数的弹性算法 Autoscaler 基于每个 Pod 的平均请求数(或并发数)进行弹性计算。默认情况下 Knative 使用基于并发数的自动弹性, 默认 Pod 的最大并发数为 100。此外 Knative 中还提供了一个叫 target-utilization-percentage 的概念,称之为目标使用率,取值范围 0~1,默认是 :0.7。 以基于并发数弹性为例,Pod 数计算方式如下: POD数=并发请求总数/(Pod最大并发数*目标使用率) 例如服务中 Pod 最大并发数设置了 10,这时候如果接收到了 100 个并发请求,目标使用率设置为 0.7,那么 Autoscaler 就会创建了 15 个 POD(100/(0.7*10) 约等于 15)。 缩容到 0 的实现机制 使用 KPA 时当无流量请求时,会将 Pod 数自动缩容到 0;当有请求时,会从 0 开始扩容 Pod。那么 Knative 中是如何实现这样的操作呢?答案是通过模式切换。 Knative 中定义了 2 种请求访问模式:Proxy 和 Serve。Proxy 顾名思义,代理模式,也就是请求会通过 activator 组件进行代理转发。Serve 模式是请求直达模式,从网关直接请求到 Pod,不经过 activator 代理。如下图: 模式的切换是由 autoscaler 组件负责,当请求为 0 时,autoscaler 会将请求模式切换为 Proxy 模式。这时候请求会通过网关请求到 activator 组件,activator 收到请求之后会将请求放在队列中,同时推送指标通知 autoscaler 进行扩容,当 activator 检测到由扩容 Ready 的 Pod 之后,随即将请求进行转发。而 autoscaler 也会判断 Ready 的 Pod,将模式切换为 Serve 模式。 应对突发流量 突发流量下如何快速弹资源 KPA 涉及到 2 个与弹性相关的概念:Stable(稳定模式)和 Panic(恐慌模式),基于这 2 种模式,可以让我们认识到 KPA 如何基于请求做到精细化弹性。 首先稳定模式是基于稳定窗口期,默认是 60 秒。也就是计算在 60 秒时间段内,Pod 的平均并发数。 而恐慌模式是基于恐慌窗口期,恐慌窗口期是通过稳定窗口期与 panic-window-percentage 参数计算得到。panic-window-percentage取值是 0~1,默认是 0.1。恐慌窗口期计算方式:恐慌窗口期=稳定窗口期 *panic-window-percentage。默认情况下也就是 6 秒。计算在 6 秒时间段内,Pod 的平均并发数。 KPA 中会基于稳定模式和恐慌模式 Pod 的平均并发数分别计算所需要的 Pod 数。 那么实际根据哪个值进行弹性生效呢?这里会依据恐慌模式下计算的 Pod 数是否超过恐慌阈值 PanicThreshold 进行判断。恐慌阈值是通过 panic-threshold-percentage/100 计算出来,panic-threshold-percentage 参数默认是 200,也就是恐慌阈值默认是 2。当恐慌模式下计算出来的 Pod 数大于或等于当前 Ready Pod 数的 2 倍,那么就会使用恐慌模式 Pod 数进行弹性生效,否则使用稳定模式 Pod 数。 显然,恐慌模式的设计是为了应对突发流量场景。至于弹性敏感度,则可以通过上述的可配置参数进行调节。 突发流量下如何避免 Pod 被打爆 KPA 中可以设置突发请求容量(target-burst-capacity)应对 Pod 被超预期的流量打爆。也就是通过这个参数值的计算,来调节请求是否切换到 Proxy 模式,从而通过 activator 组件作为请求缓冲区。如果当前 ready pod 数*最大并发数-突发请求容量-恐慌模式计算出来的并发数 <0,意味着突发流量超过了容量阈值,则切换到 activator 进行请求缓冲。当突发请求容量值为 0 时,只有 Pod 缩容到 0 时,才切换到 activator。当大于 0 并且 container-concurrency-target-percentage 设置为 100 时,请求总是会通过 activator。-1 表示无限的请求突发容量。请求也总是会通过 activator。 减少冷启动的一些技巧 延迟缩容 对于启动成本较高的 Pod, KPA 中可以通过设置 Pod 延迟缩容时间以及 Pod 缩容到 0 保留期,来减少 Pod 扩缩容频率。 apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go namespace: default spec: template: metadata: annotations: autoscaling.knative.dev/scale-down-delay: ""60s" autoscaling.knative.dev/scale-to-zero-pod-retention-period: "1m5s" spec: containers: - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/helloworld-go:73fbdd56 调低目标使用率,实现资源预热 Knative 中提供了目标阈值使用率的配置。通过调小该值可以提前扩容超过实际需要使用量的 Pod 数,在请求达到目标并发数之前进行扩容,间接的可以做到资源预热。例如,如果 containerConcurrency 设置为 10,目标利用率值设置为 70(百分比),则当所有现有 Pod 的平均并发请求数达到 7 时,Autoscaler 将创建一个新 Pod。因为 Pod 从创建到 Ready 需要一定的时间,通过调低目标利用率值可以做到提前扩容 Pod,从而减少冷启动导致的响应延迟等问题。 apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go namespace: default spec: template: metadata: annotations: autoscaling.knative.dev/target-utilization-percentage: "70" spec: containers: - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/helloworld-go:73fbdd56 配置 KPA 通过上面的介绍,我们对 Knative Pod Autoscaler 工作机制有了进一步的了解,那么接下来介绍如何配置 KPA。Knative 中配置 KPA 提供了两种方式:全局模式和 Revision 模式。 全局模式 全局模式可以修改 K8s 中的 ConfigMap:config-autoscaler,查看 config-autoscaler 使用如下命令: kubectl -n knative-serving get cm config-autoscaler apiVersion: v1 kind: ConfigMap metadata: name: config-autoscaler namespace: knative-serving data: container-concurrency-target-default: "100" container-concurrency-target-percentage: "70" requests-per-second-target-default: "200" target-burst-capacity: "211" stable-window: "60s" panic-window-percentage: "10.0" panic-threshold-percentage: "200.0" max-scale-up-rate: "1000.0" max-scale-down-rate: "2.0" enable-scale-to-zero: "true" scale-to-zero-grace-period: "30s" scale-to-zero-pod-retention-period: "0s" pod-autoscaler-class: "kpa.autoscaling.knative.dev" activator-capacity: "100.0" initial-scale: "1" allow-zero-initial-scale: "false" min-scale: "0" max-scale: "0" scale-down-delay: "0s" 参数说明: 参数 说明 container-concurrency-target-default 默认Pod最大并发数,默认值100 container-concurrency-target-percentage 并发数目标使用率,70实际表示0.7 requests-per-second-target-default 默认每秒请求数(rps),默认值200 target-burst-capacity 突发请求容量 stable-window 稳定窗口,默认60s panic-window-percentage 恐慌窗口比例,默认值为10,则表示默认恐慌窗口期为6秒(60*0.1=6) panic-threshold-percentage 恐慌阈值比例,默认值200 max-scale-up-rate 最大扩缩容速率,表示一次扩容最大数,实际计算方式:math.Ceil(MaxScaleUpRate * readyPodsCount) max-scale-down-rate 最大缩容速率,表示一次缩容最大数,实际计算方式:math.Floor(readyPodsCount / MaxScaleDownRate)。默认值2表示,每次缩容一半。 enable-scale-to-zero 是否开始缩容到0,默认开启 scale-to-zero-grace-period 优雅缩容到0的时间,也就是延迟多久缩容到0,默认30s scale-to-zero-pod-retention-period pod缩容到0保留期,该参数适用于Pod启动成本较高的情况 pod-autoscaler-class 弹性插件类型,当前支持的弹性插件包括:kpa、hpa、ahpa以及mpa(ask场景下配合mse支持缩容到 0) activator-capacity activator请求容量 initial-scale 创建revision时,初始化启动的Pod数,默认1 allow-zero-initial-scale 是否允许创建revision时,初始化0个Pod, 默认false,表示不允许 min-scale revision级别最小保留的Pod数量。默认0表示最小值可以为0 max-scale revision级别最大扩容的Pod数量。默认0表示无最大扩容上限 scale-down-delay 表示延迟缩容时间,默认0表示立即缩容 Revision 版本模式 在 Knative 中可以为每一个 Revision 配置弹性指标,部分配置参数如下: 指标类型 每个 revision 指标注解:autoscaling.knative.dev/metric 支持的指标:"concurrency","rps","cpu","memory"以及其它自定义指标 默认指标:"concurrency" 目标阈值 autoscaling.knative.dev/target 默认值:"100" pod 缩容到 0 保留期 autoscaling.knative.dev/scale-to-zero-pod-retention-period 目标使用率 autoscaling.knative.dev/target-utilization-percentage 配置示例如下: apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go namespace: default spec: template: metadata: annotations: autoscaling.knative.dev/metric: "concurrency" autoscaling.knative.dev/target: "50" autoscaling.knative.dev/scale-to-zero-pod-retention-period: "1m5s" autoscaling.knative.dev/target-utilization-percentage: "80" 对 HPA 的支持 对于 K8s HPA, Knative 也提供天然的配置支持,可以在 Knative 使用基于 CPU 或者 Memory 的自动弹性能力。 基于 CPU 弹性配置 apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go namespace: default spec: template: metadata: annotations: autoscaling.knative.dev/class: "hpa.autoscaling.knative.dev" autoscaling.knative.dev/metric: "cpu" 基于 Memory 的弹性配置 apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go namespace: default spec: template: metadata: annotations: autoscaling.knative.dev/class: "hpa.autoscaling.knative.dev" autoscaling.knative.dev/metric: "memory" 弹性能力增强 Knative 提供了灵活的插件机制(pod-autoscaler-class),可以支持不同的弹性策略。阿里云容器服务 Knative 当前支持的弹性插件包括:kpa、hpa、精准弹性扩缩容 mpa 以及 具有预测能力的 ahpa。 保留资源池 在原生的 KPA 能力之上,我们提供了保留资源池的能力。该功能可以应用在如下场景: ECS 与 ECI 混用。如果希望常态情况下使用 ECS 资源,突发流量使用 ECI, 那么我们可以通过保留资源池来实现。如单个 Pod 处理的并发 10,保留资源池 Pod 数为 5,那么常态下通过 ECS 资源可以应对不超过 50 的并发请求。如果并发数超过 50,那么 Knative 就会扩容新的 Pod 数来满足需求,新扩容出来的资源使用 ECI。 资源预热。对于完全使用 ECI 的场景,也可以通过保留资源池实现资源预热。当在业务波谷时使用保留实例替换默认的计算型实例,当第一个请求来临时使用保留实例提供服务,同时也会触发默认规格实例的扩容。当默认规格实例扩容完成以后所有新请求就会都转发到默认规格上,同时保留实例则不会接受新的请求,并且等保留实例所有接收到的请求处理完成以后就会被下线。通过这种无缝替换的方式实现了成本和效率的平衡,即降低了常驻实例的成本又不会有显著的冷启动时长。 精准弹性扩缩容 单个 Pod 处理请求的吞吐率有限,如果多个请求转发到同一个 Pod,会导致服务端过载异常,因此需要精准的控制单个 Pod 请求并发处理数。尤其对一些 AIGC 场景下,单个请求会占用较多的 GPU 资源,需要严格的限制每个 Pod 并发处理的请求数。 Knative 与 MSE 云原生网关结合,提供基于并发数精准控制弹性的实现:mpa 弹性插件。 mpa 会从 MSE 网关获取并发数,并计算所需要的 Pod 数进行扩缩容,而 MSE 网关可以做到基于请求精准转发。 配置示例如下: apiVersion: serving.knative.dev/v1 kind: Service metadata: name: helloworld-go spec: template: metadata: annotations: autoscaling.knative.dev/class: mpa.autoscaling.knative.dev autoscaling.knative.dev/max-scale: '20' spec: containerConcurrency: 5 containers: - image: registry-vpc.cn-beijing.aliyuncs.com/knative-sample/helloworld-go:73fbdd56 env: - name: TARGET value: "Knative" 参数说明: 参数 说明 autoscaling.knative.dev/class: mpa.autoscaling.knative.dev mpa表明使用MSE指标进行扩缩容,支持缩容到0 autoscaling.knative.dev/max-scale: '20' 扩容Pod数上限是20 containerConcurrency: 5 表示单个Pod能处理的最大并发数是5 弹性预测 AHPA 容器服务 AHPA(Advanced Horizontal Pod Autoscaler)可以根据业务历史指标,自动识别弹性周期并对容量进行预测,解决弹性滞后的问题。 当前 Knative 支持 AHPA(Advanced Horizontal Pod Autoscaler)的弹性能力,当请求具有周期性时,可通过弹性预测,实现预热资源。相比于调低阈值进行资源预热,通过 AHPA 可以最大程度的提升资源利用率。 此外由于 AHPA 支持自定义指标配置,Knative 与 AHPA 结合可以做到基于消息队列以及响应延迟 rt 的自动弹性。 基于 rps 使用 AHPA 配置示例如下: apiVersion: serving.knative.dev/v1 kind: Service metadata: name: autoscale-go namespace: default spec: template: metadata: labels: app: autoscale-go annotations: autoscaling.knative.dev/class: ahpa.autoscaling.knative.dev autoscaling.knative.dev/target: "10" autoscaling.knative.dev/metric: "rps" autoscaling.knative.dev/minScale: "1" autoscaling.knative.dev/maxScale: "30" autoscaling.alibabacloud.com/scaleStrategy: "observer" spec: containers: - image: registry.cn-hangzhou.aliyuncs.com/knative-sample/autoscale-go:0.1 参数说明: 参数 说明 autoscaling.knative.dev/class: ahpa.autoscaling.knative.dev 指定弹性插件AHPA。 autoscaling.knative.dev/metric: "rps" 设置AHPA指标。目前支持concurrency、rps以及响应时间rt。 autoscaling.knative.dev/target: "10" 设置AHPA指标的阈值,本示例rps阈值为10,表示单个Pod每秒最大处理请求数10。 autoscaling.knative.dev/minScale: "1" 设置弹性策略实例数的最小值为1。 autoscaling.knative.dev/maxScale: "30" 设置弹性策略实例数的最大值为30。 http://autoscaling.alibabacloud.com/scaleStrategy:"observer" 设置弹性伸缩模式,默认值是observer。observer:表示只观察,但不做真正的伸缩动作。您可以通过这种方式观察AHPA的工作是否符合预期。由于预测需要历史7天的数据,因此创建服务默认是observer模式。auto:表示由AHPA负责扩容和缩容,把AHPA指标和阈值输入到AHPA,AHPA最终决定是否生效。 ta-draft-node="block" data-draft-type="table" data-size="normal" data-row-style="normal"> 参数 说明 autoscaling.knative.dev/class: ahpa.autoscaling.knative.dev 指定弹性插件AHPA。 autoscaling.knative.dev/metric: "rps" 设置AHPA指标。目前支持concurrency、rps以及响应时间rt。 autoscaling.knative.dev/target: "10" 设置AHPA指标的阈值,本示例rps阈值为10,表示单个Pod每秒最大处理请求数10。 autoscaling.knative.dev/minScale: "1" 设置弹性策略实例数的最小值为1。 autoscaling.knative.dev/maxScale: "30" 设置弹性策略实例数的最大值为30。 http://autoscaling.alibabacloud.com/scaleStrategy:"observer" 设置弹性伸缩模式,默认值是observer。observer:表示只观察,但不做真正的伸缩动作。您可以通过这种方式观察AHPA的工作是否符合预期。由于预测需要历史7天的数据,因此创建服务默认是observer模式。auto:表示由AHPA负责扩容和缩容,把AHPA指标和阈值输入到AHPA,AHPA最终决定是否生效。 e data-draft-node="block" data-draft-type="table" data-size="normal" data-row-style="normal"> 小结 本文从 Knative 典型弹性实现 KPA 出发进行介绍,包括如何实现基于请求的自动弹性、缩容到 0、应对突发流量以及我们在 Knative 弹性功能上的扩展增强,包括保留资源池,精准弹性以及弹性预测能力。 作者:元毅 点击立即免费试用云产品 开启云上实践之旅! 原文链接 本文为阿里云原创内容,未经允许不得转载。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册