精华内容
下载资源
问答
  • 电源滤波:AC信号被转换为DC信号 4.RC滤波器 MLCC应用特点 陈永学表示,微型化是半导体和MLCC共同演进的方向,不同领域对MLCC的需求也不尽相同。比如手机和穿戴设备对MLCC要求超微型和高比容,工业设备及车载互联...

    集微网消息(文/Jimmy)集微直播间自开播以来获得了大量来自行业的关注与好评。其中“集微公开课”栏目联合行业头部企业,通过线上直播的方式分享精彩主题内容,同时设立直播间文字提问互动环节。集微网希望将“集微公开课”栏目打造成中国ICT产业最专业、优质的线上培训课程,深化产教融合,助力中国ICT产业发展。

    5月8日(周五)上午10:00,第十期“集微公开课”邀请到深圳市宇阳科技发展有限公司集团战略开拓中心总监陈永学,带来了以《宇阳科技:和您一起探讨大有可为的MLCC》为主题的精彩演讲。

    点这里观看回放

    7a240916d63f26d9fbfae34ab60b9ee3.png

    MLCC市场概况

    被动元件又称为无源器件,是指不影响信号基本特征,仅令讯号通过而未加以更改的电子元件。最常见的有电阻、电容、电感、陶振、晶振、变压器等。其中,电容作为主要的被动元件之一,其产量约占整个电子元件行业的40%。

    2dcefd935a87527813b04fd1d08151a2.png

    陶瓷电容是最主要的电容产品类型,大约占电容市场份额的56%,其优势在于体积小、高频性能好、寿命长、电压范围大。陶瓷电容可细分为单层陶瓷电容、片式多层陶瓷电容(MLCC)和引线式多层陶瓷电容。其中,MLCC是最主要的产品类型,占陶瓷电容市场约93%。

    MLCC凭借其容量大、寿命高、耐高温高压、体积小、物美价廉等优势,在整体电容市场上的占比不断提高。

    近年来,消费电子的创新持续驱动着市场对MLCC的需求,特别是智能手机、音频设备、5G等领域对需求的拉动显著。智能手机技术升级对于被动元件的拉动非常明显,加速提升了对小型化被动元件的需求。

    31bf29d5f8bdb3b60df4fc0966df0a37.png

    通过对比iPhone几代手机的MLCC用量发现,每次更新对MLCC的需求量都有逐步增大的趋势。iPhone X单机对MLCC的用量达到了1100只,相比初代增长了5倍。陈永学指出,5G时代随着射频前端数量的增加,单机MLCC用量将再提升80%以上。

    不光智能手机市场,汽车和工业应用领域也是在MLCC下游需求边际中增长最快,汽车行业对MLCC需求增长主要来自ADAS等驱动汽车电子化以及电动车对MLCC的需求提升。而工业应用领域随着IoT应用的成熟和增加,对MLCC的需求也持续旺盛。

    a7c8ba0ecbf8521459432833389df662.png

    陈永学指出,车用MLCC必须能够适应高温、强烈振动、冲击等恶劣环境,对安全性要求更高,细分市场更多,倒逼MLCC行业朝着高端化和精细化发展。并且车用MLCC认证周期长,订单稳定,技术难度更高,行业各厂商还有很大的发展空间。

    各类汽车对MLCC需求颗数不尽相同。一般来讲,普通燃油车单车MLCC需求量约3000颗,纯电动车所需量则约为18000颗。然后,特斯拉的三款车型单车对MLCC需求量均在10000颗以上,是普通燃油车的4倍。

    随着MLCC可靠性、集成度和性能的不断提升,MLCC已经成为全球需求量最大、发展最快的被动元件之一。预计到2023年,MLCC需求量将扩大至46840亿只,市场空间达到182亿美元。

    226be9685a9dd0e5285246e57e161e19.png

    中国大陆MLCC市场规模增长迅速,2018年至2023年间的复合增长率约4.2%,高于全球平均水平。2018年大陆MLCC消费量达28890亿只,占全球消费量的71.3%,预计到2023年大陆消费量将提升到34810亿只。

    目前,宇阳科技的微型及超微型MLCC(01005、0201、0402)产量占比超过90%,微型化产品占比居行业首位,微型化总产量居全球前三。未来7年,集团规划将投资70亿元建设华东和华南的MLCC新研发、生产基地。

    关于MLCC的小知识

    MLCC是片式多层陶瓷电容器的英文缩写(Multi-Layer Ceramic Capacitor),电容容量正比于介电常数、电极层数、正对面积,反比于介质厚度。

    aad24914831db833c0439354fae11124.png

    通用MLCC大致可分为I类(低电容率系列、顺电体)和II类(高电容率系列、铁电体)两类。

    7ffb3acdcda0932d5ec8a704aa2dc333.png

    602547863459643bfe1813cb2629deaa.png

    MLCC一般有四大作用:

    1.耦合:电容器对DC会切断,只接受AC信号

    2.去耦:电容器对DC会切断,并只能接受噪音信号

    3.电源滤波:AC信号被转换为DC信号

    4.RC滤波器

    3d912b737962745bb3199a5e7c7cb532.png

    MLCC应用特点

    陈永学表示,微型化是半导体和MLCC共同演进的方向,不同领域对MLCC的需求也不尽相同。比如手机和穿戴设备对MLCC要求超微型和高比容,工业设备及车载互联要求MLCC高可靠性。

    3b3cdb6e92a7b77c13f2e8630d8fb85b.png

    随着5G的到来,对MLCC的要求也愈发严苛,具备高可靠性外,还需具备高频高Q、高温度及高电压。

    c418faf8a65b2eb9607f65acab09fc1b.png

    终端产品不断向高集成、多功能、轻薄化演进,对微型化、高温、高频高Q提出了更多需求。

    9daaa76191c53fa67d3866f803a92c23.png

    在PC、安防、基站等工作温度较高的设备中使用X6S/X7T产品,大幅提升工作可靠性。

    17dbb844f6ebdebaa0a1b7a2f102f23d.png

    a57f8c9026e3c5fc24ea64c4da7df1ae.png
    展开全文
  • 架构演进

    2021-03-06 23:36:51
    目的 满足业务的增长,根据不同的业务规模选择适用的架构。 概念 分布式 what ...提高性能:解决单机性能瓶颈,多个节点可以通过负载均衡的方式共同承担外部的访问。 how 把zookeepe中的Master和Slav

    概述

    技术作为业务的支撑,它永远是伴随着业务的发展而发展,我们需要不断的学习新的技术去解决新的问题。
    但是伴随着年龄的增长,我们能够投入的时间和精力越来越少,掌握科学的学习方法,使用自己的思维方式、对技术的理解层次、系统的知识体系去包容新的技术就十分重要。

    目的

    满足业务的增长,根据不同的业务规模选择适用的架构。

    概念

    分布式

    what

    系统中不同功能的服务部署到不同的服务器上。

    why

    主要是为了解决业务增长带来的性能问题。

    how

    比如把tomcat服务和数据库服务分别部署到不同的服务器上。

    集群

    what

    同一功能服务部署在不同的服务器上,对外统一提供服务。

    why

    提供高可用:集群中的某个节点出问题不影响集群提供的服务。
    提高性能:解决单机性能瓶颈,多个节点可以通过负载均衡的方式共同承担外部的访问。

    how

    把zookeepe中的Master和Slave分别部署在不同的服务器上,共同组成一个整体对外提供配置服务。

    case

    服务按照预估TPS,把同一服务用tomcat分别部署在多台服务器上,统一对外提供数字商品服务。

    高可用

    what

    服务中部分节点失效时,其他节点能够接替它继续提供服务,则认为服务高可用。
    集群是保证服务高可用的解决方案。

    why

    异常场景下,不影响用户使用。

    how

    通过集群可用保证高可用。

    负载均衡

    what

    外部请求可以均匀的分发到多个节点上,使系统中的每个节点能够均匀的处理请求,则认为系统是负载均衡的。

    why

    高可用;高性能;

    how

    通过使用Nginx,采用负载均衡算法,实现nginx反向代理的服务器达到负载均衡。

    反向代理

    what

    外部请求进入系统,代理服务器把请求转发到某台服务器上,对外部请求来说只有代理服务器与之交互,此时代理服务器实现的是反向代理。

    why

    通过反向代理可以实现负载均衡。

    how

    nginx反向代理配置,通过nginx实现反向代理。

    演进

    单机架构

    在这里插入图片描述

    what

    把系统所需要的所有资源都部署在同一台服务器上。

    why

    1. 简单。
    2. 用户少,业务小。
    3. 性能要求不高。

    how

    tomcat、mysql等都部署在一台服务器上

    case

    淘宝早期网站架构:应用量与用户数较少,可以把tomcat和数据库部署到同一台服务器上。浏览器往www.taobao.com发起请求时,首先经过DNS服务器把域名转换为实际ip地址10.102.4.1,浏览器转而访问ip对应的tomcat。

    第一次演进:tomcat与数据库分开部署

    在这里插入图片描述

    目的

    解决服务和数据库竞争资源的问题。

    what

    tomcat和数据库分开部署

    why

    用户增长,tomcat和数据库之间相互竞争资源(CPU,内存,网络等),单机性能不足以支撑业务。

    how

    分布式部署。

    第二次演进:引人本地缓存和分布式缓存

    在这里插入图片描述

    目的

    解决数据库压力过大造成性能瓶颈的问题。

    what

    在项目中加入本地缓存,外部增加分布式缓存。

    why

    1. 并发读写造成数据库压力较大。
    2. 缓存热门商品信息或热门商品的html页面等,缓存能把绝大多数请求在读写数据库前拦截掉,大大降低数据库压力。

    how

    1. 本地缓存使用memcached。
    2. 外部增加分布式缓存使用redis。

    引发的问题

    1. 缓存和数据库一致性问题。
    2. 缓存穿透:缓存和数据库中都没有数据。
    3. 缓存击穿:热点key数据失效,访问落到数据库中。
    4. 缓存雪崩:大量key同一时间失效;redis服务器宕机引发大量key失效;

    第三次演进:引人反向代理实现负载均衡

    在这里插入图片描述

    目的

    解决单个服务无法满足大量用户访问的性能瓶颈。

    what

    在多台服务器上分别部署tomcat,使用反向代理软件(Nginx)把请求均匀分发到每个tomcat中。

    why

    解决单机的性能瓶颈。

    how

    通过Nginx反向代理内部的tomcat服务。

    引发的问题

    1. session共享。
    2. 文件上传下载问题。
    3. 单个数据库性能造成瓶颈。

    第四次演进:数据库读写分离

    在这里插入图片描述

    目的

    解决单个数据库性能瓶颈问题。

    what

    把数据库划分为读库和写库,读库可以有多个,通过同步机制把写库的数据同步到多个读库中。

    why

    解决读写在一个数据库造成的性能问题。

    how

    1. 划分1个写库和多个读库。
    2. 写库通过同步机制把数据同步到多个读库中。
    3. 需要读最新的数据,可以在缓存中多写一份数据,通过读缓存来获取最新的数据。
    4. 使用数据库中间件Mycat,可通过它来组织数据库的读写分离和分库分表,客户端通过它来访问下层的数据库;还可以解决数据同步,数据一致性的问题。

    引发的问题

    写库和读库的数据一致性问题。

    第五次演进:数据库按业务分库

    在这里插入图片描述

    目的

    解决不同业务间相互竞争数据库造成的性能瓶颈问题。

    what

    垂直拆分数据库,按照业务拆分成不同的数据库。

    why

    1. 解决不同业务竞争同一个数据库的问题。
    2. 可以使用分而治之的原则,不同的业务可以区别对待,数据访问量大的,可以多部署几台数据库服务器。

    引发的问题

    1. 分布式事务。
    2. 业务间数据无法直接关联分析。

    第六次演进:大表拆分为小表

    在这里插入图片描述

    目的

    解决单表数据量太大,性能低的问题。

    what

    当大表数据超过500万行或者2G,需要通过水平分表,把一张大表水平拆分成多张小表。

    why

    1. 解决大表性能低的问题。
    2. 数据均匀的分发到不同的数据库中的小表中,可以通过数据库水平扩展的方式来提高性能。

    how

    1. 比如可以通过商品ID进行hash,路由到对应的表中存储、查询。
    2. 针对支付记录,可以按照小时创建表,每个小时表还可以拆分成更小的表,使用用户id或者记录编号来路由数据。
    3. 可以通过Mycat来拆表和访问控制。
    4. MPP数据库架构:大规模数据并行处理架构。
      • 比如Greenplum、TiDB等。
      • 这些MPP数据库能把一个查询解析成分布式的执行计划分发到每台机器上并行执行,最终由数据库本身汇总数据进行返回。

    第七次演进:使用LVS或F5使多个Nginx负载均衡

    在这里插入图片描述

    目的

    解决单个nginx性能瓶颈。

    what

    通过网络第四层的负载均衡解决方案,来实现多个Nginx的负载均衡。

    why

    LVS或F5使用四层的TCP/IP协议,可以支持更丰富的网络协议,性能远高于Nginx。

    how

    1. 单机的LVS可用支持几十万个并发请求。
    2. LVS是单机版的软件,若LVS所在服务器宕机则会导致整个后端系统都无法访问,需要加备用节点。
    3. 可使用keepalived软件模拟出虚拟IP,然后把虚拟IP绑定到多台LVS服务器上,浏览器访问虚拟IP时,会被路由器重定向到真实的LVS服务器,当主LVS服务宕机时,keepalived软件会自动更新路由器中的路由表,把虚拟IP重定向到另外一台正常的LVS服务器,从而达到高可用的效果(集群)。
    4. nginx高可用:多个nginx通过keepalived实行高可用。

    第8次演进:通过DNS轮询实现机房间的负载均衡

    在这里插入图片描述

    目的

    1. 解决单个LVS的性能瓶颈。
    2. 解决不同地区,服务器机房距离不同,导致了访问的延迟会明显不同的问题。

    what

    1. DNS服务器中配置一个域名对应多个IP地址。
    2. 每个IP地址对应到不同的机房里的虚拟IP。
    3. 当用户访问www.taobao.com时,DNS服务器会使用轮询策略或其他策略,来选择每个IP供用户访问。
    4. DNS轮询虚拟IP,可实现机房间的负载均衡,至此,系统可做到机房级别的水平扩展,千万级到亿级的并发量都可通过增加机房来解决,系统入口处的请求并发量不再是问题。

    why

    1. 一个域名可以配置多个IP地址。
    2. 单个虚拟IP地址对应的服务器集群,并发量会达到性能瓶颈。
    3. DNS轮询IP地址,可以达到多个机房的负载均衡。

    how

    1. 域名配置多个虚拟IP。
    2. DNS轮询域名下的多个ip,访问均匀分发到不同的ip。

    第九次演进:引入NoSQL数据库和搜索引擎等技术

    在这里插入图片描述

    目的

    业务场景复杂化(检索、分析等需求越来越丰富),普通关系型数据无法满足。

    what

    外部添加分方式文件系统、NoSQL数据库、搜索引擎等来解决复杂查询、全文检索等查询变慢,导致性能低的问题。

    why

    解决大数据查询变慢、复杂统计变慢、全文检索变慢等性能问题。

    how

    1. 对于海量文件存储,可通过分布式文件系统HDFS解决。
    2. 对于key value类型的数据可以通过HBase和Redis等方案解决。
    3. 对于全文检索场景,可通过搜索引擎ElasticSearch解决。
    4. 对于多维分析场景,可以通过Kylin或Druid等方案解决。

    引发的问题

    1. 组件增多导致系统复杂度变高,维护成本变高。
    2. 运维难度变大。
    3. 数据一致性问题。

    第十次演进:大应用拆分成小应用

    在这里插入图片描述

    目的

    解决应用太大,包含太大的业务,业务的升级迭代苦难,代码开发维护变难。

    what

    1. 按照业务板块来划分应用代码,使单个应用的职责更清晰。
    2. 业务之间可以独立升级迭代。

    why

    1. 解决代码开发、维护困难的问题。
    2. 解决升级迭代困难的问题。
    3. 每个业务可合理使用资源。

    how

    1. 按照业务功能维度划分应用。
    2. 使用分布式配置中心zookeeper解决公共配置的问题。

    引发的问题

    公共配置问题。

    第十一次演进:复用的功能抽离成微服务

    在这里插入图片描述

    目的

    解决公共服务模块,由应用单独管理导致相同代码存在多份的问题,导致公共功能升级,所有的应用都得升级,比如升级支付,导致所有和支付相关的业务都得升级。

    what

    如果用户管理、订单、支付、鉴权等功能在多个应用中都存在,那么可以把这些功能的代码单独抽取出来形成一个单独的服务来管理,这样的服务就是微服务,应用和服务间通过HTTP、TCP或者RPC请求等多种方式来访问公共的服务,每个单独的服务都可以由单独的团队来管理。

    why

    1. 解决多个应用维护多份公共功能的代码。
    2. 解决单个应用代码复杂度高的问题。
    3. 微服务独立迭代,提高整体工作效率。

    how

    1. 使用微服务架构。
    2. 使用Dubbo、SpringCloud等框架实现服务治理、限流、熔断、降级等功能,提高服务的稳定性和可用性。

    引入的问题

    服务注册发现、治理、限流、熔断、降级等。

    第十二次演进:引入企业服务总线ESB屏蔽服务接口的访问差异

    在这里插入图片描述

    目的

    通过ESB统一进行访问协议转换,应用统一通过ESB来访问后端服务,服务于服务之间也通过可以通过ESB来相互调用,以此降低系统的耦合度。

    场景

    比如目前的商品系统需要去访问物流中包裹的位置,但是包裹位置模块提供的服务是socket服务,我们的商品使用的是http调用方式,这个时候就可以通过加一个ESB模块来完成http协议与socket协议之间的转换。

    引入的问题

    1. 多个服务部署在单个环境上运行环境冲突的问题。
    2. 大促获得需要动态扩缩的问题。

    第十三次演进:引人容器化技术实现运行环境隔离与动态服务管理

    在这里插入图片描述

    目的

    1. 解决动态扩缩容的场景。
    2. 简化部署和运维。

    what

    1. 目前最流行的容器化技术是Docker,最流行的容器管理服务是Kubernets(K8S),应用/服务可以打包为Docker镜像,通过K8S来动态分发和部署镜像。
    2. Docker镜像可理解为一个能运行你应用/服务最小的操作系统,里面放着应用/服务的运行代码,运行环境根据实际的需要设置好。
    3. 把整个“操作系统”打包成一个镜像后,就可以分发到需要部署相关服务的机器上,直接启动Docker镜像就可以把服务运行起来,使服务的部署和运维变得简单。

    why

    1. 无需在服务器上配置运行环境。
    2. docker镜像打包好,在服务器上启动就好,方便扩缩容(针对大促场景)。

    how

    在大促之前,可以在现有的机器集群上划分出服务器来启动Docker镜像,增强服务的性能,大促过后就可以关闭镜像,对集群上的其他服务不会造成影响。

    第十四次演进:以云平台承载系统

    在这里插入图片描述

    目的

    解决资源利用率低的问题:容器化技术可以解决动态扩缩问题,但是机器还需要公司自身来管理,在非大促的时候,会闲置着大量的机器资源来应对大促,机器自身成本和运维成本都极高,资源利用率低。

    what

    1. 云平台就是海量机器资源,通过统一的资源管理,抽象为一个整体,在之上可安心动态申请硬件资源(CPU、内存、网络等),并且之上提供统一的操作系统,提供常用的技术组件(如Hadoop技术栈,MPP数据库等)供用户使用,甚至提供开发好的应用。
    2. IaaS
      基础设施即服务:对于于机器资源统一为资源整体,可动态申请硬件资源的层面。
    3. PaaS
      平台即服务:对应于提供常用的技术组件方案系统的开发和维护。
    4. SaaS
      软件即服务:对应于提供开发好的应用或服务,按功能或性能要求付费。

    why

    1. 可以在云平台临时申请更多的资源,结合Docker和K8S来快速部署服务,在大促结束后释放资源,真正做到按需付费,资源利用率大大提高。
    2. 提高资源利用率.

    how

    系统可部署在公有云上,利用公有云的海量机器资源,解决动态硬件资源的问题。

    总结

    设计原则

    N+1设计

    what

    系统中每个组件都应做到没有单点故障。

    why

    保证每个组件高可用。

    回滚设计

    what

    系统升级时出现错误可用即时回滚到之前的版本。

    why

    确保系统可用向前兼容。

    how

    1. 功能层面考虑向前兼容。
    2. 脚本层面设计成可回滚的。

    禁用设计

    what

    提供控制具体功能十分可用的配置,在系统出现故障时能够快速下线功能。

    why

    1. 保证系统可用性,即使止损。
    2. 兼容之前的版本。

    how

    配置为新功能配置开启开关,开关可动态配置。

    监控设计

    what

    监控功能相关指标,信息。

    why

    即时发现问题,分析问题,解决问题。

    how

    设计阶段就应该考虑如何监控。

    case

    1. 运行时日志打印。
    2. 大盘监控。

    多活数据中心设计

    what

    在多个地区建立数据中心,保证在一个机房断电的情况下系统依然可用。

    why

    保证系统异常情况下高可用。

    采用成熟的技术

    what

    使用目前市场上成熟的解决方案。

    why

    刚开服或者开源的技术往往存在很多隐藏的bug,出了问题没有商业支持可能会是一个灾难。

    资源隔离

    what

    为单个业务划分一定的资源,避免单个业务占用系统的全部资源。

    why

    避免业务间相互影响,导致其他业务服务不可用。

    how

    可以使用docker容器技术进行资源隔离。

    架构能水平扩展

    what

    系统中各个组件,包括整个系统可以线性的增加。

    why

    系统只有做到水平扩展才能有效避免性能瓶颈问题。

    非核心则购买

    what

    非核心的功能可以付费购买三方提供的服务。

    why

    非核心功能如需要占用大量的研发资源才能解决,则考虑购买成熟的产品。

    使用商用硬件

    why

    1. 商用硬件能有效降低硬件故障的几率。
    2. 遇到问题可以得到及时的商业技术支持。

    快速迭代

    what

    系统应该开发小功能模块,尽快上线进行验证,早日发现问题大大降低系统交付的风险。

    why

    降低交付风险。

    how

    开发小功能模式,尽快上线验证。

    无状态设计

    what

    服务接口应该是不记录状态的,当前接口的访问不依赖于接口上次的访问状态。

    why

    避免异常情况导致的状态出错,出现服务调用失败或错误的问题。

    how

    如果需要记录状态,把状态数据放到数据库等持久性组件中,接口查询判断。

    参考

    https://www.sohu.com/a/318174553_120160554

    展开全文
  • spark shuffle演进

    2020-12-11 15:20:23
    在 Spark 或 MapReduce 分布式计算框架中,数据被分成一块一块的分区,分布在集群中各节点上,每个计算任务一次处理一个分区,当需要对具有某种共同特征的一类数据进行计算时,就需要将集群中的这类数据汇聚到同一...

    1.Shuffle定义

    Spark MapReduce 分布式计算框架中,数据被分成一块一块的分区,分布在集群中各节点上,每个计算任务一次处理一个分区,当需要对具有某种共同特征的一类数据进行计算时,就需要将集群中的这类数据汇聚到同一节点。这个按照一定的规则对数据重新分区的过程就是Shuffle


    2.Spark Shuffle的两个阶段

    SparkShuffle分为Write和Read两个阶段,分属于两个不同的Stage,前者是Parent Stage的最后一步,后者是Child Stage的第一步。
    Stage的划分在spark yarn 提交流程中已经了解到分为ResultStage和ShuffleMapStage。
    Spark Shuffle 的流程简单抽象为以下几步:
    Shuffle Write
        Map Side combine(if needed)
        Write to local output file
    Shuffle Read
       Block fetch
       Reduce side combine
       Sort(if needed)

    3.Spark Shuffle 技术演进

    1. Spark 1.1 以前是Hash Shuffle
    2. Spark 1.1 引入了Sort Shuffle
    3. Spark 1.6 Tungsten-sort并入Sort Shuffle(利用对外内存进行排序)
    4. Spark 2.0 Hash Shuffle退出历史舞台

    3.1 Hash Shuffle V1 

    相对于传统的 MapReduceSpark 假定大多数情况下 Shuffle 的数据不需要排序,强制排序反而会降低性能。因此不在 Shuffle Read 时做 Merge Sort,如果需要合并的操作的话,则会使用聚合(agggregator),即用了一个 HashMap (实际上是一个 AppendOnlyMap)来将数据进行合并。
    Map Task 过程按照 Hash 的方式重组 Partition 的数据,不进行排序。每个 Map Task 为每个 Reduce Task 生成一个文件,通常会产生大量的文件(即对应为 M*R 个中间文件,其中 M 表示 Map Task 个数,R 表示 Reduce Task 个数),伴随大量的随机磁盘 I/O 操作与大量的内存开销。
     
    Hash Shuffle V1两个严重问题:
    • 生成大量文件,占用文件描述符,同时引入 DiskObjectWriter 带来的 WriterHandler 的缓存也非常消耗内存
    • 如果在 Reduce Task 时需要合并操作的话,会把数据放在一个 HashMap 中进行合并,如果数据量较大,很容易引发 OOM

    3.2 Hash Base Shuffle V2 -- File Consolidation

    Hash Base Shuffle V2 核心思想:允许不同的task复用同一批磁盘文件,有效将多个task的磁盘文件进行一定程度上的合并,从而大幅度减少磁盘文件的数量,进而提升shuffle write的性能。一个 Executor 上所有的 Map Task 生成的分区文件只有一份,即将所有的 MapTask 相同的分区文件合并,这样每个 Executor 上最多只生成 N 个分区文件。

     
     
    Hash Shuffle 规避了排序,提高了性能;总的来说在Hash Shuffle过程中生成海量的小文件(Hash Base Shuffle V2生成海量小文件的问题得到了一定程度的缓解)。这样减少了文件数,但是假如下游 Stage 分区数 N 很大,还是会在每个 Executor上生成 N 个文件,同样,如果一个 Executor 上有 K 个 Core,还是会开 K*NWriter Handler,这里仍然容易导致OOM
     


    3.3、Sort Base Shuffle V1

    每个 Task 不会为后续的每个Task 创建单独的文件,而是将所有对结果写入同一个文件。该文件中的记录首先是按照 Partition Id 排序,每个 Partition 内部再按照Key 进行排序,Map Task 运行期间会顺序写每个 Partition 的数据,同时生成一个索引文件记录每个 Partition 的大小和偏移
    Reduce 阶段,Reduce Task 拉取数据做 Combine 时不再采用 HashMap,而是采用ExternalAppendOnlyMap,该数据结构在做 Combine 时,如果内存不足,会刷写磁盘,避免大数据情况下的 OOM。
    总体上看来 Sort Shuffle 解决了 Hash Shuffle 的所有弊端,但是因为需要其 Shuffle过程需要对记录进行排序,所以在性能上有所损失。
    这里通过减少文件数来避免因为打开过多文件而导致的OOM,同时在reduce端引入磁盘溢写的方式来避免reduce Task的OOM
     
    Tungsten-Sort Based Shuffle / Unsafe Shuffle
    Spark 1.5.0 开始,Spark 开始了钨丝计划(Tungsten),目的是优化内存和CPU 的使用,进一步提升Spark的性能。由于使用了堆外内存,而它基于 JDK Sun Unsafe API,故 Tungsten-Sort Based Shuffle 也被称为 Unsafe Shuffle。
    它的做法是将数据记录用二进制的方式存储,直接在序列化的二进制数据上 Sort 而不是在 Java 对象上,这样一方面可以减少内存的使用和 GC 的开销,另一方面避免 Shuffle 过程中频繁的序列化以及反序列化。在排序过程中,它提供 cache-efficient sorter,使用一个 8 bytes 的指针,把排序转化成了一个指针数组的排序,极大的优化了排序性能。
    但是使用 Tungsten-Sort Based Shuffle 有几个限制Shuffle 阶段不能有 aggregate 操作,分区数不能超过一定大小(2^24-1,这是可编码的最大 Parition Id),所以像 reduceByKey 这类有 aggregate 操作的算子是不能使用 Tungsten-Sort Based Shuffle,它会退化采用 Sort Shuffle
     

    3.4 Sort Shuffle V2

    Spark1.6.0 开始,把 Sort Shuffle 和 Tungsten-Sort Based Shuffle 全部统一到Sort Shuffle 中,如果检测到满足 Tungsten-Sort Based Shuffle 条件会自动采用 Tungsten-Sort Based Shuffle,否则采用 Sort Shuffle。

    Spark2.0 开始,Spark 把 Hash Shuffle 移除, Spark2.x 中只有一种 Shuffle,即为 Sort Shuffle


    到此shuffle的演进就结束了 下面说说shuffle的细节。

    4.Shuffle Writer

    ShuffleWriter(抽象类),有3个具体的实现:
    SortShuffleWriter。
    sortShulleWriter 需要在 Map 排序
    UnsafeShuffleWriter。使用
    Java Unsafe 直接操作内存,避免Java对象多余的开销和GC 延迟,效率高
    BypassMergeSortShuffleWriter。和
    Hash Shuffle的实现基本相同,区别在于 map task输出汇总一个文件,同时还会产生一个index file

    以上 ShuffleWriter 有各自的应用场景。分别如下:

    • 不满足以下条件使用 SortShuffleWriter,保底方案
    • 没有map端聚合(groubykey没有map端的聚合),RDDpartitions分区数小于16,777,216,且 Serializer支持 relocationSerializer 可以对已经序列化的对象进行排序,这种排序起到的效果和先对数据排序再序列化一致】,使用UnsafeShuffleWriter
    • 没有map端聚合操作 且 RDDpartition分区数小于200个而且不是聚合类的shuffle算子,使用 BypassMergerSortShuffleWriter  

    Shuffle Writer 流程
    数据先写入一个内存数据结构中。不同的shuffle算子,可能选用不同的数据结构
         如果是 reduceByKey
    聚合类的算子,选用 Map 数据结构,一边通过 Map进行聚合,一边写入内存
         如果是
    join 类的 shuffle 算子,那么选用 Array 数据结构,直接写入内存
    检查是否达到内存阈值。每写一条数据进入内存数据结构之后,就会判断一下, 是否达到了某个临界阈值。如果达到临界阈值的话,那么就会将内存数据结构中的数据溢写到磁盘,并清空内存数据结构
    数据排序。在溢写到磁盘文件之前,会先根据key对内存数据结构中已有的数据进行排序。排序过后,会分批将数据写入磁盘文件。默认的batch数量是10000条,也就是说,排序好的数据,会以每批1万条数据的形式分批写入磁盘文件
    数据写入缓冲区。
    写入磁盘文件是通过Java的BufferedOutputStream 实现的。 BufferedOutputStream 是Java的缓冲输出流,首先会将数据缓冲在内存中,当内存缓冲满溢之后再一次写入磁盘文件中,这样可以减少磁盘IO次数,提升性能
    重复写多个临时文件。
    一个 Task 将所有数据写入内存数据结构的过程中,会发生多次磁盘溢写操作,会产生多个临时文件。
    临时文件合并。最后将所有的临时磁盘文件进行合并,这就是merge过程。此时会将之前所有临时磁盘文件中的数据读取出来,然后依次写入最终的磁盘文件之中。
    写索引文件。
    由于一个Task 就只对应一个磁盘文件,也就意味着该task为下游 stage的task准备的数据都在这一个文件中,因此还会单独写一份索引文件,其中标识了下游各个Task 的数据在文件中的 start offset 与 end offset

    5.Shuffle MapOutputTracker

    Sparkshuffle过程分为WriterReader:
    • Writer负责生成中间数据
    • Reader负责整合中间数据
    而中间数据的元信息,则由MapOutputTracker负责管理。 它负责Writer和Reader的沟通。Shuffle Writer会将中间数据保存到Block里面,然后将数据的位置发送给MapOutputTracker。 Shuffle Reader通过向 MapOutputTracker 获取中间数据的位置之后,才能读取到数据。
    Shuffle Reader
    需要提供 shuffleIdmapIdreduceId 才能确定一个中间数据:
    • shuffleId,表示此次shuffle的唯一id
    • mapId,表示map rdd 的分区索引,表示由哪个父分区产生的数据
    • reduceId,表示reduce端的分区索引,表示属于子分区的那部分数据

    MapOutputTrackerexecutordriver端都存在:

    1. MapOutputTrackerMaster MapOutputTrackerMasterEndpoint(负责通信) 存在于driver
    2. MapOutputTrackerWorker 存在于 executor
    3. MapOutputTrackerMaster 负责管理所有 shuffleMapTask 的输出数据,每个shuffleMapTask 执行完后会把执行结果(MapStatus对象)注册到 MapOutputTrackerMaster
    4. MapOutputTrackerMaster 会处理 executor 发送的 GetMapOutputStatuses请求,并返回serializedMapStatus executor 端​​​​​
    5. MapOutputTrackerWorker 负责为 reduce 任务提供 shuffleMapTask 的输出数据信息(MapStatus对象)
    6. 如果MapOutputTrackerWorker在本地没有找到请求的 shuffle 的mapStatus,则会向MapOutputTrackerMasterEndpoint 发送 GetMapOutputStatuses 请求获取对应的 mapStatus


    6.Shuffle Reader

    1. Map Task 执行完毕后会将文件位置、计算状态等信息封装到 MapStatus 对象中,再由本进程中的 MapOutPutTrackerWorker 对象将其发送给Driver进程的MapOutPutTrackerMaster对象
    2. Reduce Task开始执行之前会先让本进程中的 MapOutputTrackerWorker 向Driver 进程中的 MapOutputTrackerMaster 发动请求,获取磁盘文件位置等信息
    3. 当所有的Map Task执行完毕后,Driver进程中的 MapOutputTrackerMaster 就掌握了所有的Shuffle文件的信息。此时MapOutPutTrackerMaster会告诉MapOutPutTrackerWorker磁盘小文件的位置信息
    4. 完成之前的操作之后,由 BlockTransforService Executor 所在的节点拉数据,默认会启动五个子线程。每次拉取的数据量不能超过48M

    7.Hadoop Shuffle Spark Shuffle 的区别

    共同点:
    二者从功能上看是相似的;从High Level
    来看,没有本质区别,实现(细节)上有区别

    实现上的区别:
    • Hadoop中有一个Map完成,Reduce便可以去fetch数据了,不必等到所有Map任务完成;而Spark的必须等到父stage完成,也就是父stage map 操作全部 完成才能去fetch数据。这是因为spark必须等到父stage执行完,才能执行子 stage,主要是为了迎合stage规则。子stage需要从父stage的多个分区中拉取数据。
    • HadoopShuffle是sort-base的,那么不管是Map的输出,还是Reduce的输出,都是partition内有序的,而spark不要求这一点。
    • Hadoop的Reduce要等到fetch完全部数据,才将数据传入reduce函数进行聚合,而 Spark是一边fetch一边聚合

    8.Shuffle优化

    开发过程中对 Shuffle 的优化:

    • 减少Shuffle过程中的数据量
    • 避免Shuffle
    以下介绍 Shuffle 的优化主要是参数优化:
    优化一:调节
    map 端缓冲区大小
    • 合理设置参数,性能会有 1%~5% 的提升
    • spark.shuffle.file.buffer 默认值为32Kshuffle write阶段buffer缓冲大小。将数据写到磁盘文件之前,会先写入buffer缓冲区,缓冲写满后才溢写到磁盘。
    • 调节map端缓冲的大小,避免频繁的磁盘IO操作,进而提升任务整体性能
    优化二:调节 reduce 端拉取数据缓冲区大小
    • spark.reducer.maxSizeInFlight 默认值为48M。设置shuffle read阶段buffer缓冲区大小,这个buffer缓冲决定了每次能够拉取多少数据
    • 在内存资源充足的情况下,可适当增加参数的大小(如96m),减少拉取数据的次数及网络传输次数,进而提升性能
    • 合理设置参数,性能会有 1%~5% 的提升
    优化三:调节 reduce 端拉取数据重试次数及等待间隔
    • Shuffle read阶段拉取数据时,如果因为网络异常导致拉取失败,会自动进行重试
    • spark.shuffle.io.maxRetries 默认值3。最大重试次数
    • spark.shuffle.io.retryWait,默认值5s。每次重试拉取数据的等待间隔
    • 一般调高最大重试次数,不调整时间间隔
    优化四:调节 Sort Shuffle 排序操作阈值
     
    • 如果shuffle reduce task的数量小于阈值,则shuffle write过程中不会进行排序操作,而是直接按未经优化的Hash Shuffle方式写数据,最后将每个task产生的所有临时磁盘文件都合并成一个文件,并创建单独的索引文件
    • spark.shuffle.sort.bypassMergeThreshold,默认值为200
    • 当使用SortShuffleManager时,如果的确不需要排序操作,建议将这个参数调大
    优化五:调节 Shuffle 内存大小
    • Spark Shuffle 阶段分配了专门的内存区域,这部分内存称为执行内存
    • 如果内存充足,而且很少使用持久化操作,建议调高这个比例,给 shuffle 聚合操作更多内存,以避免由于内存不足导致聚合过程中频繁读写磁盘
    • 合理调节该参数可以将性能提升10%左右
     
     
     

     
     
     
     
     
    展开全文
  • Eclipse架构演进

    2020-11-09 11:24:10
    2010 年 6 月,Eclipse 基金会发布了 Helios 协调版本,来自 40 多家公司的 39 个项目和 490 名提交者共同合作,在基础平台的功能基础上进行开发。Eclipse最初的架构愿景是什么?它是如何发展的?应用的架构如何起到...

    Eclipse软件架构

    Kim Moir
    实现软件模块化是一项众所周知的艰巨任务。与由不同社区编写的庞大代码库的互操作性也很难管理。在Eclipse,我们在这两方面都取得了成功。2010 年 6 月,Eclipse 基金会发布了 Helios 协调版本,来自 40 多家公司的 39 个项目和 490 名提交者共同合作,在基础平台的功能基础上进行开发。Eclipse最初的架构愿景是什么?它是如何发展的?应用的架构如何起到鼓励社区参与和发展的作用?让我们回到最开始。
    2001年11月7日,一个名为Eclipse 1.0的开源项目发布。当时,Eclipse被描述为"一个综合开发环境(IDE),适用于任何事物,也适用于任何具体事物"。这种描述是故意通用的,因为其架构愿景不仅仅是另一套工具,而是一个框架;一个模块化和可扩展的框架。Eclipse提供了一个基于组件的平台,可以作为开发人员构建工具的基础。这种可扩展的架构鼓励社区在核心平台的基础上,将其扩展到最初愿景的极限之外。Eclipse以平台的形式开始,Eclipse SDK是概念验证产品。Eclipse SDK允许开发者自我托管并使用Eclipse SDK本身来构建较新版本的Eclipse。
    开放源码开发者的刻板印象是,一个利他主义者为了解决自己的个人利益,辛辛苦苦到深夜修复bug,实现奇妙的新功能。相反,如果你回顾Eclipse项目的早期历史,一些最初捐赠的代码是基于IBM开发的VisualAge for Java。第一批从事这个开源项目的提交者是IBM一家名为Object Technology International(OTI)的子公司的员工。这些投入者有偿全职参与这个开源项目,回答新闻组的问题,解决错误,实现新功能。一个由感兴趣的软件供应商组成的联盟成立了,以扩大这种开放工具的努力。Eclipse 联盟的最初成员是 Borland、IBM、Merant、QNX 软件系统公司、Rational 软件公司、RedHat、SuSE 和 TogetherSoft。
    通过对这一努力的投资,这些公司将拥有基于Eclipse的商业产品的专业知识。这类似于企业对Linux内核的投资,因为让员工改进作为其商业产品基础的开源软件符合他们的自身利益。2004年初,Eclipse基金会成立,以管理和扩大不断发展的Eclipse社区。这个非营利性的基金会由企业会员会费资助,并由董事会管理。今天,Eclipse社区的多样性已经扩大到包括170多家成员公司和近1 000名承诺者。
    最初,人们对"Eclipse"的认识仅仅是SDK,但如今它的意义远不止于此。2010年7月,eclipse.org上有250个不同的项目在开发。有支持用C/C++、PHP、Web服务、模型驱动开发、构建工具等开发的工具。每一个项目都包含在一个顶层项目(TLP)中,该项目由一个项目管理委员会(PMC)管理,该委员会由项目的资深成员提名,负责制定技术方向和发布目标。为了简洁起见,本章的范围将局限于Eclipse1和Runtime Equinox2项目中Eclipse SDK架构的演变。由于Eclipse有着悠久的历史,我将重点介绍早期的Eclipse,以及3.0、3.4和4.0版本。

    1. 早期的Eclipse
      在21世纪初,软件开发者的工具很多,但能一起工作的工具很少。Eclipse试图提供一个开源平台,为应用开发者创建可互操作的工具。这将允许开发人员专注于编写新的工具,而不是编写代码处理基础设施问题,如与文件系统交互,提供软件更新,并连接到源代码仓库。Eclipse最著名的可能是Java开发工具(JDT)。其意图是,这些模范的Java开发工具将成为有兴趣为其他语言提供工具的人的榜样。
      在深入了解Eclipse的架构之前,我们先来看看Eclipse SDK对开发者来说是什么样子的。启动Eclipse并选择工作台后,你会看到Java透视图。透视图组织了当前使用的工具所特有的视图和编辑器。
      在这里插入图片描述
    2. 图6.1:Java视角
      早期版本的Eclipse SDK架构有三大要素,对应着三大子项目:平台、JDT(Java开发工具)和PDE(插件开发环境)。
    3. 6.1.1. 平台
      Eclipse平台使用Java编写,运行它需要一个Java虚拟机。它是由称为插件的小功能单元构建的。插件是Eclipse组件模型的基础。插件本质上是一个JAR文件,它有一个manifest,该manifest描述了它本身、它的依赖关系以及它如何被利用或扩展。这个manifest信息最初存储在一个plug-in.xml文件中,它驻扎在插件目录的根目录下。Java开发工具提供了用Java开发的插件。插件开发环境(PDE)提供了开发插件以扩展Eclipse的工具。Eclipse插件是用Java编写的,但也可以包含非代码贡献,如在线文档的HTML文件。每个插件都有自己的类加载器。插件可以通过在plugin.xml中使用request语句来表达对其他插件的依赖。观察org.eclipse.ui插件的plugin.xml,可以看到它的名称和指定的版本,以及它需要从其他插件导入的依赖关系。
    <?xml version="1.0" encoding="UTF-8"?
    <plugin
       id="org.eclipse.ui"
       name="%Plugin.name"
       version="2.1.1"
       provider-name="%Plugin.providerName"
       class="org.eclipse.ui.Internal.UIPlugin">
       <runtime>
          <library name="ui.jar"><export name="*"/>
             <packages prefixes="org.eclipse.ui"/></library>
       </runtime>
       <requirements>
          <import plugin="org.apache.xerces"/><import plugin="org.eclipse.core.resources"/><import plugin="org.eclipse.update.core"/>。
          : :                :
          <import plugin="org.eclipse.text" export="true" /><import plugin="org.eclipse.ui.workbench.texteditor" export="true"/><import plugin="org.eclipse.ui.editors" export="true"/></requirements>
    </plugin>
    

    为了鼓励人们在Eclipse平台的基础上进行构建,需要有一种机制来为平台做出贡献,并让平台接受这种贡献。这是通过使用扩展和扩展点来实现的,扩展点是Eclipse组件模型的另一个元素。出口确定了你希望别人在编写他们的扩展时使用的接口,这就限制了你的插件之外的类可以使用到那些被导出的类。它还对插件外部可用的资源提供了额外的限制,而不是将所有公共方法或类都提供给消费者。导出的插件被认为是公共API。所有其他的都被认为是私有的实现细节。要编写一个能为Eclipse工具栏贡献菜单项的插件,可以使用org.eclipse.ui插件中的actionSets扩展点。

    <extension-point id="actionSets" name="%ExtPoint.actionSets"
                     schema="schema/actionSets.exsd"/>
    <extension-point id="command" name="%ExtPoint.command"
                     schema="schema/commands.exsd"/>
    <extension-point id="contexts" name="%ExtPoint.contexts"
                     schema="schema/contexts.exsd"/>
    <extension-point id="decorators" name="%ExtPoint.decorators"
                     schema="schema/decorators.exsd"/>
    <extension-point id="dropActions" name="%ExtPoint.dropActions"
                     schema="schemma/dropActions.exsd"/>

    你的插件扩展可以为org.eclipse.ui.actionSet扩展点贡献一个菜单项,它看起来像这样。

    <?xml version="1.0" encoding="UTF-8"?
    <plugin
       id="com.example.helloworld"
       name="com.example.helloworld"
       版本="1.0.0"><runtime>
          <library name="helloworld.jar"/></runtime>
       <requires>
          <import plugin="org.eclipse.ui"/></requires>
       <extension
             point="org.eclipse.ui.actionSets"><actionSet
                label="示例行动集"
                visible="true"
                id="org.eclipse.helloworld.actionSet"><menu
                   label="示例&菜单"
                   id="exampleMenu">
                <separator
                      name="exampleGroup">
                </separator>
             </menu>
             <action
                   label="&示例动作"
                   icon="icon/example.gif"
                   tooltip="你好,Eclipse世界"
                   class="com.example.helloworld.actions.ExampleAction"
                   menubarPath="exampleMenu/exampleGroup"
                   toolbarPath="exampleGroup"
                   id="org.eclipse.helloworld.actions.ExampleAction"></action>
          </actionSet>
       </extension>
    </plugin>
    

    当Eclipse启动时,运行时平台会扫描安装中插件的清单,并建立一个存储在内存中的插件注册表。扩展点和相应的扩展通过名称进行映射。产生的插件注册表可以从Eclipse平台提供的API中引用。该注册表被缓存到磁盘上,以便在下次重新启动Eclipse时可以重新加载这些信息。所有插件在启动时都会被发现以填充注册表,但在实际使用代码之前,它们不会被激活(加载类)。这种方法被称为"懒惰激活"。通过在需要之前不实际加载与插件相关的类,可以减少在安装中添加额外捆绑包对性能的影响。例如,贡献给org.eclipse.ui.actionSet扩展点的插件,在用户选择工具栏中的新菜单项之前不会被激活。
    在这里插入图片描述

    • 图 6.2: 菜单示例
      生成这个菜单项的代码是这样的。
    package com.example.helloworld.actions;
    
    import org.eclipse.jface.action.IAction;
    import org.eclipse.jface.viewers.ISelection;
    import org.eclipse.ui.IWorkbenchWindow;
    import org.eclipse.ui.IWorkbenchWindowActionDelegate;
    import org.eclipse.jface.dialogs.MessageDialog;
    
    public class ExampleAction implements IWorkbenchWindowActionDelegate {
        private IWorkbenchWindow window;
    
        public ExampleAction() {
        }
    
        public void run(IAction action) {
            MessageDialog.openInformation(
                window.getShell(),
                "org.eclipse.helloworld",
                "Hello, Eclipse architecture world");
        }
    
        public void selectionChanged(IAction action, ISelection selection) {
        }
    
        public void dispose() {
        }
    
        public void init(IWorkbenchWindow window) {
            this.window = window;
        }
    }
    

    一旦用户选择了工具栏中的新项目,扩展注册表就会被实现扩展点的插件查询。提供扩展点的插件实例化贡献,并加载插件。一旦插件被激活,我们例子中的ExampleAction构造函数就会被运行,然后初始化一个工作台动作委托。由于工作台中的选择已经发生了变化,并且已经创建了委托人,所以可以改变动作。打开消息对话框,显示"你好,Eclipse架构世界"。
    这种可扩展的架构是Eclipse生态系统成功发展的关键之一。公司或个人可以开发新的插件,并将其作为开放源码发布或进行商业销售。
    关于Eclipse最重要的一个概念是,一切都是插件。无论是Eclipse平台中包含的插件,还是你自己编写的插件,插件都是组装好的应用程序的一级组件。图6.3显示了Eclipse早期版本中插件所贡献的相关功能集群。
    在这里插入图片描述

    • 图6.3:早期的Eclipse架构
      工作台是Eclipse平台用户最熟悉的UI元素,因为它提供了组织Eclipse在桌面上如何显示给用户的结构。工作台由视角、视图和编辑器组成。编辑器与文件类型相关联,因此当打开一个文件时,就会启动正确的编辑器。视图的一个例子是"问题"视图,它指示Java代码中的错误或警告。编辑器和视图共同构成了一个视角,它以一种有组织的方式向用户展示工具。
      Eclipse工作平台是建立在标准Widget Toolkit(SWT)和JFace基础上的,SWT值得探讨一下。小工具工具箱一般分为原生的和仿真的两种。原生的widget工具包使用操作系统调用来构建用户界面组件,如列表和按钮。与组件的交互由操作系统处理。仿真的widget工具包在操作系统之外实现组件,自己处理鼠标和键盘、绘图、焦点和其他widget功能,而不是依赖操作系统。两种设计都有不同的优缺点。
      原生小部件工具包是"完美的像素"。它们的小部件的外观和感觉与桌面上其他应用程序中的对应物一样。操作系统供应商不断地改变他们的小组件的外观和感觉,并添加新的功能。原生小组件工具包可以免费获得这些更新。不幸的是,本地工具箱很难实现,因为它们的底层操作系统小部件实现有很大的不同,导致不一致和程序不可移植。
      仿真部件工具包要么提供自己的外观和感觉,要么试图像操作系统一样绘制和行为。它们比原生工具包的最大优势是灵活性(尽管现代原生小组件工具包如Windows Presentation Framework (WPF)也同样灵活)。因为实现小组件的代码是工具包的一部分,而不是嵌入到操作系统中,所以可以让小组件以任何方式绘制和行为。使用仿真小组件工具箱的程序具有高度的可移植性。早期的仿真小组件工具箱名声不佳。它们的速度通常很慢,而且在模拟操作系统方面做得很差,使得它们在桌面上显得格格不入。尤其是当时的Smalltalk-80程序,由于使用了仿真部件,很容易被识别。用户知道他们运行的是一个"Smalltalk程序",这影响了人们对Smalltalk应用程序的接受。
      与其他计算机语言(如C和C++)不同,Java的第一个版本带有一个本地的widget工具箱库,称为抽象窗口工具箱(AWT)。AWT被认为是有限的、错误的和不一致的,受到了广泛的谴责。在Sun公司和其他地方,部分原因是由于使用AWT的经验,一个可移植的、高性能的原生widget工具包被认为是不可行的。解决办法是Swing,一个功能齐全的仿真部件工具包。
      1999年左右,OTI使用Java实现了一个名为VisualAge Micro Edition的产品。VisualAge Micro Edition的第一个版本使用了Swing,而OTI使用Swing的经验并不乐观。早期版本的Swing存在bug,有定时和内存问题,而且当时的硬件功能不够强大,无法提供可接受的性能。OTI曾成功地为Smalltalk-80和其他Smalltalk实现构建了一个本地widget工具包,以获得Smalltalk的认可。这个经验被用来构建SWT的第一个版本。VisualAge Micro Edition和SWT获得了成功,当Eclipse的工作开始时,SWT自然而然地成为了选择。在Eclipse中使用SWT而不是Swing,这在Java社区中引起了分裂。有些人认为是阴谋,但Eclipse是成功的,SWT的使用使它与其他Java程序区别开来。Eclipse性能卓越,像素完美,人们普遍的感受是,“我不敢相信这是一个Java程序”。
      早期的Eclipse SDK在Linux和Windows上运行。在2010年,已经支持了十多个平台。开发者可以为一个平台编写应用程序,并将其部署到多个平台上。为Java开发一个新的widget工具包在当时的Java社区内是一个有争议的问题,但Eclipse的提交者认为,为了在桌面上提供最好的原生体验,这是值得的。这一论断在今天依然适用,有数百万行代码依赖于SWT。
      JFace是SWT之上的一个层,它为常见的UI编程任务提供了工具,例如偏好和向导的框架。像SWT一样,它被设计成可以与许多窗口系统一起工作。然而,它是纯Java代码,不包含任何本地平台代码。
      该平台还提供了一个基于称为主题的小信息单位的综合帮助系统。一个主题由一个标签和对其位置的引用组成。这个位置可以是一个HTML文档文件,也可以是一个描述附加链接的XML文档。主题以目录(TOC)的形式分组。将主题视为树叶,将TOC视为组织的分支。要在你的应用程序中添加帮助内容,你可以向org.eclipse.help.toc扩展点做出贡献,就像下面org.eclipse.platform.doc.isv plugin.xml所做的那样。
    <?xml version="1.0" encoding="UTF-8"?>
    <?eclipse version="3.0"?>
    <plugin>
    
    <!-- ===================================================================== -->
    <!-- Define primary TOC                                                    -->
    <!-- ===================================================================== -->
       <extension
             point="org.eclipse.help.toc">
          <toc
                file="toc.xml"
                primary="true">
          </toc>
          <index path="index"/>
       </extension>
    <!-- ===================================================================== -->
    <!-- Define TOCs                                                           -->
    <!-- ===================================================================== -->
       <extension
             point="org.eclipse.help.toc">
          <toc
                file="topics_Guide.xml">
          </toc>
          <toc
                file="topics_Reference.xml">
          </toc>
          <toc
                file="topics_Porting.xml">
          </toc>
          <toc
                file="topics_Questions.xml">
          </toc>
          <toc
                file="topics_Samples.xml">
          </toc>
       </extension>
    

    Apache Lucene 被用来索引和搜索在线帮助内容。在Eclipse的早期版本中,在线帮助是作为Tomcat Web应用程序提供的。此外,通过在Eclipse本身内部提供帮助,也可以使用帮助插件的子集来提供独立的帮助服务器。3
    Eclipse还提供了团队支持,以与源代码库进行交互,创建补丁和其他常见任务。工作空间提供了文件和元数据的集合,将你的工作存储在文件系统中。还有一个调试器来跟踪Java代码中的问题,以及一个构建特定语言调试器的框架。
    Eclipse项目的目标之一是鼓励该技术的开源和商业消费者扩展该平台以满足他们的需求,而鼓励这种采用的方法之一是提供一个稳定的API。一个API可以被认为是一个技术合同,规定了你的应用程序的行为。它也可以被认为是一种社会契约。在Eclipse项目中,口号是"API是永远的"。因此,鉴于API是要无限期使用的,在编写API时必须仔细考虑。一个稳定的API是客户端或API消费者与提供者之间的合同。这种合同确保了客户端可以长期依赖Eclipse平台提供API,而不需要客户端进行痛苦的重构。一个好的API也是足够灵活的,可以让实现不断发展。

    1. 6.1.2.Java开发工具(JDT)
      JDT提供了Java编辑器、向导、重构支持、调试器、编译器和增量构建器。编译器还用于内容辅助、导航和其他编辑功能。Eclipse中并没有附带Java SDK,所以由用户自己选择在桌面上安装哪个SDK。为什么JDT团队要单独编写一个编译器来在Eclipse中编译你们的Java代码?他们有一个最初的编译器代码贡献,来自VisualAge Micro Edition。他们计划在编译器之上构建工具,因此自己编写编译器是一个合理的决定。这种方法也允许JDT提交者提供扩展点来扩展编译器。如果编译器是由第三方提供的命令行应用程序,这将是困难的。
      编写自己的编译器提供了一种机制,在集成开发环境中为增量构建器提供支持。增量构建器提供了更好的性能,因为它只重新编译已经改变的文件或其依赖关系。增量构建器是如何工作的?当您在Eclipse中创建一个Java项目时,您是在工作区中创建资源来存储您的文件。Eclipse内的构建器在你的工作空间内接收输入(.java文件),并创建一个输出(.class文件)。通过构建状态,构建器知道工作空间中的类型(类或接口),以及它们如何相互引用。每次编译源文件时,编译器都会向构建器提供构建状态。当调用增量构建时,构建器会得到一个资源delta,它描述了任何新的、修改的或删除的文件。删除的源文件会删除其对应的类文件。新的或修改的类型被添加到队列中。队列中的文件按顺序编译,并与旧的类文件进行比较,以确定是否有结构性变化。结构性改变是对类的修改,会影响到引用它的另一个类型。例如,改变方法签名,或者添加或删除一个方法。如果有结构变化,所有引用它的类型也会被添加到队列中。如果类型有任何改变,新的类文件会被写入构建输出文件夹。构建状态会随着编译类型的引用信息而更新。这个过程对队列中的所有类型重复进行,直到空为止。如果有编译错误,Java编辑器会创建问题标记。多年来,随着Java运行时本身的新版本,JDT提供的工具已经得到了极大的扩展。
    2. 6.1.3.插件式开发环境(PDE)
      插件开发环境(PDE)提供了开发、构建、部署和测试插件以及其他用于扩展Eclipse功能的工件的工具。由于Eclipse插件在Java世界中是一种新的工件类型,所以没有一个构建系统可以将源代码转化为插件。因此,PDE团队编写了一个名为PDE Build的组件,它可以检查插件的依赖关系,并生成Ant脚本来构建构建工件。
    3. 6.2.Eclipse 3.0。运行时、RCP和机器人
    4. 6.2.1.运行时
      Eclipse 3.0可能是最重要的Eclipse版本之一,因为在这个发布周期中发生了许多重大变化。在3.0之前的Eclipse架构中,Eclipse组件模型由插件组成,这些插件可以通过两种方式相互交互。首先,它们可以通过使用插件.xml中的request语句来表达它们的依赖关系。如果插件A需要插件B,插件A就可以看到B的所有Java类和资源,尊重Java类的可见性约定。每个插件都有一个版本,他们也可以指定其依赖的版本。其次,组件模型提供了扩展和扩展点。历史上,Eclipse提交者为Eclipse SDK编写了自己的运行时来管理类加载、插件依赖和扩展及扩展点。
      Equinox项目是作为Eclipse的一个新的孵化器项目创建的。Equinox项目的目标是用现有的Eclipse组件模型取代Eclipse组件模型,并为动态插件提供支持。正在考虑的解决方案包括JMX、Jakarta Avalon和OSGi。JMX不是一个完全开发的组件模型,所以被认为不合适。没有选择Jakarta Avalon是因为它作为一个项目似乎正在失去动力。除了技术要求之外,考虑支持这些技术的社区也很重要。他们是否愿意加入Eclipse特有的变化?是否积极开发并获得新的采用者?Equinox团队认为,围绕他们最终选择的技术的社区与技术考虑同样重要。
      在研究和评估了现有的备选方案后,提交人选择了OSGi。为什么选择OSGi?它有一个语义版本管理方案来管理依赖关系,它提供了JDK本身所缺乏的模块化框架。它提供了一个JDK本身所缺乏的模块化框架。对其他捆绑包可用的包必须显式导出,而所有其他的包都是隐藏的。OSGi提供了自己的类加载器,因此Equinox团队不必继续维护自己的类。通过标准化一个在Eclipse生态系统之外有更广泛采用的组件模型,他们认为他们可以吸引更广泛的社区,并进一步推动Eclipse的采用。
      Equinox团队认为,由于OSGi已经有了一个现有的、充满活力的社区,他们可以与该社区合作,帮助将Eclipse所需的功能包含在组件模型中。例如,当时OSGi只支持在包级别上列出需求,而不是Eclipse所要求的插件级别。此外,OSGi还没有包含片段的概念,片段是Eclipse为现有插件提供平台或环境特定代码的首选机制。例如,片段提供了与Linux和Windows文件系统一起工作的代码,以及贡献语言翻译的片段。一旦决定使用OSGi作为新的运行时,提交者需要一个开源的框架实现。他们评估了Oscar,Apache Felix的前身,以及IBM开发的服务管理框架(SMF)。当时,Oscar是一个研究项目,部署有限。SMF最终被选中,因为它已经被用于航运产品,因此被认为是企业级的。Equinox的实现作为OSGi规范的参考实现。
      还提供了一个兼容层,以便现有的插件在3.0的安装中仍然可以使用。要求开发人员重写他们的插件以适应Eclipse 3.0基础架构的变化,会使Eclipse作为一个工具平台的势头停滞不前。Eclipse消费者的期望是,这个平台应该继续工作。
      随着向 OSGi 的转换,Eclipse 插件被称为 bundle。插件和bundle是一样的:它们都提供了一个模块化的功能子集,在manifest中用元数据描述自己。以前,依赖关系、导出的包以及扩展和扩展点都是在plugin.xml中描述的。随着转向OSGi bundles,扩展和扩展点继续在plugin.xml中描述,因为它们是Eclipse的概念。其余的信息则在META-INF/MANIFEST.MF中描述,这是OSGi的捆绑清单版本。为了支持这一变化,PDE在Eclipse中提供了一个新的清单编辑器。每个bundle都有一个名称和版本。org.eclipse.ui bundle的manifest是这样的。
    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2
    Bundle-Name:%Plugin.name
    Bundle-SymbolicName: org.eclipse.ui; singleton:=true。
    Bundle-Version: 3.3.0.qualifier.
    Bundle-ClassPath: .
    Bundle-Activator: org.eclipse.ui.internal.UIPlugin。
    Bundle-Vendor: %Plugin.providerName.
    捆绑-本地化:插件
    Export-Package: org.eclipse.ui.internal;x-internal:=true。
    Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.2.0,4.0.0)"。
    org.eclipse.swt;bundle-version="[3.3.0,4.0.0)";可见性:=reexport。
    org.eclipse.jface;bundle-version="[3.3.0,4.0.0)";可见性:=reexport。
    org.eclipse.ui.workbench;bundle-version="[3.3.0,4.0.0)";visibility:=reexport.bundle-version="[3.3.0,4.0.0)"。
    org.eclipse.core.expressions;bundle-version="[3.3.0,4.0.0)"
    Eclipse-LazyStart: true
    Bundle-RequiredExecutionEnvironment:CDC-1.0/Foundation-1.0, J2SE-1.3
    

    从Eclipse 3.1开始,清单还可以指定 bundle所需的执行环境(BREE)。执行环境指定了 bundle 运行所需的最小 Java 环境。Java编译器不理解捆绑包和OSGi清单。PDE提供了开发OSGi bundle的工具。因此,PDE 会解析 bundle 的清单,并为该 bundle 生成 classpath。如果你在manifest中指定了J2SE-1.4的执行环境,然后写了一些包含generics的代码,你会被告知你的代码中存在编译错误。这可以确保你的代码遵守你在清单中指定的合同。
    OSGi为Java提供了一个模块化框架。OSGi框架管理自描述捆绑的集合,并管理它们的类加载。每个捆绑包都有自己的类加载器。捆绑包可用的classpath是通过检查manifest的依赖关系来构造的,并生成捆绑包可用的classpath。OSGi应用程序是捆绑的集合。为了充分拥抱模块化,你必须能够以可靠的格式为消费者表达你的依赖关系。因此,manifest描述的是这个bundle的客户端可用的导出包,它对应的是可供消费的公共API。正在消费该API的捆绑包必须有一个对应的他们正在消费的包的导入。manifest还允许你表达你的依赖的版本范围。看上面清单中的Require-Bundle标题,你会注意到org.eclipse.core.runtime bundle所依赖的org.eclipse.ui必须至少是3.2.0,小于4.0.0。
    OSGi Bundle Lifecycle

    • 图 6.4:OSGi Bundle Lifecycle
      OSGi是一个动态框架,它支持安装、启动、停止或卸载捆绑包。如前所述,懒惰激活是Eclipse的核心优势,因为插件类在需要之前不会被加载。OSGi bundle生命周期也实现了这种方法。当你启动一个OSGi应用时,捆绑包处于安装状态。如果它的依赖性得到满足,该捆绑就会变为解析状态。一旦解决,该捆绑中的类就可以被加载和运行。启动状态意味着该 bundle 正在根据其激活策略被激活。一旦激活,该捆绑处于激活状态,它就可以获取所需的资源并与其他捆绑进行交互。当一个捆绑正在执行它的激活器停止方法,以清理它在激活时打开的任何资源时,它就处于停止状态。最后,一个bundle可以被卸载,这意味着它不能使用。
      随着API的发展,需要有一种方法来向您的消费者发出变化信号。其中一种方法是在您的清单中使用捆绑包和版本范围的语义版本化来指定依赖关系的版本范围。OSGi使用了一个四部分的版本命名方案,如图6.5所示。
      在这里插入图片描述
    • 图6.5:版本命名方案
      在OSGi版本编号方案中,每个捆绑包都有一个由名称和四部分版本号组成的唯一标识符。一个id和版本号一起对消费者来说表示了一组独特的字节。按照Eclipse的惯例,如果你要对一个bundle进行修改,版本号的每一段都向消费者表示所做的修改类型。因此,如果你想表明你打算打破API,你会递增第一个(主要)段。如果你刚刚添加了API,你就递增第二个(小)段。如果你修复了一个不影响API的小bug,则递增第三个(服务)段。最后,第四段或限定段递增,表示构建id源控制仓库标签。
      除了表达捆绑之间的固定依赖关系外,OSGi内部还有一种机制叫做服务,它提供了捆绑之间的进一步解耦。服务是具有一组属性的对象,这些属性在OSGi服务注册表中注册。与Eclipse在启动过程中扫描捆绑时在扩展注册表中注册的扩展不同,服务是动态注册的。正在消费服务的捆绑包需要导入定义服务合同的包,框架从服务注册表中确定服务的实现。
      就像Java类文件中的主方法一样,有一个特定的应用程序定义来启动Eclipse。Eclipse应用程序是用扩展名来定义的。例如,启动Eclipse IDE本身的应用程序是org.eclipse.ui.ide.workbench,它定义在org.eclipse.ui.ide.application bundle中。
    <plugin>
        <extension
             id="org.eclipse.ui.ide.workbench"
             point="org.eclipse.core.runtime.applications">
          <application>
             <run
                   class="org.eclipse.ui.internal.ide.application.IDEApplication">
             </run>
          </application>
      </extension>
    </plugin>
    

    Eclipse提供了许多应用程序,如运行独立的帮助服务器、Ant任务和JUnit测试的应用程序。

    • 6.2.2.富客户端平台(RCP)
      在开源社区工作最有趣的事情之一是,人们以完全意想不到的方式使用软件。Eclipse的初衷是提供一个平台和工具来创建和扩展IDE。然而,在3.0发布之前的一段时间里,bug报告显示,社区正在使用平台捆绑的子集,并使用它们来构建富客户端平台(RCP)应用程序,许多人都会将其识别为Java应用程序。由于Eclipse最初是以IDE为中心构建的,因此必须对捆绑包进行一些重构,以使这种用例更容易被用户社区采用。RCP应用程序并不需要IDE中的所有功能,所以几个捆绑包被拆分成了更小的捆绑包,可以被社区用于构建RCP应用程序。
      RCP在野外应用的例子包括:美国航天局在喷气推进实验室使用RCP监测火星车机器人,Bioclipse用于生物信息学的数据可视化,荷兰铁路公司用于监测火车性能。贯穿这些应用的共同点是,这些团队决定可以利用RCP平台提供的实用性,并集中精力在其上构建自己的专用工具。他们可以通过专注于在一个具有稳定API的平台上构建他们的工具来节省开发时间和资金,以保证他们的技术选择能够得到长期的支持。
      在这里插入图片描述
    • 图6.6: Eclipse 3.0架构
      从图6.6的3.0架构来看,你会注意到Eclipse Runtime仍然存在,以提供应用模型和扩展注册表。管理组件之间的依赖关系,插件模型现在由OSGi管理。除了继续能够为自己的IDE扩展Eclipse之外,消费者还可以在RCP应用框架的基础上建立更通用的应用。
    • 6.3.Eclipse 3.4
      轻松地将应用程序更新到新版本并添加新内容的能力是理所当然的。在Firefox中,它可以无缝地发生。对于Eclipse来说,它并不那么容易。更新管理器是最初的机制,用于在Eclipse安装中添加新内容或更新到新版本。
      要了解更新或安装操作过程中的变化,有必要了解Eclipse所说的"特性"是什么意思。特性是一个PDE构件,它定义了一组捆绑包,这些捆绑包以一种可以构建或安装的格式打包在一起。特性也可以包括其他特性。(见图 6.7)。
      在这里插入图片描述
    • 图6.7.Eclipse 3.3 SDK功能层次结构图
      如果你希望更新你的Eclipse安装到一个只包含一个新捆绑包的新版本,那么整个功能都必须更新,因为这是更新管理器使用的粗粒度机制。更新一个功能来修复一个捆绑包是低效的。
      有PDE向导来创建功能,并在你的工作空间中构建它们。feature.xml文件定义了包含在特性中的捆绑包,以及捆绑包的一些简单属性。一个特性,就像一个捆绑包,有一个名称和一个版本。特性可以包含其他特性,并为它们包含的特性指定版本范围。一个特性中包含的捆绑包,以及特定的属性都会被列出。例如,你可以看到org.eclipse.launcher.gtk.linux.x86_64片段指定了它应该使用的操作系统(os)、窗口系统(ws)和架构(arch)。因此升级到新版本时,这个片段将只安装在这个平台上。这些平台过滤器包含在这个捆绑包的OSGi清单中。
    <?xml version="1.0" encoding="UTF-8"?>
    <feature
          id="org.eclipse.rcp"
          label="%featureName"
          version="3.7.0.qualifier"
          provider-name="%providerName"
          plugin="org.eclipse.rcp"
          image="eclipse_update_120.jpg">
    
       <description>
          %description
       </description>
    
       <copyright>
          %copyright
       </copyright>
    
       <license url="%licenseURL">
          %license
       </license>
    
       <plugin
             id="org.eclipse.equinox.launcher"
             download-size="0"
             install-size="0"
             version="0.0.0"
             unpack="false"/>
    
       <plugin
             id="org.eclipse.equinox.launcher.gtk.linux.x86_64"
             os="linux"
             ws="gtk"
             arch="x86_64"
             download-size="0"
             install-size="0"
             version="0.0.0"
             fragment="true"/>
    

    一个Eclipse应用程序不仅仅由功能和捆绑包组成。有启动Eclipse本身的特定平台可执行文件、许可证文件和特定平台的库,如这个Eclipse应用程序中包含的文件列表所示。

    com.ibm.icu
    org.eclipse.core.commands
    org.eclipse.core.conttenttype
    org.eclipse.core.databinding
    org.eclipse.core.databinding.beans
    org.eclipse.core.expressions
    org.eclipse.core.jobs
    org.eclipse.core.runtime
    org.eclipse.core.runtime.compatibility.auth
    org.eclipse.equinox.common
    org.eclipse.equinox.launcher
    org.eclipse.equinox.launcher.carbon.macosx
    org.eclipse.equinox.launcher.gtk.linux.ppc
    org.eclipse.equinox.launcher.gtk.linux.s390
    org.eclipse.equinox.launcher.gtk.linux.s390x
    org.eclipse.equinox.launcher.gtk.linux.x86
    org.eclipse.equinox.launcher.gtk.linux.x86_64
    

    这些文件不能通过更新管理器更新,因为它只处理功能。由于这些文件中的许多文件在每一个主要的版本都会更新,这意味着每次有新的版本发布时,用户都必须下载一个新的压缩包,而不是更新他们现有的安装。这对Eclipse社区来说是不可接受的。PDE提供了对产品文件的支持,它指定了构建Eclipse RCP应用程序所需的所有文件。然而,更新管理器并没有一个机制来提供这些文件到你的安装中,这对用户和产品开发者来说都是非常令人沮丧的。2008年3月,p2作为新的供应解决方案被发布到SDK中。为了向后兼容,Update Manager仍然可以使用,但p2是默认启用的。

    • 6.3.1. p2概念
      Equinox p2是关于安装单元(IU)的。IU是对你要安装的工件的名称和ID的描述。这个元数据也描述了工件的能力(提供了什么)和需求(它的依赖性)。元数据还可以表达适用性过滤器,如果一个工件只适用于特定的环境。例如,org.eclipse.swt.gtk.linux.x86片段只有在Linux gtk x86机器上安装时才适用。从根本上说,元数据是捆绑清单中信息的表达。人造物只是被安装的二进制位。通过分离元数据和它们所描述的工件来实现关注点的分离。一个p2资源库由元数据和工件资源库组成。
      在这里插入图片描述

    • 图6.8:P2概念
      配置文件是您安装中的 IU 列表。例如,您的 Eclipse SDK 有一个描述您当前安装的 profile。在 Eclipse 中,您可以请求更新到较新版本的构建,这将创建一个具有不同 IU 集的新配置文件。配置文件还提供了与安装相关的属性列表,例如操作系统、窗口系统和架构参数。配置文件还存储了安装目录和位置。配置文件由一个配置文件注册表持有,该注册表可以存储多个配置文件。导演负责调用供应操作。它与规划师和引擎一起工作。规划师检查现有的配置文件,并确定将安装转化为新状态所必须进行的操作。引擎负责执行实际的供应操作,并将新工件安装到磁盘上。触点是引擎的一部分,与被安装系统的运行时实现一起工作。例如,对于Eclipse SDK,有一个Eclipse接触点,它知道如何安装捆绑包。对于从RPM二进制文件中安装Eclipse的Linux系统,引擎会处理一个RPM接触点。此外,p2还可以在进程内或进程外的单独进程中执行安装,例如构建。
      新的p2供应系统有很多好处。Eclipse安装工件可以从一个版本更新到另一个版本。由于以前的配置文件存储在磁盘上,所以也有办法恢复到以前的Eclipse安装。此外,给定一个配置文件和一个存储库,你可以重新创建报告错误的用户的Eclipse安装,尝试在自己的桌面上重现问题。使用p2提供了一种更新和安装的方法,而不仅仅是Eclipse SDK,它是一个适用于RCP和OSGi用例的平台。Equinox团队还与另一个Eclipse项目的成员合作,即Eclipse Communication Framework(ECF),为消费p2仓库中的工件和元数据提供可靠的传输。
      当p2发布到SDK中时,Eclipse社区内有许多热烈的讨论。由于update manager对于Eclipse安装来说是一个不太理想的解决方案,Eclipse消费者习惯于将捆绑包解压缩到他们的安装中,然后重新启动Eclipse。这种方法在尽力的基础上解决了你的捆绑包。这也意味着你安装中的任何冲突都是在运行时解决的,而不是在安装时解决。约束应该在安装时解决,而不是在运行时解决。然而,用户往往对这些问题熟视无睹,并认为既然捆绑包存在于磁盘上,那么它们就可以工作。以前,Eclipse提供的更新站点是一个由JARred bundles和特性组成的简单目录。一个简单的site.xml文件提供了站点中可供消耗的特性的名称。随着p2的出现,p2仓库中提供的元数据要复杂得多。为了创建元数据,需要对构建过程进行调整,以便在构建时生成元数据,或者在现有的捆绑包上运行一个生成器任务。起初,缺乏描述如何进行这些改变的文档。同样,如同往常一样,向更多的人展示新技术会暴露出意想不到的bug,这些bug必须得到解决。然而,通过编写更多的文档和长时间的工作来解决这些bug,Equinox团队能够解决这些问题,现在p2是许多商业产品背后的底层供应引擎。以及,Eclipse基金会每年都会使用所有贡献项目的p2聚合仓库来运送其协调发布。

    • 6.4.6.4. Eclipse 4.0
      必须不断地检查架构,以评估它是否仍然合适。它是否能够纳入新技术?它是否能鼓励社区的发展?它是否容易吸引新的贡献者?2007年末,Eclipse项目的提交者们决定,这些问题的答案都是否定的,他们开始为Eclipse设计新的愿景。同时,他们意识到,有成千上万的Eclipse应用依赖于现有的API。2008年底,一个孵化器技术项目应运而生,有三个具体目标:简化Eclipse编程模型,吸引新的提交者,使该平台能够利用新的网络技术,同时提供一个开放的架构。
      在这里插入图片描述

    • 图6.9:Eclipse 4.0 SDK早期采用者版本
      Eclipse 4.0于2010年7月首次发布,供早期采用者提供反馈。它由3.6版本中的SDK捆绑包和技术项目中的新捆绑包组成。和3.0一样,有一个兼容层,这样现有的捆绑包就可以和新版本一起使用。和以往一样,有一个警告,即消费者需要使用公共API,以确保兼容性。如果你的捆绑包使用的是内部代码,就没有这样的保证。4.0版本提供了Eclipse 4应用平台,它提供了以下功能。

    • 6.4.1.模型工作台
      在4.0中,使用Eclipse建模框架(EMFgc)生成了一个模型工作台。模型和视图的渲染之间的关注点是分离的,因为渲染器与模型对话,然后生成SWT代码。默认情况下是使用SWT渲染器,但也可以使用其他解决方案。如果您创建一个4.x应用程序示例,将为默认的工作台模型创建一个XMI文件。该模型可以被修改,工作台将被立即更新以反映模型的变化。图 6.10 是为 4.x 示例应用程序生成模型的一个例子。
      在这里插入图片描述

    • 图6.10:为例4.x应用生成的模型。

    • 6.4.2.层叠样式表的样式
      Eclipse发布于2001年,当时还没有出现丰富的互联网应用程序时代,这些应用程序可以通过CSS提供不同的外观和感觉的皮肤。Eclipse 4.0提供了使用样式表来轻松改变Eclipse应用程序的外观和感觉的能力。默认的CSS样式表可以在org.eclipse.platform bundle的css文件夹中找到。
      6.4.3.依赖性注入
      Eclipse扩展注册表和OSGi服务都是服务编程模型的例子。按照惯例,一个服务编程模型包含服务生产者和消费者。经纪人负责管理生产者和消费者之间的关系。
      在这里插入图片描述

    • 图6.11:生产者和消费者之间的关系
      传统上,在Eclipse 3.4.x应用中,消费者需要知道实现的位置,并了解框架内的继承,才能消费服务。因此,消费者代码的可重用性较差,因为人们无法重写消费者接收哪种实现。例如,如果你想在Eclipse 3.x中更新状态行上的消息,代码会是这样的。
      getViewSite().getActionBars().getStatusLineManager().setMessage(msg);
      Eclipse 3.6是由组件构建的,但这些组件中的许多组件耦合得太紧。为了组装更松耦合的组件的应用程序,Eclipse 4.0使用依赖注入来为客户提供服务。在Eclipse 4.x中,依赖注入是通过使用一个自定义框架来实现的,该框架使用上下文的概念作为一种通用机制来为消费者定位服务。上下文存在于应用程序和框架之间。上下文是有层次的。如果一个上下文有一个不能满足的请求,它将把这个请求委托给父上下文。Eclipse上下文被称为IEclipseContext,存储可用的服务,并提供OSGi服务查询。基本上,上下文类似于Java地图,它提供了一个名称或类到对象的映射。上下文处理模型元素和服务。模型的每个元素,都会有一个上下文。在4.x中,服务是通过OSGi服务机制来发布的。
      在这里插入图片描述

    • 图6.12:服务经纪人上下文
      生产者将服务和对象添加到存储它们的上下文中。服务由上下文注入到消费者对象中。消费者声明它想要什么,上下文决定如何满足这个请求。这种方法使消费动态服务变得更加容易。在Eclipse 3.x中,当服务可用或不可用时,消费者必须附加监听器才能得到通知。在Eclipse 4.x中,一旦上下文被注入到消费者对象中,任何变化都会再次自动传递给该对象。换句话说,依赖注入再次发生。消费者通过使用遵守 JSR 330 标准的 Java 5 注解(如 @inject)以及一些自定义的 Eclipse 注解来表示它将使用上下文。支持构造函数、方法和字段注入。4.x运行时会扫描对象以寻找这些注解。执行的操作取决于找到的注解。
      这种将上下文和应用之间的关注点分离,可以更好地重用组件,并免除消费者对实现的理解。在4.x中,更新状态行的代码是这样的。

    @Inject
    IStatusLineManager statusLine;
    ⋮    ⋮    ⋮
    statusLine.setMessage(msg);
    
    1. 6.4.4.应用服务
      Eclipse 4.0 的主要目标之一是简化消费者的 API,以便易于实现通用服务。这些简单的服务列表后来被称为"二十件事",被称为Eclipse应用服务。其目标是提供独立的API,客户可以使用,而不必深入了解所有可用的API。它们被结构化为独立的服务,因此它们也可以用Java以外的其他语言来使用,比如Javascript。例如,有一个API可以访问应用程序模型,读取和修改偏好,并报告错误和警告。
    2. 6.5.6.5. 结论
      Eclipse的基于组件的架构已经发展到在保持向后兼容性的同时融入新技术。这样做的代价很高,但回报是Eclipse社区的发展,因为建立了信任,消费者可以继续基于稳定的API来发布产品。
      Eclipse有这么多的消费者,他们的用例多种多样,我们庞大的API变得很难让新消费者采用和理解。回想起来,我们应该让我们的API更简单。如果80%的消费者只使用了20%的API,那么就需要简化,这也是创建Eclipse 4.x流的原因之一。
      众人的智慧确实揭示了一些有趣的用例,比如将IDE分解成可用于构建RCP应用的捆绑包。相反,众人往往会产生大量的噪音,要求提供需要大量时间来实现的边缘案例方案。
      在Eclipse项目的早期,提交人可以奢侈地将大量时间投入到文档、示例和回答社区问题上。随着时间的推移,这个责任已经转移到了整个Eclipse社区。我们本可以更好地提供文档和用例来帮助社区,但考虑到每个版本都有大量的项目计划,这很难做到。与人们对软件发布日期滑落的期望相反,在Eclipse,我们始终如一地按时交付我们的版本,这让我们的消费者相信他们也能做到这一点。
      通过采用新技术和重塑Eclipse的外观和工作方式,我们继续与消费者对话,并让他们参与到社区中来。如果您有兴趣参与Eclipse,请访问http://www.eclipse.org。
      脚注
    3. http://www.eclipse.org
    4. http://www.eclipse.org/equinox
    5. 例如:http://help.eclipse.org。
    展开全文
  • 分布式架构演进过程

    2021-02-24 11:41:06
    在介绍架构之前,为了避免部分读者对架构设计中的一些概念不了解,...如Zookeeper中的Master和Slave分别部署在多台服务器上,共同组成一个整体提供集中配置服务。在常见的集群中,客户端往往能够连接任意一个节点获得
  • 2月23日,在上海举行的第23届GTI国际产业峰会上,中国移动联合近20家国内外主流运营商和厂商,共同发布《5G无线技术演进白皮书》。
  • 嵌入式操作系统与物联网演进之路

    千次阅读 2017-05-05 10:27:10
    物联网是新一代信息技术的重要组成部分,回顾其发展,其中不得不提的必然是嵌入式系统。在如今的物联网热潮之下,嵌入式系统也面临着全新的...本期我们与嵌入式系统专家何小庆共同探索嵌入式物联网操作系统的演进之路。
  • 一张前端演进史的图在 Reddit 上引起了热议,我们征得原图作者的同意,将这张图放在这里,希望和大家一起了解前端技术的历史,探讨前端圈的发展,共同学习进步! 内容涉及: 浏览器的发展史 HTML 生态演进史 CSS ...
  • C-V2X业务演进白皮书

    2019-11-07 17:53:32
    IMT2020(5G)推进组C-V2X工作组适时在2017年启动C-V2X业务演进课题,中兴通讯牵头联合通信、汽车、交通、IT与互联网等38家成员单位共同开展研究。在北京“2019中国国际信息通信展览会”的“2019未来城市发展论坛”中...
  • 戳蓝字“CSDN云计算”关注我们哦!云计算演进历程云计算产生背景云计算的产生是需求推动、技术进步、商业模式转变共同促进的结果。需求推动指的是政企客户低成本且高性能的信息化...
  • 2月23日,在上海举行的第23届GTI国际产业峰会上,中国移动联合近20家国内外主流运营商和厂商,共同发布《5G无线技术演进白皮书》。这是业界第一次联合发布关于5G无线发展演进的白皮书,标...
  • 为了更好地理解不同架构框架之间的关系、共同点与差别,我们首先看一看企业架构框架的演进过程来,企业架构框架演进行过程,如下图。从上图,可知企业架构的演进的两条主线:一条是以Zachman框架为基础,开发出的...
  • 在全球各大运营商以及包括华为在内的主流设备商等的踊跃参与、共同努力和积极贡献之下,FSAN/ITU-T于2010年6月完成了NG PON的相关标准工作。在业界翘盼之下,可由GPON平滑演进而成的10GPON系统终于揭开了神秘面纱,...
  • 分析与把握由于物联网的业务需求所带来的用户流量模型的变化,以及由此引起的3G/B3G承载网与物联网业务所需承载网的不同,进而分析物联网的发展对C网的演进路线与策略的影响,应该引起业界的共同关注。1、物联网发展...
  • 在当今的移动互联网...与此同时,随着无线标准的演进和Wi-Fi技术的日益成熟,新型应用不断涌现,家中的各种智能设备与家电设备有了更多互连、互动的可能性,智能家庭的概念逐渐成为了行业与消费者共同关注的新热点。
  • 欢迎同学们共同探讨,指正。(文末福利:《小程序开发不求人》电子书下载) 从 Service Worker 到 V8 Worker 本节简要介绍支付宝小程序从 Service Worker 到 V8 Worker 的技术演进过程。 众所周知,支付宝小程序源码...
  • 携程高级技术副总裁叶亚明:从呼叫中心到移动互联网的演进   CSDN、ITValue共同发起首届最具价值CTO评选,携程高级技术副总裁叶亚明已参与评选。近期,CTO俱乐部对其进行了专访,请他分享了携程的技术架构...
  • 云计算的产生是需求推动、技术进步、商业模式转变共同促进的结果。需求推动指的是政企客户低成本且高性能的信息化需求;人用户的互联网、移动互联网应用需求强烈,追求更好用户体验。技术进步指的是虚拟化技术、分布...
  • 一、背景介绍 我们知道 Zabbix 在监控界占有不可撼动的地位,...思必驰的监控系统的演进经过如下几个阶段: 人肉堆积阶段——采用比较原始的模式,例如系统监测采用 Zabbix,网络监测采用 Cacti 等,八仙过海各显神...
  • 结合七牛的实战经验,分析七牛的客户使用云计算的架构方式,以及为了适应不同的客户类型和使用场景,七牛的产品变化过程,并在此基础上与大家共同探讨云计算的产业构成,给出企业如何更好使用云计算基础设施的建议。...
  • 在介绍架构之前,为了避免部分读者对架构设计中...如Zookeeper中的Master和Slave分别部署在多台服务器上,共同组成一个整体提供集中配置服务。在常见的集群中,客户端往往能够连接任意一个节点获得服务,并且当集群中一
  • 早些年学习5GC时的个人总结材料,初学者可以用来参考借鉴,可以共同探讨,共同学习。早些年学习5GC时的个人总结材料,初学者可以用来参考借鉴,可以共同探讨,共同学习。
  • 3.2 会场,小二与商家共同打造的购物清单 99 3.3 搜索,大促场景下智能化演进之路 107 3.4 个性化推荐,大数据和智能时代的新航路 114 3.5 供应链,从飞速增长到精耕细作 120 3.6 蚂蚁花呗,无忧支付的完美体验 127 ...
  • 欢迎同学们共同探讨,指正。作者: 旷古 阿里技术从 Service Worker 到 V8 Worker本节简要介绍支付宝小程序从 Service Worker 到 V8 Worker 的技术演进过程。众所周知,支付宝小程序源码打包完成之后主要分...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 461
精华内容 184
关键字:

共同演进