• [应用专区] 【AR502H产品】【串口功能】串口没有输出
    【功能模块】      AR502H串口输出模块【操作步骤&问题现象】1、我创建了一个容器,命名为lxc01,该容器是特权模式的容器(登陆后是root用户)。2、映射串口设备:在AR502H使用 container add-dev lxc01命令将所有的设备映射到容器里,如下图所示:3、然后配置串口的模式:使用serialportctl命令来配置/dev/ttyRS1,和/dev/ttyRS2,如下图所示:4、配置串口:在容器内容使用stty命令执行如下操作:stty -F /dev/ttyRS1 speed 9600 cs8 -parenb -cstopb将串口1设置成了9600波特率 8数据位 1停止位 无校验位,如下图所示:5、连接串口:    然后使用串口1连接到我的主机电脑的一个串口,并将该串口设置为与/dev/ttyRS1相同的配置。6、测试:    在lxc01容器内,使用echo “111111” > /dev/ttyRS1命令,在我的电脑那一端的串口终端没有收到任何信息。并且485接口的灯也没有闪烁(我们做回环测试是可以闪烁的,说明串口连接没有问题)。请问这是什么原因,我对串口的操作还有哪些需要操作的。
  • [容器专区] 【融合终端产品】容器内执行“rmmod ftdi_sio”命令失败
    【功能模块】在容器运行的demo程序会调用函数并执行system("rmmod ftdi_so"),窗口显示执行命令异常,如下图所示:【操作步骤&问题现象】1、容器包的生成方法是参考《边缘计算网关二次开发智能(AR-CORE系列)》指导手册,制作脚本是从容器编译环境制作脚本下载。2、容器制作步骤:a.制作基础镜像 -> b.在基础镜像里编译第三方开源组件(命令:./build_opensrc.sh arm64) -> c.制作最终编译环境的镜像 -> d.在最终容器环境下编译生成容器包,执行命令:./build_ova.sh arm64 1.0.0 huawei unprivileged3、将生成的容器安装包ARLXC-EC-1.0.1-arm64-unprivileged.ova导入到融合终端的/mnt/internal_storage目录下,然后安装容器并加载所有驱动,容器状态如下:4、进入容器后,手动执行命令“rmmod ftdi_sio”是正常,但执行demo程序后,就会出现异常现象,如下界面5、相同的demo程序,放在贵单位核心板默认安装的lxc01环境下是可以正常运行的,能成功操作ft4232芯片并实现SPI的收发通信。
  • [技术干货] 跳转机分配问题终于“有救”了!容器化时代到来
    跳转机容器化方案介绍想必大家在利用跳转机进行解决方案开发和测试过程中都会遇到这些问题:1. hi,兄弟,帮我分配个跳转机;2. 谁呀,XX跳转机我在使用,不要抢占;3.跳转机全分配完了,没有可用的了,而实际上有很多跳转机分而不用;4. 我想用跳转机来模拟用户,可没有足够的跳转机资源进行容量测试;5.我们跳转机是WINDOWS系统,而实际交付版本配套工具是需要安装在LINUX上的,无资源进行镜像测试;……遇到以上问题怎么办?通过学习和实践利用容器化跳转机方案将如上问题彻底解决,现就该方案跟大家做个分享,欢迎大拿们一起交流。什么是容器容器是应用层的抽象,多个容器可以在同一台宿主机上运行,并共享操作系统资源,每个容器在用户界面是独立运行的,互相不干扰。更多知识,点击:https://mp.weixin.qq.com/s?__biz=MzA5MjM5OTYzNA==&mid=2247489316&idx=1&sn=31404eacde815bee1d9d23d99fea1fb0&chksm=906ce659a71b6f4f96df95d1c8055ca5c76f7cc56057270b6872dd7b28f6235ca08dcf9b9e10&token=1376150626&lang=zh_CN#rd
  • [技术干货] 没有它你的DevOps是玩不转的,你信不?
    善用兵者,役不再籍,粮不三载。取用于国,因粮于敌,故军食可足也。                                                                                                                 ——《孙子兵法》在古代,带兵作战的将领,不仅要能善于用兵,而且要能保障粮食的充足。正所谓兵马未动,粮草先行。粮草永远摆在第一位,因为在冷**时代,战争中的将士都是在拼力气,吃饱才有力气打仗。在今天互联网的“战争”环境中,我们为了能更快的应对市场变化,一直以来不断调整着作战的方针和打法,也从传统的开发方式转变为了敏捷开发,由敏捷开发又过渡了到DevOps。在2019年的中国DevOps行业报告中指出:“尽管受访企业期望 DevOps 能够带来更高效的交付效率,提升客户满意度,创造更多的商业价值,但成功实践 DevOps 依然是一个难题 。”其中28.22% 被调查者认为自己组织的 DevOps 实践是不成功的, 41.13%的被调查者不清楚如何衡量自己组织的 DevOps 实践是否成功。如果以一个更加直观的数据来展示,就是在接受调查的企业中有69.35%是没有能很好的了解和实践DevOps的。也许,在实践DevOps的这几年来,并没有多少公司是真正知道什么是DevOps的。DevOps只是从字面上理解的打破部门墙的一键发布的工具链吗,是否有了这个工具链就是DevOps?答案是否定的。那么,DevOps是什么?DevOps 是集文化理念、实践和工具于一身,可以提高组织高速交付应用程序和服务的能力,与使用传统软件开发和基础设施管理流程相比,能够帮助组织更快地发展和改进产品。这种速度使组织能够更好地服务其客户,并在市场上更高效地参与竞争。——AWS从AWS给出的定义来看,好像也还是比较的抽象。那如果简单的来说,DevOps就是让软件过程既“快”又“稳”。何为快和稳,这个快和稳体现在,部署频率、交付周期、平均修复时长、变更失败比例这4个维度上。在2018年的DevOps调查报告中基于上述4个维度,由于仅有6%达到了所规定的高性能指标,为了避免特殊原因造成数据过低,所以放宽的条件,并给出了准高性能DevOps指标。从达成这一准高性能DevOps指标的团队分析来看,其具体体现在三个方面:一方面是自动化、标准化、质量保证、敏捷方法的实践活动上;一方面是DevOps各个阶段的对应工具上。除此以外就是,团队正在开发应用的架构上。架构的选择对于DevOps的实践是至关重要的,从某种程度上来说,架构就是DevOps这场战役的粮草,它是支撑着DevOps成功落地的重要前提。受访的准高性能DevOps指标的团队将“使用微服务框架”作为团队正在开发应用的架构上的Top1。什么是微服务是一种软件架构风格,它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础,利用模块化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关 (Language-Independent/Language agnostic) 的 API 集相互通信。微服务的起源是由 Peter Rodgers 博士于 2005 年度云计算博览会提出的微 Web 服务 (Micro-Web-Service) 开始,Juval Löwy 则是与他有类似的前导想法,将类别变成细粒服务 (granular services),以作为Microsoft下一阶段的软件架构,其核心想法是让服务是由类似 Unix 管道的访问方式使用,而且复杂的服务背后是使用简单URI来开放接口,任何服务,任何细粒都能被开放 (exposed)。这个设计在 HP 的实验室被实现,具有改变复杂软件系统的强大力量。2014年,Martin Fowler与James Lewis共同提出了微服务的概念,定义了微服务是由以单一应用程序构成的小服务,自己拥有自己的行程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用 HTTP API 通信。同时服务会使用最小的规模的集中管理 (例如Docker) 能力,服务可以用不同的编程语言与数据库等组件实现。 微服务的特点根据Martin Fowler的分析,微服务架构有以下的一些通用特性,但并非所有微服务架构应用都必须具备所有这些特性:1.  通过服务实现应用的组件化(Componentizationvia Services):微服务架构中将组件定义为可被独立替换和升级的软件单元,在应用架构设计中通过将整体应用切分成可独立部署及升级的微服务方式进行组件化设计。2.  围绕业务能力组织服务(Organizedaround Business Capabilities):微服务架构采取以业务能力为出发点组织服务的策略,因此微服务团队的组织结构必须是跨功能的(如:既管应用,也管数据库)、强搭配的DevOps开发运维一体化团队,通常这些团队不会太大(如:亚马逊的“Two pizza team”- 不超过12人)。3.  产品而非项目模式(Productsnot Projects):传统的应用模式是一个团队以项目模式开发完整的应用,开发完成后就交付给运维团队负责维护;微服务架构则倡导一个团队应该如开发产品般负责一个“微服务”完整的生命周期,倡导“谁开发,谁运营”的开发运维一体化方法。4.  智能端点与管道扁平化(Smartendpoints and dumb pipes):微服务架构主张将组件间通讯的相关业务逻辑/智能放在组件端点侧而非放在通讯组件中,通讯机制或组件应该尽量简单及松耦合。RESTful HTTP协议和仅提供消息路由功能的轻量级异步机制是微服务架构中最常用的通讯机制。5.  “去中心化”治理(DecentralizedGovernance):整体式应用往往倾向于采用单一技术平台,微服务架构则鼓励使用合适的工具完成各自的任务,每个微服务可以考虑选用最佳工具完成(如不同的编程语言)。微服务的技术标准倾向于寻找其他开发者已成功验证解决类似问题的技术。6.  “去中心化”数据管理(DecentralizedData Management):微服务架构倡导采用多样性持久化(PolyglotPersistence)的方法,让每个微服务管理其自有数据库,并允许不同微服务采用不同的数据持久化技术。7.  基础设施自动化(InfrastructureAutomation):云化及自动化部署等技术极大地降低了微服务构建、部署和运维的难度,通过应用持续集成和持续交付等方法有助于达到加速推出市场的目的。8.  故障处理设计(Designfor failure):微服务架构所带来的一个后果是必须考虑每个服务的失败容错机制。因此,微服务非常重视建立架构及业务相关指标的实时监控和日志机制。9.  演进式的设计(EvolutionaryDesign):微服务应用更注重快速更新,因此系统的计会随时间不断变化及演进。微服务的设计受业务功能的生命周期等因素影响。如某应用是整体式应用,但逐渐朝微应用架构方向演进,整体式应用仍是核心,但新功能将使用应用所提供的API构建。再如在某微服务应用中,可替代性模块化设计的基本原则,在实施后发现某两个微服务经常必须同时更新,则这很可能意味着应将其合并为一个微服务。微服务适用的场景基于微服务的优势,我们可以看到,微服务比较实用于以下场景:1.    对于业务流程较为复杂,且业务会变得逐渐复杂的项目,可以考虑使用微服务架构2.    项目存在多个团队(公司)多种开发语言时 3.    核心业务和非核心业务变得泾渭分明 4.    需要平滑升级时(服务无中断、客户无感知)5.    想对系统进行细粒度监控时 (bug调查困难或性能等问题)既然微服务有其使用的场景,那么也一定有其优缺点。微服务的优势微服务的诞生正是在互联网高速发展,技术日新月异变化以及传统架构无法适应快速变化等多种因素共同推动下的必然产物。从一个网站的演变可以看到使用微服务后带来了很多优点,总结如下:逻辑清晰:这个特点是由微服务的单一职责的要求所带来的。逻辑清晰带来的是微服务的可维护性,在我们对一个微服务进行修改时,能够更容易分析到这个修改到底会产生什么影响,从而通过完备的测试保证修改质量。简化部署:微服务则可以只对一个微服务单独进行部署,不影响其他功能的同时,在效率上也得到了提升,从而快速的发布新的功能。可扩展性强:在分布式系统中,采用微服务的系统相对单块系统具备更好的可扩展性。灵活组合减少浪费:在微服务架构中,可以通过组合已有的微服务以达到功能重用的目的,减少了重复浪费。技术异构:微服务间松耦合,不同的微服务可以选择不同的技术栈进行开发。微服务的缺点以往单体应用,排查问题通常是看一下日志,研究错误信息和调用堆栈。而微服务架构整个应用分散成多个服务,定位故障点非常困难。在微服务架构中,一个服务故障可能会产生雪崩效用,导致整个系统故障。微服务架构虽然逻辑设计上看是完美的,但就像积木搭建的华丽宫殿一样,经不起风吹草动。微服务架构虽然解决了旧问题,也引入了新的问题:提高了系统的复杂度,此外还有:1.    服务的注册与发现问题;2.    服务之间的分布式事务问题;3.    数据隔离再来的报表处理问题;4.    服务之间的分布式一致性问题;5.    服务管理的复杂性,服务的编排;6.    不同服务实例的管理。 微服务在使用上是一把“双刃剑”,这就像粮草如果在搬运的过程中被敌方夺取,那可能会是毁灭性的。所以DevOps团队在微服务的架构上需要非常的重视,一个成熟度高的微服务框架才是实现其DevOps的重要前提,反之亦然。那么如何算得上是一个成熟度高的微服务呢?在华为云DevCloud专业服务中提供了微服务的能力评估,想知道成熟度高不高,快来看看你的微服务的成熟度评估结果吧~~~~~~~~~~~
  • 容器技术:从通用向多元化发展
    (1) 安全容器        容器技术的采纳率连年提升,已经开始进入企业的生产环境。以Docker 为代表的普通容器通过Namespaces 和cGroups 实现的隔离,共享内核的机制使得隔离性具有天然的缺陷无法根除,在多租户场景下安全问题更加凸显:        内核Bug 引发容器逃逸,操作系统内核漏洞、Docker 组件设计缺陷、不当的配置等都会导致Docker 容器发生逃逸。由于频发的安全及逃逸漏洞,一般在云环境中的容器应用不得不运行在虚拟机中,以满足多租户安全隔离要求。而分配、管理、运维这些传统虚拟机与容器轻量、灵活、弹性的初衷相悖,同时在资源利用率、运行效率上也存在不足。内核资源竞争影响业务性能,同一个宿主机上的不同Pod,实际上是不同的用户态进程的集合,这些用户态进程虽然在namespace 上是相互隔离的,但他们还是会共享很多内核资源,比如调度器、某些内核线程或者对象。这种级别的资源共享会引入很多可以观测到的性能抖动,对在线业务的影响也很明显。与Docker 普通容器不同,安全容器通过添加隔离层,给进程分配了一个独立的操作系统内核,从而避免了让容器共享宿主机的内核。因此容器进程能够看到的攻击面,就从整个宿主机内核变成了一个极小的、独立的、以容器为单位的内核,从而有效解决了容器进程发生“逃逸”或者夺取整个宿主机的控制权的问题。(2) Serverless 容器        FaaS 平台提供的是函数级别的Serverless 化部署,且应用场景多依赖于其绑定的触发器,对函数的执行有一些配置限制,并且不支持进程常驻。传统的应用大都是单体应用或者微服务应用,在迁移到FaaS 平台时,需要拆分函数,迁移成本较高。        Serverless 容器,可以很好地弥补FaaS 的不足,Serverless 容器可以支持进程常驻的服务形态,不限运行时长,并扩大Serverless的应用场景。Serverless 容器支持服务的形态,传统的单体应用或者微服务应用,几乎可以无缝迁移到Serverless 容器平台上。        Serverless 容器和传统的容器相比,为了实现Serverless 的理念,在如下几个方面做了加强:免运维的纯托管模式,传统的容器往往是直接将容器集群托管给业务方,业务方需要分担容器集群的一些运维工作。Serverless 容器则把容器集群完全托管给云厂商,由云厂商进行集群的运维工作,用户不用关注这些运维工作,只需部署自己的业务逻辑即可;以实际资源用量计费,传统的容器是按照容器的实例配置进行计费的,Serverless 容器是按照实际资源使用量进行计费;秒级弹性伸缩响应,传统的容器往往借助于容器编排工具来实现弹性伸缩,比如通过Kubernetes 可以实现Docker 的容器的弹性伸缩,但是Kubernetes 伸缩时间是分钟级的,而Serverless 容器能够提供更加极致的伸缩能力,做到秒级伸缩并且资源实例和伸缩至零。    (3) 裸金属容器        容器服务最早部署形态是基于IAAS 虚拟机,以虚拟机节点作为容器集群的计算节点,并基于此构建容器的网络、存储和编排能力,这样的堆叠架构虽然可以让整个软件栈分工明确、边界清晰,但是带来了较大的性能损耗和功能冗余。此外如果用户对实例安全隔离性要求较高,就需要借助虚拟化技术,而虚拟化平台不能很好支持该能力。基于以上痛点,在裸金属服务器上搭建容器服务成为一些对性能和实例隔离性较高用户的选择。        随着裸金属容器的发展,为了进一步提高容器负载性能和稳定性,原来部署在裸金属之上的非业务负载组件也逐步的由专门的卸载硬来承载,比如容器存储、容器网络、容器引擎以及服务网格组件。将容器组件下沉到卸载卡后,有几方面好处:l 裸金属节点就可以被当做纯粹的计算资源,可以“完全”被业务负载使用。同时避免了对业务负载的性能干扰。l 容器网络、容器存储组件下沉到卸载卡后可以与传统IAAS 层的网络、存储组件垂直打通,减少冗余功能;直接以硬件设备直通方式将存储、网络资源分配给容器实例,缩短I/O 路径,提高性能。l 容器层组件下沉到卸载卡后,裸金属成为纯粹的计算资源,可以被容器实例或者虚机实例共享,为虚拟机和容器实例共节点奠定了基础,提高资源整体利用率。虽然裸金属容器可以通过卸载技术获得诸多益处,但同时也面临着较大的挑战:l 资源占用问题。由于卸载卡上的资源非常有限,容器组件需要进行轻量化瘦身后才能较好的适配卸载卡,当前业界也在推动容器引擎层面的轻量化改造,比如kata-shim-v2 和isulad。l 实例密度问题。由于容器存储和网络资源都是走VF 直通方式,而当前卸载卡上支持的VF 数量比较有限,在小规格实例场景,VF 会成为实例密度提升的限制。        此外,裸金属容器不仅在资源利用率和性能上有优势,对系统运维管理的自动化和敏捷性上有较高诉求。为了获得较高的自动化运维能力,很多的依赖组件都进行了微服务改造,借助容器编排自身能力来自动化管理所依赖的服务,甚至是节点操作系统本身。比如AWS 为了提高容器计算节点操作系统更新管理的灵活性,推出了bottlerocket 产品,放弃原来基于包更新的升级机制,采用镜像粒度一步更新方法,降低了OS 更新的失败率,提高运维自动化程度和容器应用的稳定性。来源:云原生产业联盟
  • [技术干货] 因为这7个C++的坑,整个团队加班一星期
     摘要:近期踩到了一些比较隐晦的C++的坑,可把我们团队给坑惨了~~近期我们团队进行版本质量加固时,踩到了一些比较隐晦的C++的坑,特总结分享在此,供大家参考。1. string的字符串拼接,导致coredump该问题的核心点在于第9行,竟然是可以编译通过,其原因是x+"-",会被转成char*,然后与to_string叠加导致BUG。2. map的迭代器删除map要删除一个元素,通常通过erase()函数来完成,但是要注意,如果我们传入了一个iterator作为erase的参数来删除当前迭代器所指向的元素,删除完成后iterator会失效,产生未定义行为。正确的使用方法应该是接收erase()的返回值,让iterator指向被删除元素的下一个元素或者end()。for  ( auto  iter = m.begin(); iter != m.end(); iter++) {  if  (...)  iter = m.erase(iter);  } 但是上述代码仍然有错误,因为如果触发了删除,那么iter再下一轮循环时会指向下下个元素,所以正确的写法应该是:  for  ( auto  iter = m.begin(); iter != m.end();) {  if  (...) {  iter = m.erase(iter);  continue ;  }  else  {  iter++;  }  } 3. stringstream的性能问题stringstream的清空是clear之后,置空。stringstream在任何情况下都比snprintf慢。memset是个很慢的函数,宁愿新创建对象。上述测试结果是单线程,改成多线程,同样成立。str += “a”, 比 str =str+ “a” 效率高很多,后者会创建新对象。4. 智能指针(shared_ptr)使用注意4.1尽量使用make_shared初始化提高性能std::shared_ptr<Widget> spw(newWidget);需要分配两次内存。每个std::shared_ptr都指向一个控制块,控制块包含被指向对象的引用计数以及其他东西。这个控制块的内存是在std::shared_ptr的构造函数中分配的。因此直接使用new,需要一块内存分配给Widget,还要一块内存分配给控制块autospw = std::make_shared<Widget>();一次分配就足够了。这是因为std::make_shared申请一个单独的内存块来同时存放Widget对象和控制块。这个优化减少了程序的静态大小,因为代码只包含一次内存分配的调用,并且这会加快代码的执行速度,因为内存只分配了一次。另外,使用std::make_shared消除了一些控制块需要记录的信息,这样潜在地减少了程序的总内存占用。异常安全processWidget(std::shared_ptr<Widget>( new  Widget),   //潜在的资源泄露   computePriority()); 上述代码存在内存泄漏的风险,上述代码执行分为3个步骤:1.  new  Widget2. shared_ptr构造3. computePriority 编译器不需要必须产生这样顺序的代码,但“new Widget”必须在std::shared_ptr的构造函数被调用前执行。如果编译器产生的顺序代码如下:1.  new  Widget2. 执行computePriority。3. 执行std::shared_ptr的构造函数。 如果执行步骤2:computePriority的时候程序出现异常,则在第一步动态分配的Widget就会泄露了,因为它永远不会被存放到在第三步才开始管理它的shared_ptr中4.2 父类之类智能指针转换C++中是允许裸指针,因此裸指针之间转换方法同C语言指针强转,智能指针转换不能通过上述方法进行强转,必须通过库提供转换函数进行转换。 C++11的方法是:std::dynamic_pointer_cast;boost中的方法是:boost::dynamic_pointer_cast#include <memory>#include <boost/shared_ptr.hpp>#include <boost/make_shared.hpp>#include <iostream>class  Base {  public :  Base(){}  virtual  ~Base() {}};class  D :  public  Base {  public :  D(){}  virtual  ~D() {}};int  main(){  //方式一:先初始化子类智能指针,然后调用dynamic_pointer_cast转换成基类智能指针对象  std::shared_ptr<D> d1 = std::make_shared<D>();  std::shared_ptr<Base> b1 = std::dynamic_pointer_cast<Base>(d1);    //方式二:先new子类D的指针,然后调用shared_ptr的构造函数初始化基类智能指针  std::shared_ptr<Base> b2 = shared_ptr<Base>( new  D());  return  0;} 结论方式一和方式二均能够实现基类智能指针指向子类,但建议采用方式1,通过std::make_shared的方式构造智能指针,然后进行转换;5. map的安全查找办法即map[key]这种写法,就是会创建元素(且不一定初始化),因此在业务逻辑是希望查找的时候,就老老实实用find,不然会有脏数据写入。6. string 的指针构造std::string 的构造方式,除了与其它顺序容器相近的方式之外,提供了三种额外的构造方式:string s(cp, n): s 是cp指向的数组中前n个字符的拷贝,该数组至少应该包含n个字符string s(s2, pos2):s 是string s2从下标pos2开始的字符的拷贝,若pos2>s2.size(),构造函数的行为未定义string s(s2, pos2, len2):s 是string s2从下标pos2开始len2个字符的拷贝,若pos2>s2.size(),构造函数的行为未定义。不管len2的值是多少,构造函数至多拷贝s2.size()-pos2个字符 std::string 未提供 string(cp, pos2, len2) 这种构造方式,如果代码中使用了该方式,最终会将 cp 指向的数组构造成一个string,然后调用string(s2, pos2, len2)这种构造方式。不提供string(cp, pos2, len2)这种构造方式原因在于:使用这种方式构造容易出现问题,cp是一个指针,通常使用时,能获得其数组长度并检查传入参数;若传入两个参数,容易出现越界。7. 变量初始化变量初始化总是没错的,不管后面是否会修改该值。尤其是int等内建的类型,在类或struct中及容易忽略初始化,使变量成为随机值,产生不可预知的错误。变量请初始化!变量请初始化!!变量请初始化!!!
  • [技术干货] 【转载】容器、Docker、虚拟机,别再傻傻分不清
     摘要:容器技术起源于Linux,是一种内核虚拟化技术,提供轻量级的虚拟化,以便隔离进程和资源。尽管容器技术已经出现很久,却是随着Docker的出现而变得广为人知。容器技术起源于Linux,是一种内核虚拟化技术,提供轻量级的虚拟化,以便隔离进程和资源。尽管容器技术已经出现很久,却是随着Docker的出现而变得广为人知。Docker是第一个使容器能在不同机器之间移植的系统。它不仅简化了打包应用的流程,也简化了打包应用的库和依赖,甚至整个操作系统的文件系统能被打包成一个简单的可移植的包,这个包可以被用来在任何其他运行Docker的机器上使用。容器和虚拟机具有相似的资源隔离和分配方式,容器虚拟化了操作系统而不是硬件,更加便携和高效。图1 容器 vs 虚拟机相比于使用虚拟机,容器有如下优点:更高效的利用系统资源由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,容器对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。更快速的启动时间传统的虚拟机技术启动应用服务往往需要数分钟,而Docker容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间,大大节约了开发、测试、部署的时间。一致的运行环境开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些问题并未在开发过程中被发现。而Docker的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性。更轻松的迁移由于Docker确保了执行环境的一致性,使得应用的迁移更加容易。Docker可以在很多平台上运行,无论是物理机、虚拟机,其运行结果是一致的。因此可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。更轻松的维护和扩展Docker使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker团队同各个开源项目团队一起维护了大批高质量的官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。Docker容器典型使用流程Docker容器有如下三个主要概念:镜像:Docker镜像里包含了已打包的应用程序及其所依赖的环境。它包含应用程序可用的文件系统和其他元数据,如镜像运行时的可执行文件路径。镜像仓库:Docker镜像仓库用于存放Docker镜像,以及促进不同人和不同电脑之间共享这些镜像。当编译镜像时,要么可以在编译它的电脑上运行,要么可以先上传镜像到一个镜像仓库,然后下载到另外一台电脑上并运行它。某些仓库是公开的,允许所有人从中拉取镜像,同时也有一些是私有的,仅部分人和机器可接入。容器:Docker容器通常是一个Linux容器,它基于Docker镜像被创建。一个运行中的容器是一个运行在Docker主机上的进程,但它和主机,以及所有运行在主机上的其他进程都是隔离的。这个进程也是资源受限的,意味着它只能访问和使用分配给它的资源(CPU、内存等)。典型的使用流程如图2所示:图2 Docker容器典型使用流程(1)首先开发者在开发环境机器上开发应用并制作镜像。Docker执行命令,构建镜像并存储在机器上。(2)开发者发送上传镜像命令。Docker收到命令后,将本地镜像上传到镜像仓库。(3)开发者向生产环境机器发送运行镜像命令。生产环境机器收到命令后,Docker会从镜像仓库拉取镜像到机器上,然后基于镜像运行容器。使用示例下面使用Docker将基于Nginx镜像打包一个容器镜像,并基于容器镜像运行应用,然后推送到容器镜像仓库。安装DockerDocker几乎支持在所有操作系统上安装,用户可以根据需要选择要安装的Docker版本。在Linux操作系统下,可以使用如下命令快速安装Docker。curl -fsSL get.docker.com -o get-docker.shsh get-docker.sh说明: CentOS 8.0操作系统使用上述脚本安装Docker会出现问题,建议使用如下命令安装较低版本Docker。 wget -O /etc/yum.repos.d/docker-ce.repo https://repo.huaweicloud.com/docker-ce/linux/centos/docker-ce.repo sudo sed -i 's+download.docker.com+repo.huaweicloud.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo yum install docker-ce-18.06.3.ce -y systemctl restart docker Docker打包镜像 Docker提供了一种便捷的描述应用打包的方式,叫做Dockerfile,如下所示: # 使用官方提供的Nginx镜像作为基础镜像 FROM nginx:alpine   # 执行一条命令修改Nginx镜像index.html的内容 RUN echo "hello world" > /usr/share/nginx/html/index.html   # 允许外界访问容器的80端口 EXPOSE 80 执行docker build命令打包镜像。 docker build -t hello . 其中-t表示给镜像加一个标签,也就是给镜像取名,这里镜像名为hello。. 表示在当前目录下执行该打包命令。 执行docker images命令查看镜像,可以看到hello镜像已经创建成功。您还可以看到一个Nginx镜像,这个镜像是从镜像仓库下载下来的,作为hello镜像的基础镜像使用。 # docker images REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE hello               latest              d120ec16dcea        17 minutes ago      158MB nginx               alpine              eeb27ee6b893        2 months ago        148MB 本地运行容器镜像 有了镜像后,您可以在本地执行docker run命令运行容器镜像。 # docker run -p 8080:80 hello docker run命令会启动一个容器,命令中-p是将本地机器的8080端口映射到容器的80端口,即本地机器的8080端口的流量会映射到容器的80端口,当您在本地机器访问 http://127.0.0.1:8080时,就会访问到容器中,此时浏览器中返回的内容应该就是“hello world”。 把镜像推送到镜像仓库 华为云提供了容器镜像服务SWR,您也可以将镜像上传到SWR,下面演示如何将镜像推送到SWR。详细的方法请参见客户端上传镜像,本文档后续的示例中将主要使用SWR作为示例。 首先登录SWR控制台,在左侧选择“我的镜像”,然后单击右侧“客户端上传镜像”,在弹出的窗口中单击“生成临时登录指令”,然后复制该指令在本地机器上执行,登录到SWR镜像仓库。 上传镜像前需要给镜像取一个完整的名称,如下所示: # docker tag hello swr.cn-east-3.myhuaweicloud.com/container/hello:v1 这里swr.cn-east-3.myhuaweicloud.com是仓库地址,每个华为云区域的地址不同,v1则是hello镜像分配的版本号。 swr.cn-east-3.myhuaweicloud.com是仓库地址,每个华为云区域的地址不同。 container是组织名,组织一般在SWR中创建,如果没有创建则首次上传的时候会自动创建,组织名在单个区域内全局唯一,需要选择合适的组织名称。 v1则是hello镜像分配的版本号。 然后执行docker push命令就可以将镜像上传到SWR。 # docker push swr.cn-east-3.myhuaweicloud.com/container/hello:v1 当需要使用该镜像时,使用docker pull命令拉取(下载)该命令即可。 # docker pull swr.cn-east-3.myhuaweicloud.com/container/hello:v1
  • [技术干货] JFrog:这是一个流动的世界,开发者是雨点的制造者
    2020年10月26日上午6:00,作者:Richard MacManus             JFrog上个月进行了首次公开募股(IPO),从那时起,其股价几乎翻了一番。对于一个很难向开发者社区以外的人解释的软件公司来说,这并不坏。甚至连公司的名字都不能说明它到底在做什么。正如JFrog的联合创始人兼首席执行官Shlomi Ben Haim在最近的一次采访中告诉我的那样,如果他的母亲给他打电话祝贺公司的成功,“当我们开始谈论二进制时,她就会失去注意力。”             JFrog是一个DevOps平台,其主要货币是,正如本哈伊姆(Ben Haim)所暗示的那样,它的主要货币是二进制。他还指出,“软件包”和“图像”是同一事物的替代术语。不管用什么术语,它都是已经编译好并准备好供计算机系统执行的代码。有些人将JFrog与GitHub进行了比较,不同之处在于GitHub是源代码的存储库,而JFrog是二进制文件的存储库。“这是你从你的源代码中构建出来的,以及你打包在一起的东西,”本·哈伊姆在谈到二进制文件时说,“从这一点开始,这就是你测试、安全和在运行时部署的东西。”在当前的DevOps应用程序开发时代,有很多活动部件。当您浏览组成JFrog平台的各种软件产品时,您将了解到DevOps变得多么复杂,以及为什么企业越来越需要像JFrog这样的平台来管理它。JFrog成立于2008年,在2008年和在后来的几年里,它的唯一产品是 Artifactory,从2011年起,被称为管理被称为“Repository Management Solution.”之后,JFrog拓展了其他安全、CI?CD、分布式计算产品以及一些其他产品。            关于JFrog的另一个有趣的地方是,正如你猜的,它的销售是由开发者驱动的。决定使用JFrog软件的并不是像微软(Microsoft)和甲骨文(Oracle)等知名软件供应商的那样由企业首席信息官驱动。在JFrog的例子中,这是一个自下而上的采购过程,开发者最初选择使用JFrog,后来随着JFrog的广泛部署,首席信息官可能会承担相应的费用。本•哈伊姆自豪地告诉我,JFrog没有对外销售人员,正因为如此。“即使是今天作为一家上市公司,我们在这个领域连一个直销员都没有。一个也没有。从来没有人敲过别人的门,主动提供JFrog Artifactory——它都安装在里面,都是进货(销售)。”显然,这一策略奏效了。据本•哈伊姆(Ben Haim)称,财富100强企业中有75%现在都在使用JFrog。            你的特斯拉神器库戴尔科技资本公司是JFrog的早期投资者,其董事总经理泰勒•杰威尔(Tyler Jewell)在其开发者主导的景观论文中写道,“artifact存储库”类别同比增长了45%。他说,这是“软件构建方式的转变所驱动的”,特别是第三方可重用模块(通过低代码、JavaScript框架等)的日益增多的使用。             我问Ben Haim,他是否认为未来几年工件库的这种增长水平仍在继续?他回答说,这种增长的一部分原因是由于微服务、容器和其他云计算原生技术的兴起,软件二进制文件“成倍增长”,“因为软件发布变得如此容易”,他不认为工件存储库的市场会很快放缓,因为“可寻址市场将显著增长”。原因:非企业用例。“下一步——想想看——将在你的组织之外,因为你希望你的特斯拉得到更新,你的iPhone也得到更新。DevOps for IoT(物联网)仍处于非常早期的阶段。”这就引出了JFrog一直在其网站上推广的软件理论:液体软件。这在其主页上被定义为“软件更新过程自动地、连续地运行,就像软件是流动的一样。”这让我想起了互联网就像电网一样的比喻——换句话说,就是一种实用工具。JFrog也提出了同样的建议,只是它用电换水。本哈伊姆回到特斯拉,他称之为“一台有轮子的电脑”,进一步解释。他说,目前,如果你需要在你的特斯拉汽车上运行软件更新,“它需要关闭你的发动机两个小时”;有时甚至需要技术人员“到你家里来运行软件更新”,我自己不是特斯拉的车主,我无法验证等待时间(这个Quora线程表明这更像是30分钟),但不管怎样,本·哈伊姆的观点是:在软件更新的过程中,汽车变得无法运行。这是目前的状况,但JFrog的目标是使所有软件更新都能在后台持续进行。“在液体软件的世界里,特斯拉也会随着这个缩放应用程序的更新而更新,”Ben Haim说,他提到了我们目前正在进行的Zoom视频通话。他推测,特斯拉最终将使用点对点网络技术,让汽车相互更新,从而“不让网络超载,也不让我们的基础设施超载” 这一切都要回到开发人员身上,他们当然要负责维护这种“流动”的软件更新过程。              开发者如雨滴制造者            “JFrog(2008年)是由一群本身就是开发者的人创立的,”本•哈伊姆说。“我们的主要想法是解决问题——当公司要求我们提供更多、更快和更安全的产品时,我们如何才能更快?”             他继续说,在JFrog成立之时,软件开发正处于转型期——“从瀑布到敏捷再到DevOps。”尽管DevOps这个词直到2009年才被发明出来,并在那之后又过了几年才获得关注,但JFrog还是围绕着同一个概念建立了自己的公司——或者正如本·哈伊姆所说,“自动化[和]机器的力量,以及开发人员的力量”的结合。在我们的谈话中,本哈伊姆把开发者称为商业的“雨点”。他指的是开发人员正在创造被称为“数字化转型”(我无法告诉你,这句话在新一代“后流感”的电子邮件宣传中被使用了多少次)。 本哈伊姆以一家现代银行为例,说明了开发者将传统业务转变为数字化业务的能力。“我不认为我已经三年多没有亲自拜访过我的银行,但如果我不喜欢应用,我会从一家银行搬到另一家银行。”              他的观点是,现在银行提供了更好的用户体验,因为你可以在网上做更多的事情。我完全同意这一点,我不怀念那些不得不亲自开车去银行分行做任何事情的日子。“开发者之所以成为造雨者,是因为他们创造了企业的竞争优势,”本哈伊姆这样总结道。一旦你理解了这个概念,就很容易理解为什么JFrog在股票市场上表现如此出色——尽管很少有投资者了解它的实际作用。原文链接:https://thenewstack.io/jfrog-its-a-liquid-world-and-developers-are-the-rainmakers/
  • [Java] Iterator 的使用以及特点
    Java中的Iterator功能比较简单,并且只能单向移动:(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。(2) 使用next()获得序列中的下一个元素。(3) 使用hasNext()检查序列中是否还有元素。(4) 使用remove()将迭代器新返回的元素删除。 Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
  • [技术干货] [转载]Python Collections模块
    在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。1.namedtuple: 生成可以使用名字来访问元素内容的tuple2.deque: 双端队列,可以快速的从另外一侧追加和推出对象3.Counter: 计数器,主要用来计数4.OrderedDict: 有序字典5.defaultdict: 带有默认值的字典1、namedtuple我们知道tuple可以表示不变集合,例如,一个点的二维坐标就可以表示成:>>> p=(2,6)但是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的。这时,namedtuple就派上了用场:from collections import namedtuple point = namedtuple("point", ['x', 'y']) print(point) p_obj = point(6, 8) print(p_obj.x) print(p_obj.y)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py68Process finished with exit code 0类似的,如果要用坐标和半径表示一个圆,也可以用namedtuple定义:# namedtuple('名称', [属性list]):Circle = namedtuple("Circle", ['x', 'y', 'r']) cir = Circle(8, 6, 10) print(cir.x) print(cir.y) print(cir.r)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py8610Process finished with exit code 02、deque使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:from collections import deque q = deque(['a', 'b', 'c']) q.append('d') print(q) q.appendleft('e') print(q) q.pop() print(q) q.popleft() print(q)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py deque(['a', 'b', 'c', 'd']) deque(['e', 'a', 'b', 'c', 'd']) deque(['e', 'a', 'b', 'c']) deque(['a', 'b', 'c']) Process finished with exit code 0deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。3、OrderedDict使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。如果要保持Key的顺序,可以用OrderedDict:from collections import OrderedDict lis = [('a', 21), ('b', 55), ('c', 86)] dic = dict(lis)  # dict的Key是无序的print(dic) ord_dic = OrderedDict(lis)  # OrderedDict的Key是有序的print(ord_dic)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py {'a': 21, 'b': 55, 'c': 86}OrderedDict([('a', 21), ('b', 55), ('c', 86)])Process finished with exit code 0注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序:ord_dic = OrderedDict() ord_dic['z'] = 99ord_dic['y'] = 110ord_dic['z'] = 666print(ord_dic.keys())  # 按照插入的Key的顺序返回结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py odict_keys(['z', 'y']) Process finished with exit code 04、defaultdict 有如下值集合 [11,22,33,44,55,66,77,88,99,90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。即: {'k1': 大于66 , 'k2': 小于66}lis = [11, 22, 33, 55, 77, 66, 88, 99] dic = {}for value in lis:     if value > 66:         if dic.has_key('k1'):             dic['k1'].append(value)         else:             dic['k1'] = [value]     else:         if dic.has_key('k2'):             dic['k2'].append(value)         else:             dic['k2'] = [value]from collections import defaultdictlis = [11, 22, 33, 55, 77, 66, 88, 99]my_dic = defaultdict(lis)for value in lis:    if value > 66:        my_dic['k1'].append(value)    else:        my_dic['k2'].append(value)print(my_dic)使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:from collections import defaultdict dd = defaultdict(lambda: 'N/A') dd['key1'] = 'abc'  # key1存在print(dd['key1']) print(dd['key2'])  # key2不存在,返回默认值print(dd['key3'])结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py abc N/A N/A Process finished with exit code 05、CounterCounter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。from collections import Counter coun = Counter("absdsdsdadsdsa") print(coun)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py Counter({'s': 5, 'd': 5, 'a': 3, 'b': 1}) Process finished with exit code 0创建下面的代码说明了Counter类创建的四种方法:from collections import Counterc = Counter()  # 创建一个空的Counter类print(c)c = Counter('g***d')  # 从一个可iterable对象(list、tuple、dict、字符串等)创建print(c)c = Counter({'a': 4, 'b': 2})  # 从一个字典对象创建print(c)c = Counter(a=4, b=2)  # 从一组键值对创建print(c)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py Counter() Counter({'a': 3, 'l': 2, 'g': 1, 'h': 1, 'd': 1}) Counter({'a': 4, 'b': 2}) Counter({'a': 4, 'b': 2}) Process finished with exit code 0计数值的访问与缺失的键当所访问的键不存在时,返回0,而不是KeyError;否则返回它的计数。计数值的访问from collections import Counter cou = Counter("hello world") print(cou["l"]) print(cou["o"]) print(cou["a"])结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py320Process finished with exit code 0计数器的更新(update和subtract)可以使用一个iterable对象或者另一个Counter对象来更新键值。计数器的更新包括增加和减少两种。其中,增加使用update()方法:计数器的更新(update)from collections import Counter cou = Counter("hello world") cou.update("which")  # 使用另一个iterable对象更新print(cou["h"]) c = Counter("watch") cou.update(c)  # 使用另一个Counter对象更新print(cou["h"])结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py34Process finished with exit code 0减少则使用subtract()方法:计数器的更新(subtract)from collections import Counter c = Counter('which') print(c["h"]) c.subtract('witch')  # 使用另一个iterable对象更新print(c['h']) d = Counter('watch') c.subtract(d)  # 使用另一个Counter对象更新print(c['a'])结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py21-1Process finished with exit code 0键的修改和删除当计数值为0时,并不意味着元素被删除,删除元素应当使用del。 键的删除from collections import Counterc = Counter("abcdcba")print(c)c["b"] = 0print(c) del c["a"]print(c)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py Counter({'a': 2, 'b': 2, 'c': 2, 'd': 1}) Counter({'a': 2, 'c': 2, 'd': 1, 'b': 0}) Counter({'c': 2, 'd': 1, 'b': 0}) Process finished with exit code 0elements()返回一个迭代器。元素被重复了多少次,在该迭代器中就包含多少个该元素。元素排列无确定顺序,个数小于1的元素不被包含。elements()方法 from collections import Counterc = Counter(a=4, b=2, c=0, d=-2)print(list(c.elements()))结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py ['a', 'a', 'a', 'a', 'b', 'b'] Process finished with exit code 0most_common([n])返回一个TopN列表。如果n没有被指定,则返回所有元素。当多个元素计数值相同时,排列是无确定顺序的。most_common()方法from collections import Counterc = Counter('abracadabra')print(c)print(c.most_common())print(c.most_common(3))结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) [('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)] [('a', 5), ('b', 2), ('r', 2)] Process finished with exit code 0浅拷贝copy浅拷贝copyfrom collections import Counterc = Counter("abcdcba")print(c) d = c.copy()print(d)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py Counter({'a': 2, 'b': 2, 'c': 2, 'd': 1}) Counter({'a': 2, 'b': 2, 'c': 2, 'd': 1}) Process finished with exit code 0算术和集合操作+、-、&、|操作也可以用于Counter。其中&和|操作分别返回两个Counter对象各元素的最小值和最大值。需要注意的是,得到的Counter对象将删除小于1的元素。Counter对象的算术和集合操作from collections import Counterc = Counter(a=3, b=1) d = Counter(a=1, b=2)print(c + d)  # c[x] + d[x]print(c - d)  # subtract(只保留正数计数的元素)print(c & d)  # 交集:  min(c[x], d[x])print(c | d)  # 并集:  max(c[x], d[x])结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py Counter({'a': 4, 'b': 3}) Counter({'a': 2}) Counter({'a': 1, 'b': 1}) Counter({'a': 3, 'b': 2}) Process finished with exit code 0其他常用操作下面是一些Counter类的常用操作,来源于Python官方文档Counter类常用操作sum(c.values())  # 所有计数的总数c.clear()  # 重置Counter对象,注意不是删除list(c)  # 将c中的键转为列表set(c)  # 将c中的键转为setdict(c)  # 将c中的键值对转为字典c.items()  # 转为(elem, cnt)格式的列表Counter(dict(list_of_pairs))  # 从(elem, cnt)格式的列表转换为Counter类对象c.most_common()[:-n:-1]  # 取出计数最少的n个元素c += Counter()  # 移除0和负值
  • [交流分享] spring支持的几种bean的作用域
    当通过spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域:singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效其中比较常用的是singleton和prototype两种作用域。对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。来自:https://blog.csdn.net/fangchao2011/article/details/89185365
  • [技术干货] [转载]Python Collections模块
    在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。1.namedtuple: 生成可以使用名字来访问元素内容的tuple2.deque: 双端队列,可以快速的从另外一侧追加和推出对象3.Counter: 计数器,主要用来计数4.OrderedDict: 有序字典5.defaultdict: 带有默认值的字典1、namedtuple我们知道tuple可以表示不变集合,例如,一个点的二维坐标就可以表示成:>>> p=(2,6)但是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的。这时,namedtuple就派上了用场:from collections import namedtuple point = namedtuple("point", ['x', 'y']) print(point) p_obj = point(6, 8) print(p_obj.x) print(p_obj.y)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py <class '__main__.point'>68Process finished with exit code 0类似的,如果要用坐标和半径表示一个圆,也可以用namedtuple定义:# namedtuple('名称', [属性list]):Circle = namedtuple("Circle", ['x', 'y', 'r']) cir = Circle(8, 6, 10) print(cir.x) print(cir.y) print(cir.r)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py8610Process finished with exit code 02、deque使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:from collections import deque q = deque(['a', 'b', 'c']) q.append('d') print(q) q.appendleft('e') print(q) q.pop() print(q) q.popleft() print(q)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py deque(['a', 'b', 'c', 'd']) deque(['e', 'a', 'b', 'c', 'd']) deque(['e', 'a', 'b', 'c']) deque(['a', 'b', 'c']) Process finished with exit code 0deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。3、OrderedDict使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。如果要保持Key的顺序,可以用OrderedDict:from collections import OrderedDict lis = [('a', 21), ('b', 55), ('c', 86)] dic = dict(lis)  # dict的Key是无序的print(dic) ord_dic = OrderedDict(lis)  # OrderedDict的Key是有序的print(ord_dic)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py {'a': 21, 'b': 55, 'c': 86}OrderedDict([('a', 21), ('b', 55), ('c', 86)])Process finished with exit code 0注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序:ord_dic = OrderedDict() ord_dic['z'] = 99ord_dic['y'] = 110ord_dic['z'] = 666print(ord_dic.keys())  # 按照插入的Key的顺序返回结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py odict_keys(['z', 'y']) Process finished with exit code 04、defaultdict 有如下值集合 [11,22,33,44,55,66,77,88,99,90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。即: {'k1': 大于66 , 'k2': 小于66}lis = [11, 22, 33, 55, 77, 66, 88, 99] dic = {}for value in lis:     if value > 66:         if dic.has_key('k1'):             dic['k1'].append(value)         else:             dic['k1'] = [value]     else:         if dic.has_key('k2'):             dic['k2'].append(value)         else:             dic['k2'] = [value]from collections import defaultdictlis = [11, 22, 33, 55, 77, 66, 88, 99]my_dic = defaultdict(lis)for value in lis:    if value > 66:        my_dic['k1'].append(value)    else:        my_dic['k2'].append(value)print(my_dic)使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:from collections import defaultdict dd = defaultdict(lambda: 'N/A') dd['key1'] = 'abc'  # key1存在print(dd['key1']) print(dd['key2'])  # key2不存在,返回默认值print(dd['key3'])结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py abc N/A N/A Process finished with exit code 05、CounterCounter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。from collections import Counter coun = Counter("absdsdsdadsdsa") print(coun)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo005.py Counter({'s': 5, 'd': 5, 'a': 3, 'b': 1}) Process finished with exit code 0创建下面的代码说明了Counter类创建的四种方法:from collections import Counterc = Counter()  # 创建一个空的Counter类print(c)c = Counter('g***d')  # 从一个可iterable对象(list、tuple、dict、字符串等)创建print(c)c = Counter({'a': 4, 'b': 2})  # 从一个字典对象创建print(c)c = Counter(a=4, b=2)  # 从一组键值对创建print(c)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py Counter() Counter({'a': 3, 'l': 2, 'g': 1, 'h': 1, 'd': 1}) Counter({'a': 4, 'b': 2}) Counter({'a': 4, 'b': 2}) Process finished with exit code 0计数值的访问与缺失的键当所访问的键不存在时,返回0,而不是KeyError;否则返回它的计数。计数值的访问from collections import Counter cou = Counter("hello world") print(cou["l"]) print(cou["o"]) print(cou["a"])结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py320Process finished with exit code 0计数器的更新(update和subtract)可以使用一个iterable对象或者另一个Counter对象来更新键值。计数器的更新包括增加和减少两种。其中,增加使用update()方法:计数器的更新(update)from collections import Counter cou = Counter("hello world") cou.update("which")  # 使用另一个iterable对象更新print(cou["h"]) c = Counter("watch") cou.update(c)  # 使用另一个Counter对象更新print(cou["h"])结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py34Process finished with exit code 0减少则使用subtract()方法:计数器的更新(subtract)from collections import Counter c = Counter('which') print(c["h"]) c.subtract('witch')  # 使用另一个iterable对象更新print(c['h']) d = Counter('watch') c.subtract(d)  # 使用另一个Counter对象更新print(c['a'])结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py21-1Process finished with exit code 0键的修改和删除当计数值为0时,并不意味着元素被删除,删除元素应当使用del。 键的删除from collections import Counterc = Counter("abcdcba")print(c)c["b"] = 0print(c) del c["a"]print(c)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py Counter({'a': 2, 'b': 2, 'c': 2, 'd': 1}) Counter({'a': 2, 'c': 2, 'd': 1, 'b': 0}) Counter({'c': 2, 'd': 1, 'b': 0}) Process finished with exit code 0elements()返回一个迭代器。元素被重复了多少次,在该迭代器中就包含多少个该元素。元素排列无确定顺序,个数小于1的元素不被包含。elements()方法 from collections import Counterc = Counter(a=4, b=2, c=0, d=-2)print(list(c.elements()))结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py ['a', 'a', 'a', 'a', 'b', 'b'] Process finished with exit code 0most_common([n])返回一个TopN列表。如果n没有被指定,则返回所有元素。当多个元素计数值相同时,排列是无确定顺序的。most_common()方法from collections import Counterc = Counter('abracadabra')print(c)print(c.most_common())print(c.most_common(3))结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) [('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)] [('a', 5), ('b', 2), ('r', 2)] Process finished with exit code 0浅拷贝copy浅拷贝copyfrom collections import Counterc = Counter("abcdcba")print(c) d = c.copy()print(d)结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py Counter({'a': 2, 'b': 2, 'c': 2, 'd': 1}) Counter({'a': 2, 'b': 2, 'c': 2, 'd': 1}) Process finished with exit code 0算术和集合操作+、-、&、|操作也可以用于Counter。其中&和|操作分别返回两个Counter对象各元素的最小值和最大值。需要注意的是,得到的Counter对象将删除小于1的元素。Counter对象的算术和集合操作from collections import Counterc = Counter(a=3, b=1) d = Counter(a=1, b=2)print(c + d)  # c[x] + d[x]print(c - d)  # subtract(只保留正数计数的元素)print(c & d)  # 交集:  min(c[x], d[x])print(c | d)  # 并集:  max(c[x], d[x])结果:D:\YuchuanProjectData\PythonProject\venv\Scripts\python.exe D:/YuchuanProjectData/PythonProject/YuchuanDemo006.py Counter({'a': 4, 'b': 3}) Counter({'a': 2}) Counter({'a': 1, 'b': 1}) Counter({'a': 3, 'b': 2}) Process finished with exit code 0其他常用操作下面是一些Counter类的常用操作,来源于Python官方文档Counter类常用操作sum(c.values())  # 所有计数的总数c.clear()  # 重置Counter对象,注意不是删除list(c)  # 将c中的键转为列表set(c)  # 将c中的键转为setdict(c)  # 将c中的键值对转为字典c.items()  # 转为(elem, cnt)格式的列表Counter(dict(list_of_pairs))  # 从(elem, cnt)格式的列表转换为Counter类对象c.most_common()[:-n:-1]  # 取出计数最少的n个元素c += Counter()  # 移除0和负值
  • [技术干货] 【转】为什么DevOps落地这么难(上)?
    转自:荣信er          华为云DevCloud                                8月27日我们在学习研究的过程中,大家都在说成功的案例,很少有人讲失败的案例。我担心这会产生一种误导:不管什么企业,什么组织结构,什么技术能力,什么基础设施平台,都可以轻松落地DevOps。个人非常喜欢查理·芒格的逆向思维方式,既然大家都在讲成功的案例,我给大家泼泼冷水,讲讲我所理解和了解的真实情况。作为DevOps的学习和布道者,对DevOps本身没有任何诋毁质疑,只是希望从反面让大家更全面的了解DevOps,不要在错误的时间,以错误的方式,错误地尝试了一下,然后做出了DevOps无用的判断。要谈落地Devops,先来看看什么是Devops。先看下 “官方”解释:·         DevOps(Development和Operations的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。·         它是一种重视“软件开发人员(Dev)”和“IT运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。透过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。·         DevOps不能简单认为是工具、方法、技能或组织结构,DevOps的框架结合所有这一切元素,去建立一个流水线的过程,使业务更快的运营并且更快地应对变化。看完之后是不是一头雾水?这可能是刚接触到DevOps的第一反应(或者说是我当年的第一反应吧)。2009年,Patrick Debois(DevOps之父)在提出Dev和Ops概念时的主要目的是如何在运维工作中应用 Scrum 和其它敏捷实践,为的是促成开发运维合作(打破开发和运维之间的部门墙)。为什么会有部门墙?参考康威定律:“设计系统的架构受制于产生这些设计的组织的沟通结构。”通俗的来讲:产品必然是其(人员)组织沟通结构的缩影。我们来看一个图,更好的理解一下Dev和Ops部门墙产生的原因。传统的Dev 和 Ops 的关注点不同,Dev的关注点是如何开发测试交付新的功能,Ops的关注点是保证站点的稳定和高性能。导致直接的矛盾点表现在以下两方面:(一)在价值流下游的Ops 评审认为价值链上游的 Dev 软件非功能质量不满足要求,因此阻止变更。(二)在价值流上游的 Dev 无法获得价值链下游的 Ops 的真实运行环境,因此无法提升交付质量。于是,逐渐陷入了“无法提升质量”和“ 非功能质量不满足要求 ”的死循环中。这么看,问题是不是清晰了,但是有人又会说,这墙也不是一天两天垒起来的,为什么现在要砸墙了?软件工程方法论从瀑布到敏捷,到目前的DevOps,都不是凭空演进出来的。敏捷的目的是为了打破产品和开发团队之间的部门墙,但是市场变化越来越快,需要更快的交付和反馈,所以只打破产品和开发部门部门墙还不够,现在需要将开发和运维运营也打通。2010 年The Agile Admin 博客发表“ What is DevOps ”。在 DevOpsDays 之后,DevOps 被越来越多的人所熟知并迅速得到了大多数人的认可。2010年,《持续交付》的作者 Jez Humble 参加了第二届的 DevOpsDays 并做了 “持续交付”的演讲。从本质上说《持续交付》中所提到的实践给 Patrick 和 Andrew 最初所遇到的问题给出了最佳实践。理解了DevOps的产生历史和目的,再来看看DevOps具体是什么。DevOps落地由于涉及的内容非常多,所以不同的角色以不同的视角看,基本就是横看成岭侧成峰,远近高低各不同。我们从不同角度和层面来看看什么是DevOps?从上图可以看出,DevOps落地后,人员管理的组织结构会有变化。目前大多数传统IT企业的开发和运维部门的运作模式是共享的运维团队,开发完成后的交付物,交给运维团队负责部署、发布和运维。DevOps推荐的多功能团队类似于图中虚拟运维组的形式,每个开发团队都有自己的运维人员(运维人员少的也要有共享的运维联络人)。这里的运维人员指的是一种角色,有些团队也有全栈工程师,开发测试兼运维。对于中大型的公司,还经常会有基础设施运维团队,提供基础设施即代码等平台化能力。未来随着云原生服务的发展,运维的角色会有更大的转变(打破部门墙的最高境界,干掉运维部门,一切运维服务都是云原生服务)。看完组织结构的变化,再来看技术架构的演进。从技术架构层面看(以Java Web应用为例):随着IT技术的不断发展,应用系统的建设经过单体应用、SOA应用、逐步走向微服务应用。微服务的实施必然要具备需求管理、代码版本管理、质量管理、构建管理、测试管理、部署管理、环境管理等全流程自动化工具链,以及开发部门与运维部门的深度协作。因此,DevOps是微服务实施的充分必要条件。 从信息流转来看,DevOps包含了从需求管理到需求开发、代码管理、基础设施管理、持续集成、自动化测试、持续部署、持续发布和应用运维管理全流程。每个过程都需要DevOps方法和工具的支撑。比如我们需要Git来管理代码,需要根据企业的实际情况寻找合适的分支管理方法;我们需要Jenkins来做持续集成;使用selenium来做自动化测试;需要使用ansible来自动化部署;使用chef或者puppet来管理基础环境等等。理解了Dev和Ops部门墙,然后从人员管理、技术架构、信息流转多个角度看完DevOps,现在我们应该对“什么是DevOps”,“DevOps具体要做什么”有了初步的理解。(对这块感兴趣的,后续会专题介绍。)广义的DevOps涉及的内容极广,理解之后,我们才能更好的分析DevOps难落地的原因。
  • [技术干货] 《ONAP技术详解与应用实践》读书笔记5
    ONAP与相关标准开源组织协同ONAP一直在紧跟标准组织在SDN/NFV方面的进展,并在实施过程中尽量遵循与继承标准已有成果,比如ETSI、MEF、TMF、IETF、3 GPP、BBF等。同时,ONAP还与许多开源社区开展了协同工作,典型的有OpenStack、Kubernetes和OPNFV等。1.5.1 ONAP与ETSI NFV欧洲电信标准组织(ETSI)是电信产业具有全球影响力的电信设备和网络标准制定者。ETSI NFV是NFV领域的标准权威组织。ETSI NFV的标准定义聚焦在VNF和NS(Network Service)的生命周期管理,也就是MANO(NFVO和VNFM在一起的统称)的相关架构和接口。从功能范畴上来说,ONAP的范围远远大于MANO的范畴,ONAP要解决的是全部网络基础设施端到端的自动化运维问题,而MANO仅关注NFV的生命周期自动化。在架构和实现上,ONAP的VF-C模块相当于ETSI的NFVO功能,而VNFM模块一般由厂商来实现,VIM模块一般由云平台供应商来实现。ONAP同厂商特有的VNFM和VIM的集成接口都遵循ETSI NFV的相关标准(SOL003、SOL005等)ONAP在VNF的信息模型和SO、VF-C模块的接口上遵循ETSI NFV的相关标准。ETSI VNF的相关标准还在持续演进中,还有很多标准没有定稿,ONAP同ETSI VNF的关系是互相促进,互相影响的。ONAP的开源实现可能领先于ETSI的标准制定,并促成ETSI相关标准的成熟。1.5.2 ONAP与MEF城域以太网论坛(MEF)是2001年成立的一个专注于解决城域以太网专线业务技术标准的非营利性组织。最近几年MEF的工作重点转移到推动运营商的数字化转型和业务标准定义上来。MEF根据用户和运营商之间的消费关系提出了LSO(Lifecycle Service Orchestration,生命周期服务编排)的概念和对应的参考架构。在Casablanca版本的CCVPN用例中,在External API(北向接口项目中)支持跨运营商的企业以太专线定义中,参考了MEF的Interlude(MEF中定义的,用于Service Orche-strator间交互接口的API标准名)接口标准。1.5.3 ONAP与TMFTMF(TeleManagement Forum,电信管理论坛)是一个为电信运营和管理提供策略建议和实施方案的世界性组织,是专注于通信行业OSS和管理问题的全球性非营利性社团联盟。TMF提出的NG OSS(New Generation Operations Systems and Software,下一代运维系统)功能模型,包括TOM(Telecom Opera-tions Map,电信运营图)和eTOM(enhanced Telecom Operations Map,增强电信运营图),被国际电信运营商、设备制造商及电信运营支撑系统开发商广泛接受,成为事实上的国际标准。2018年3月,ONAP与TMF宣布正式合作。TMF开放API成为ONAP Beijing版本(2018年6月发布)的重要组成部分。在ONAP的Casablanca版本的CCVPN用例中,External API(北向接口项目中)实现对TMF接口标准的框架支持,包括为了实现跨ONAP的通信,支持了TMT 641(业务订单接口)标准,后续还会支持TMF 633(目录接口)、TMF638(业务状态变更通知)等标准接口。1.5.4 ONAP与IETFIETF负责互联网标准的开发和推动。IETF制定了TCP、IP、MPLS等关键互联网协议。IETF面向SDN各技术领域开展标准化工作,IETF的SDN参考架构已基本成为SDN的主流标准架构。IETF定义了网络配置模型语言YANG,并且定义了很多网络资源和业务模型,比如L3VPN、L2VPN、L1VPN等。SDN控制器北向接口的配置模型,一般会遵照IETF模型。ONAP同SDN厂商进行对接时,一般采用IETF定义的RestConf接口和对应的YANG模型。在Casablanca版本的CCVPN用例中,ONAP同OTN控制器的接口采用了IETF定义的ACTN(Abstraction and Control of TE networks)相关标准,包括拓扑模型、业务模型等。1.5.5 ONAP与3GPP3GPP是1998年全球各大标准组织为了协同3G标准合作建立的组织。3GPP成立后就成为无线通信领域的权威组织,并制定了WCDMA、TD-SCDMA等3G标准,以及4G标准LTE和最新的5G标准。2018年3GPP发布了首个5G标准版本R15,标志着世界正式进入5G时代。4G改变生活,5G改变社会。5G的基站网络规模会大大超过4G的;5G大量采用虚拟化技术来实现核心网业务;5G要求支持网络切片(Network Slicing);5G的基站分成DU和CU等,这类新的特点导致5G的自动化运维成为一个很大的挑战。5G是ONAP的一个核心应用场景,5G蓝图是ONAP持续多个版本的蓝图。3GPP也成立专门的工作组来研究5G同ONAP集成的运维架构。1.5.6 ONAP与BBFBBF(Broadband Forum,宽带论坛)是1994年成立的全球标准组织,聚焦在定义宽带接入的相关技术,比如DSL和PON等。BBF近年来积极推动把NFV引入电信机房,提出CloudCO(Cloud Central Office)架构。ONAP社区的vCPE和BBS两个蓝图,都是聚焦在未来的家庭宽带业务场景,相关标准参照BBF。1.5.7 ONAP与OpenStackOpenStack是当前最主流的开源云计算基础设施管理平台.电信运营商的NFVi基础设施普遍采用OpenStack作为云操作系统,提供虚拟机的编排管理和虚拟网络资源的配置管理等功能。ONAP从第一个版本开始就在MultiVIM项目中支持与OpenStack的集成,多数组件也同时支持通过OpenStack的Heat脚本进行部署管理。从Beijing版本开始ONAP支持通过OOM集成的Kubernetes实现容器化部署与管理。1.5.8 ONAP与KubernetesKubernetes(K8s)是Google开源的一个容器编排引擎,目前是CNCF(云原生云计算基金会)基金会下面的项目。K8s是集群中负责管理跨多台主机容器化应用的开源系统,支持自动化部署、大规模可伸缩、应用容器化管理,其目标是让部署容器化的应用简单且高效。K8s目前已是面向云原生的应用,是容器化部署场景的最热门的开源项目,尤其是从VNF向CNF(云原生网络功能)演进的过程,K8s被认为是默认配套。ONAP在很多项目中都在开展与K8s的集成,包括Multi-VIM项目、OOM项目等。OOM对ONAP的支持就是通过K8s实现的,使用了Rancher(容器管理平台)、Helm、Kubectl等组件。1.5.9 ONAP与OPNFVOPNFV(Open Platform for NFV)专注于加速NFV的发展,其目标是建立一个运营商级的、集成的开源参考平台。OPNFV是一个集成型的开源项目,成立多年,在NFV和NFVi的功能测试、性能测试上积累了大量的测试工具和测试用例。2018年OPNFV成立OPNFV Verified Program(OVP)认证项目,针对商用VIM产品进行认证。LFN成立以后,ONAP对NFV的认证和OPNFV对VIM的认证将统一运作,在LFN成立统一的CVC(Compliance andVerification Committee)进行管理。
  • [热门活动] Volcano:带你体验容器与批量计算的碰撞的火花
    历史在分析趋势之前,我们先看一下分布式调度系统的历史。早期分布式调度系统以批处理系统为主,例如九几年的LSF/SGE/PBS等,这些批处理系统大规划的使用在HPC领域,而且对作业级的调度进行大量的研究工作;后续由批处理系统延伸出多集群、多组织资源共享的需求,便成了网络计算。网络计算与云计算最大的不同是:网络计算强调多组织的资源共享,而云计算强调云厂商的集中式支持;这也是云计算成为主流的主要原因:多组织之间共享需要完备的协议和足够的安全支持,而云服务仅需要对用户提供相应服务和安全,并不需要在多个云厂商之间进行共享;随着开源社区的发展,再将应用接口逐步统一,e.g. Kubernetes。Hadoop出现后,不仅推动了分布式调度系统中对数据的处理,同时也推动了开源软件的生态。2012和2014是两个重要的节点,Hadoop将资源管理层与领域框架层分开,随后的领域框架也有机会构建自己的生态,e.g. Spark;同时,将资源管理层与领域框架分开也被广泛认可。在容器及Kuberentes流行后,凭借其高资源利用率与隔离,环境标准化等优势,越来越多的人希望将这些批量计算应用统一到 Kubernetes 平台上。未来的趋势多种应用统一调度随着各行各业的发展,涌现出越来越多的领域框架来支持业务的发展;这些框架都在相应的业务领域有着不可替代的作用,e.g. Spark, Tensorflow, Flink等。在业务复杂性能不断增加的情况下,单一的领域框架很难应对现在复杂的业务场景;因此现在普遍使用多种框架达成业务目标,如下图所示。但随着各个领域框架集群的不断扩大,以及单个业务的波动性,各个子集群的资源浪费比较严重;因此越来越多的用户希望通过统一调度系统来解决资源共享的问题。在技术选型上,Kubernetes凭借其优秀的扩展性获得大部分用户青睐。异构硬件在批量计算任务向云原生环境迁移的过程中,对云原生环境的算力提出了新的要求;各个厂商为了应对这些新的需求,为各个场景提供了不同架构的硬件,例如 鲲鹏,昇腾,X86,GPU等。当多种应用运行在统一平台上时,需要云原生调度系统能够对异构硬件资源进行统一的管理与调度,使用各种应用达到最优的资源配比。目前,硬件的信息通过kubernetes的 device plugin 机制提供,但Kubernetes的 device plugin 仍有一些不足,例如 无法很好的支持硬件拓扑。在调度方面 Volcano 已经支持主流的调度策略,并在最新的1.0版本中支持了 GPU 共享,大大增加了GPU的利用率,有效降低了GPU的使用成本。跨集群/跨云跨集群一直是分布调度系统解决大规模、灾备等问题的主要解决方案;同时,为了降低厂商绑定的风险,并最大限度兼顾不同云厂商的优势,多云环境下的负载高效分发逐渐成为趋势。在多云的环境中,面向数据位置的优化,作业执行时间预估等问题都是需要调度系统解决的问题;在 Volcano 中,将通过多个项目实现跨集群、跨云的作业调度,例如 JobForward (#880)。智能化调度算法在分布调度系统中有大量的研究,从早期的批处理系统到近期的Borg,Volcano等;早期的批处理系统以特定场景的算法优化为主,对于复杂的场景需要大量的计算,虽然有大量针对HPC和网络的调度优化,但常用和落地的算法比较少。随着人工智能的发展,越来越多的调度系统将会使用AI相应的能力对算法进行优化;在 Volcano 中,将通过AI的能力驱动 Volcano 中各个调度算法进行优化,并通过AI的能力提供新的调度算法。总结分布式调度系统是一个复杂的系统,需要多个组件共协作以提高整体的效率,例如 应用管理,调度,异构硬件管理,存储等,仅靠调度器无法完成这些工作。Volcano 作为CNCF首个面向批量计算的分布式调度系统,包含了应用管理,作业调度,异构硬件等多个组件和功能;其调度器兼容kubernetes调度策略,同时支持在线、离线两种作业类型;控制器提供了统一的作业管理,支持多种作业的接入,包括 MPI, Tensorflow, MidSpore, Spark 等;设备插件提供了对异构硬件的支持,例如 1.0 版中支持了 GPU 共享。因此,Volcano面向分布式调度系统的趋势提供了完整的方案,可以在多种场景下提高作业性能,资源使用率等。Volcano特训营:六节课学懂容器批量计算由Volcnao项目发起者马达主讲的直播课程正在进行中,课程共有6期,从技术原理到实战演练,涵盖Volcano全景。锁定后续课程信息,获取往期回放与讲师PPT,请假助手微信(k8s2222)并备注“Volcano”。
总条数:888 到第
上滑加载中