关于原理:使用第一性原理思维思考如何打造提高生产力的平台-京东云技术团队

引言当初全社会都在搞数字化转型,从政府到企业,那么为什么要进行数字化转型呢?实质上还是社会治理和企业经营难度变得更大了。 以企业来说,转型的指标是为了实现有品质的活着,比方能赚更多的钱或者持续保持持重经营,转型的外围是冀望借助数字化技术构建一个管理体系,以应答外部环境动荡、企业竞争变动和技术更新倒退带来的不确定性。 数字化转型会带来大量的研发需要,如何更好更快的交付这些需要成为一个突出问题,该怎么打造一个平台去解决该问题?能不能用第一性原理思维去推导出倒退方向? 什么是第一性原理第一性原理指的是,将问题拆分成最根本的事实或法则,依据这些已知信息,一直推演和计算,从而找到解决问题最优门路的办法。 该思维比拟闻名的利用例子有 埃隆·马斯克升高火箭发射老本的故事。将火箭发射老本进行细分,倒退火箭可重复使用发射技术,简化设计和改良工艺以升高火箭制作老本亨利·福特升高汽车制作老本的故事。将汽车拆解为最根本的部件,利用装配线和流水线工人批量制作汽车埃隆·马斯克升高汽车电池组老本的故事。剖析电池的原材料市场价格,一直迫近这个价格极限,采纳自建工厂、改良电池设计、改良生产过程等措施来降低成本乔布斯去掉手机物理键盘的故事。剖析手机的组成部件,通过去掉物理键盘来扩充触摸屏区域,带来更好的体验和更低的制作老本如果采纳类推思维去思考类推思维是指借助本人的感觉和教训积攒常识的办法 以国内外做得好的平台为例,微软的 Power Platform、守业公司轻流这些平台都以帮忙企业疾速开发利用、应答市场倒退为目标。 微软 Power Platform[]() 除了上述 5 大产品外,还具备以下性能 Dataverse:能够进行数据的治理,相当于是个更易于应用的数据库连接器:能够和大量的 API、服务、零碎进行通信Common Data Model:标准化和可扩大的数据模型,能不便数据的流转和利用,由微软和行业合作伙伴多年积攒而成生态系统:Power Platform 能够连贯到微软的生态系统,例如 Azure(寰球第二大云计算平台)、Microsoft 365(蕴含 Office 办公套件和 Teams)、Dynamics 365(蕴含 ERP 和 CRM 性能)Power Fx:低代码语言,相似 Excel 的公式,相比业余的编程语言更易于应用Power Platform 的产品理念是让没有技术背景的人、开发者都能轻松高效的解决业务问题。产品架构上以 Dataverse 为外围,内置数据模型(Common Data Model)升高业务建模老本,可视化的 UI 编辑器(Power Apps、Power Pages)可升高利用开发成本,报表制作工具(Power BI)可挖掘出数据的价值,效率工具(Power Automate 和 Power Virtual Agents)可将员工从干燥反复的工作中解放出来,这一整套组合拳下来,冀望帮忙企业更好的倒退业务,节俭经营老本 微软这么做了,咱们是不是也要这么做呢?即 开发一套非专业开发者也能学会应用的数据库开发可视化的 UI 编辑器,反对挪动利用、门户、报表的制作开发效率工具,实现工作的自动化,反对桌面软件、Web、即时聊天窗口开发一种非专业开发者也能学会应用的编程语言轻流All-in-One 利用开发平台 []() 专有轻流,面向多角色的企业级平台产品 []() 轻流是从表单+流程治理这种高频场景切入的,面向的是业务人员而不是开发者,随着行业案例的积攒,客户的增多, 逐渐倒退为疾速解决业务问题的利用开发平台和面向中大客户的企业级平台这两个套餐分级迭代。 值得一提的是轻流和神策一样,也采纳了订阅制免费模式,这样保障了不论是私有云还是私有化部署都能以高迭代速度去服务客户 轻流这么做了,咱们是不是也要这么做呢?即 开发一套通过表单来进行数据建模的工具,反对流程治理,反对自动化工作开发可视化的 UI 编辑器,反对挪动利用、门户、报表的制作提供插件能力,不便 IT 人员进行系统集成和性能扩大继续集成内部支流零碎和业务能力,丰盛平台生态思考这些平台都提供了数据建模能力,一种是相似数据库的建模过程,一种是表单的建模过程这些平台都提供了 UI 编辑器,能够进行前端页面的可视化搭建,反对多平台(挪动端、Web 端)这些平台都提供了代码开发能力,能够进行代码级别的逻辑编写这些平台都提供了扩大机制,能够集成内部零碎和业务能力看来,如果要做一个生产力平台,就必须提供这四大性能 ...

July 6, 2023 · 1 min · jiezi

关于原理:PC-GWPASan方案原理-堆破坏问题排查实践

背景家喻户晓,堆crash dump是最难剖析的dump类型之一。此类crash最大的问题在于,造成谬误的代码无奈在产生堆毁坏时被发现。线上采集到的minidump,仅能提供非常无限的信息。当调试工具报告了堆毁坏、堆内存拜访违例后,即使是有教训的开发人员也会感觉头疼。 剪映专业版及其依赖的音视频编辑SDK、特效模块均采纳MD的形式链接规范库,这意味着任何一个模块呈现了堆损坏都会相互影响。从crash的地位回溯堆毁坏的源头,是一个十分有挑战性的工作。剪映业务模块较常见的是Use-after-free,而音视频编辑SDK和特效模块这类底层算法特效模块更多的是Buffer-overflow,不同团队模块间的堆谬误相互影响,导致问题难以定位。 GWP-ASan是Google主导开发的用于检测堆内存问题的调试工具。它基于经典的Electric Fence Malloc调试器原理,概率采样内存调配行为,抓取内存问题并生成上传解体报告。说到这里,兴许你会好奇它和ASan(Address Sanitizer)的区别。ASan是一种编译器调试工具,监控所有内存调配行为,能够发现栈、堆和全局内存问题,但它性能开销很高(2-3倍),不适宜线上应用。GWP-ASan相较于ASan,尽管无奈发现栈内存和全局内存问题,但因为它是采样监控,性能耗费能够忽略不计,更实用于线上场景。目前,GWP-ASan可检测的谬误有: Use-after-freeBuffer-underflowBuffer-overflowDouble-freefree-invalid-address Electric Fence Malloc调试器:https://linux.die.net/man/3/efenceGWP-ASan有多种实现计划,本计划基于Windows平台阐明,字节外部APM-PC平台相较于市面上其余计划的亮点有: 无侵入式接入,能够检测特定类型三方库的内存调配。反对无感知监测,发现异常后过程可持续运行。反对调整检测所用的堆页面个数配置和采样率配置,灵便调整性能耗费。剪映专业版接入字节外部APM-PC平台的GWP-ASan性能后,帮忙业务、音视频编辑SDK、特效模块解决30余例疑难堆crash。GWP-ASan dump比原生dump提供了更丰盛的信息,并指出了堆crash关联的信息细节,升高了疑难crash的排查难度,无效缩短了研发排查、修复问题的工夫。 技术计划监控原理检测原理概述创立受爱护内存池:首先,咱们须要保留一块间断的n*page size的受爱护内存池。其中,可分配内存的page是Slot,不可分配内存的page是Guard Page。Slot和Guard Page距离散布,整个内存池最前和最初都是Guard Page,所有的Slot都受到Guard Page爱护,之后利用调配的堆内存将随机采样调配到这些Slot上。 采样监控内存调配行为,记录堆栈:之后,hook利用堆内存调配行为,每次调配堆内存时,随机决定指标内存是走GWP-ASan调配——调配在一个闲暇的Slot上,还是走零碎原生调配。如果走GWP-ASan调配,那么指标内存会被随机左对齐/右对齐调配在一个闲暇的Slot上,同时记录分配内存的堆栈信息。 而当开释内存时,会先判断指标内存是否在GWP-ASan受爱护内存池上,如果是,那么开释这块内存和其所在的Slot,同时记录开释内存的堆栈。slot闲暇后,能够从新被用于调配。堆栈信息记录在metadata中。 继续监测,记录异样:   首先,咱们须要晓得Guard Page和闲暇的Slot都是不可读写的。接下来咱们看看GWP-ASan是如何发现异常的:Use-after-free: Slot上未分配内存时,是不可读写的。当拜访到不可读写的Slot时,利用抛出异样,此时查看该Slot是否刚开释过内存,如果开释过内存,那么能够断定此异样为Use-after-free。Buffer-underflow:当内存左对齐调配在Slot上时,如果产生了underflow,利用会拜访到Slot左侧不可读写的Guard Page,利用抛出异样,此异样为Buffer-underflow。Buffer-overflow:当内存右对齐调配在Slot上时,如果产生了overflow,利用会拜访到Slot右侧不可读写的Guard Page,利用抛出异样,此异样为Buffer-overflow。Double-free:利用开释内存时,首先查看指标内存地址是否位于受爱护内存池区间内,如是,由GWP-ASan开释内存,开释前查看指标内存地址所在Slot是否曾经被开释,如是,那么能够断定此异样为Double-free。Free-invalid-address: 利用开释内存时,首先查看指标内存地址是否位于受爱护内存池区间内,如是,由GWP-ASan开释内存,开释前先查看要开释的内存地址和之前调配返回的内存地址是否相等,如果不相等,那阐明指标开释地址是非法地址。此异样为Free-invalid-address。堆内存调配API后面曾经提到,GWP-ASan用于检测堆内存问题,为了检测堆内存问题,必须先感知利用内存调配行为。很天然的,咱们会想到hook内存调配办法,然而该hook哪个办法呢? 下图形容了Windows利用调配堆内存的可用办法: GlobalAlloc/LocalAlloc是为了兼容Windows旧版本的API,当初根本不实用,所以不监控。HeapAlloc/HeapFree个别用于过程分配内存,不监控。VirtualAlloc是应用层内存调配的底层实现,开发个别不间接用此API分配内存,它离利用调配堆内存行为太远,堆栈参考意义不大;且Windows GWP-ASan须要基于此实现,因而,也不监控。 最终选定Hook malloc/free等系列办法,hook malloc/free后,能感知到用户调配的堆内存。 ### Hook计划 上面的计划都是应用层的Hook计划,内核层Hook仅实用于x86平台。 Detours库作为微软官网出品的hook库,兼容性佳,稳定性好,是最佳抉择。然而还须要留神的是,Windows下,运行时库配置会影响hook后果,Detours只能无侵入式hook/MD库的内存调配行为,/MT库须要提供本身内存调配的函数指针能力hook。 堆栈记录首先要阐明的是,GWP-ASan监控依赖解体监控。Use-after-free、Buffer-underflow、Buffer-overflow都是在客户端产生异样后,联合GWP-ASan的metadata去断定的。目前字节外部APM-PC平台的解体报告格局为minidump。一个minidump文件由多种streams组成,如thread_list_stream、module_list_stream和exception_stream等等。不同stream记录了不同信息,咱们能够将GWP-ASan采集到的异样信息视为独自的gwpasan_stream,附加到minidump文件中。 GWP-ASan采集的信息次要包含:谬误类型、调配地址和大小、调配堆栈、开释堆栈(如有)、受爱护内存池起止地址。这些信息基于Protobuf协定序列化后,被增加到minidump文件中。GWP-ASan通过Windows native API CaptureStackBackTrace API在客户端回溯 “开释/调配” 堆栈。minidump上传到平台后,平台抽取出GWP-ASan信息,联合minidump中loaded module list,联合相干模块的符号表,符号化GWP-ASan调配/开释堆栈。GWP-ASan信息联合minidump本来的信息,根本就能定位问题。 监控流程 拓展场景无解体计划GWP-ASan检测到异样后,会被动解体导致客户端过程退出,给用户带来了不良体验。无解体的GWP-ASan检测到异样后,再将对应内存页标注为可读写的(如为use-after-free/buffer-underflow/buffer-overflow),仅生成上传解体报告,不被动终结过程,客户端标注异样已解决。用户无感知,程序持续运行。须要留神的是,客户端在UEF里标记拜访区域内存页为可读写内存页可能影响后续的GWP-ASan检测。 实战分享Use-After-Free:开释后应用理论案例 1咱们看下惯例的dump输入,windbg告知咱们程序crash在25行。 因为12行有空指针查看,能够排除空指针问题。 执行.ecxr复原异样现场也能够证实,此crash和空指针无关。只是一个内存拜访违例。 汇编指定地址,能够晓得这个crash动作是在读取类的虚指针,读取内存的过程中crash了。 00007ffb`d422e4a0 498b06 mov rax,qword ptr [r14]00007ffb`d422e4a3 488bd5 mov rdx,rbp00007ffb`d422e4a6 498bce mov rcx,r1400007ffb`d422e4a9 ff10 call qword ptr [rax]查看问题代码: ...

April 12, 2023 · 4 min · jiezi

关于原理:得物技术深入理解synchronzied底层原理

一、synchronized简介synchronized是Java中的关键字,是一种同步锁。在多线程编程中,有可能会呈现多个线程同时争抢同一个共享资源的状况,这个资源个别被称为临界资源。这种共享资源能够被多个线程同时拜访,且又能够同时被多个线程批改,然而线程的执行是须要CPU的资源调度,其过程是不可控的,所以须要采纳一种同步机制来管制对共享资源的拜访,于是线程同步锁——synchronized就应运而生了。 二、如何解决线程并发平安问题多线程并发读写访问临界资源的状况下,是会存在线程平安问题的,能够采纳的同步互斥拜访的形式,就是在同一时刻,只能有同一个线程可能拜访到临界资源。当多个线程执行同一个办法时,该办法外部的局部变量并不是临界资源,因为这些局部变量会在类加载的时候存在每个线程的公有栈的局部变量表中,因而不属于共享资源,所有不会导致线程平安问题。 三、synchronized用法synchronized关键字最次要有以下3种应用形式: 润饰类办法,作用于以后类加锁,如果多个线程不同对象拜访该办法,则无奈保障同步。润饰静态方法,作用于以后类对象加锁,进入同步代码前要取得以后类对象的锁,锁的是蕴含这个办法的类,也就是类对象,这样如果多个线程不同对象拜访该静态方法,也是能够保障同步的。润饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要取得给定对象的锁。四、Synchronized原理剖析能够先通过一个简略的案例看一下同步代码块: public class SynchTestDemo { public void print() { synchronized ("得物") { System.out.println("Hello World"); } } }synchronized属于Java关键字,没方法间接看到其底层源码,所以只能通过class文件进行反汇编。 先通过javac SynchTestDemo.java指令间接SynchTestDemo.java文件编译成SynchTestDemo.class文件;再通过javap -v SynchTestDemo.class指令再对SynchTestDemo.class文件进行反汇编,能够失去上面的字节码指令: 这些反编译的字节码指令这里就不具体解释了,对照着JVM指令手册也能看懂是什么意思。通过上图反编译的后果能够看出,monitorexit指令实际上是执行了两次,第一次是失常状况下开释锁,第二次为产生异常情况时开释锁,这样做的目标在于保障线程不死锁。 monitorenter首先能够看一下JVM标准中对于monitorenter的形容: 翻译过去就是:任何一个对象都有一个monitor与其相关联,当且有一个monitor被持有后,它将处于锁定的状态,其余线程无奈来获取该monitor。当JVM执行某个线程的某个办法外部的monitorenter时,他会尝试去获取以后对应的monitor的所有权。其过程如下: 如果monitor的进入数为0,则该线程进入monitor,而后将进入数设置为1,该线程即为monitor的所有者;如果线程曾经占有该monitor,只是从新进入,则进入monitor的进入数加1;如果其余线程曾经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再从新尝试获取monitor的所有权;monitorexit也能够先看一下JVM标准中对monitorexit的形容: 翻译过去就是: 能执行monitorexit指令的线程肯定是领有以后对象的monitor的所有权的线程;执行monitorexit时会将monitor的进入数减1。当monitor的进入数减为0时,以后线程退出monitor,不再领有monitor的所有权,此时其余被这个monitor阻塞的线程能够尝试去获取这个monitor的所有权;synchronized关键字被编译成字节码后会被翻译成monitorenter和monitorexit两条指令别离在同步块逻辑代码的起始地位与完结地位,如下图所示: 每个同步对象都有一个本人的Monitor(监视器锁),加锁过程如下图所示: 通过下面的形容能够看出synchronized的实现原理:synchronized的底层理论是通过一个monitor对象来实现的,其实wait/notify办法也是依赖于monitor对象来实现的,这就是为什么只有在同步代码块或者办法中能力调用该办法,否则就会抛出出java.lang.IllegalMonitorStateException的异样的起因。 上面能够再通过一个简略的案例看一下同步办法: public class SynchTestDemo { public synchronized void print() { System.out.println("Hello World"); } }与下面同理能够查看到,该办法的字节码指令: 从字节码反编译的能够看出,同步办法并没有通过指令monitorenter和monitorexit来实现的,然而绝对于一般办法来说,其常量池多了了 ACC_SYNCHRONIZED 标示符。JVM理论就是依据该标识符来实现办法的同步的。 当办法被调用时,会查看ACC_SYNCHRONIZED标记是否被设置,若被设置,线程会先获取monitor,获取胜利能力执行办法体,办法执行实现后会再次开释monitor。在办法执行期间,其余线程都无奈取得同一个monitor对象。 其实两种同步形式从实质上看是没有区别的,两个指令的执行都是JVM调用操作系统的互斥原语mutex来实现的,被阻塞的线程会被挂起、期待从新调度,会导致线程在“用户态”和“内核态”进行切换,就会对性能有很大的影响。 五、什么是monitor?monitor通常被形容为一个对象,能够将其了解为一个同步工具,或者能够了解为一种同步机制。所有的Java对象自打new进去的时候就自带了一把锁,就是monitor锁,也就是对象锁,存在于对象头(Mark Word),锁标识位为10,指针指向的是monitor对象起始地址。在Java虚拟机(HotSpot)中,Monitor是由其底层理论是由C++对象ObjectMonitor实现的: ObjectMonitor() { _header = NULL; _count = 0; //用来记录该线程获取锁的次数 _waiters = 0, _recursions = 0; // 线程的重入次数 _object = NULL; // 存储该monitor的对象 _owner = NULL; // 标识领有该monitor的线程 _WaitSet = NULL; // 处于wait状态的线程,会被退出到_WaitSet _WaitSetLock = 0 ; _Responsible = NULL; _succ = NULL; _cxq = NULL; // 多线程竞争锁时的单向队列 FreeNext = NULL; _EntryList = NULL; // 处于期待锁block状态的线程,会被退出到该列表 _SpinFreq = 0; _SpinClock = 0; OwnerIsThread = 0;}_owner:初始时为NULL。当有线程占有该monitor时,owner标记为该线程的惟一标识。当线程开释monitor时,owner又复原为NULL。owner是一个临界资源,JVM是通过CAS操作来保障其线程平安的;_cxq:竞争队列,所有申请锁的线程首先会被放在这个队列中(单向链接)。cxq是一个临界资源,JVM通过CAS原子指令来批改cxq队列。批改前cxq的旧值填入了node的next字段,_cxq指向新值(新线程)。因而_cxq是一个后进先出的stack(栈);_EntryList:_cxq队列中有资格成为候选资源的线程会被挪动到该队列中;_WaitSet:因为调用wait办法而被阻塞的线程会被放在该队列中。举个例子具体分析一下_cxq队列与_EntryList队列的区别: ...

September 29, 2021 · 7 min · jiezi

关于原理:JS-原生方法原理探究五如何实现-instanceof

这是JS 原生办法原理探索系列的第五篇文章。本文会介绍如何实现 instanceof 办法。 typeof 操作符返回一个示意数据类型的字符串,它能够应酬惯例场景下的数据类型判断。对根本数据类型 undefined、 boolean、string、 number、Symbol 和援用数据类型 function 都能够正确判断,然而对 null、数组、对象等则对立返回 "object"。 比如说: function F1(){}function F2(){}const obj1 = new F1()const obj2 = new F2()typeof obj1 // ‘object’typeof obj2 // 'object' 这里只能看出 obj1 和 obj2 是对象,但不晓得具体是哪个构造函数创立的对象。 但应用 instanceof 之后,就高深莫测了: console.log(obj1 instanceof F1) // trueconsole.log(obj1 instanceof F2) // falseconsole.log(obj2 instanceof F2) // true依据 MDN 的形容: instanceof 运算符用于检测构造函数的 prototype 属性是否呈现在某个实例对象的原型链上。instanceof 运算符有两个操作数,左操作数通常是一个实例对象,它的类型能够是对象或者函数,也能够是根本类型(这种状况下不会报错,但总返回 false),右操作数通常是一个可调用的(callable)对象,咱们能够间接认为它的类型应该是一个函数。 那么 instanceof 的实现原理是什么呢?从定义中咱们能够看到,它的原理和原型链的机制无关,具体地说,它会拿到右操作数的原型对象,而后在左操作数上通过 __proto__ 一直查找实例的原型链,只有右操作数的 prototype 呈现在左操作数的原型链上时,就返回 true。如果原型链始终查找到止境 —— 也就是 null,还没有找到右操作数的原型,就返回 false。 ...

June 8, 2021 · 2 min · jiezi

关于原理:JS-原生方法原理探究三从规范解读如何实现-new-操作符

这是 JS 原生办法原理探索系列的第三篇文章。本文会介绍如何模仿实现 new 操作符。对于 new 的具体用法,MDN 曾经形容得很分明了,这里咱们不说废话,间接讲如何模仿实现。 new 操作符的标准留神:上面展现的所有标准都是 ES5 版本的,与当初最新的标准有些区别首先看一下依据标准的形容, new 操作符做了什么事: 全是英文,不过没关系,我简略翻译一下: 我在应用 new 操作符的时候,前面跟着的构造函数可能带参数,也可能不带参数,如果不带参数的话,比如说 new Fn(),那么这里这个 Fn 就是一个 NewExpression;如果带参数,比如说 new Fn(name,age),那么这里的 Fn 就是一个 MemberExpression。 这两种状况下应用 new 操作符所进行的操作有点点不同,这里拿带参数的状况阐明一下: 首先会对 Fn 这个 MemberExpression 求值,其后果是指向理论函数对象的一个援用,咱们把这个援用作为 ref接着调用 GetValue(ref) 进行求值,失去理论的函数对象,把这个对象作为 constructor对 Arguments 也就是传进来的参数求值,失去一个参数列表,作为 argList如果 constructor 不是对象,则抛出类型谬误如果 constructor 没有实现外部的 [[Constructor]] 办法,也抛出类型谬误调用 constructor 的 [[Constructor]]办法,并将 argList 传入作为参数,返回调用后果从这些形容能够看出,更多的实现细节放在函数的 [[Constructor]] 办法里。那么这个办法具体是做什么用的呢? [[Constructor]] 的标准在 JS 中,函数有两种调用形式,一种是失常调用,这将调用函数的外部办法 [[Call]],还有一种是通过 new 调用,此时的函数作为一个构造函数,这将调用函数的另一个外部办法 [[Consturct]]。所以,要实现 new 操作的话,咱们得先搞懂 [[Construct]] 外部办法做了什么事。 ...

June 8, 2021 · 2 min · jiezi