当前位置: 首页 > news >正文

《DevOps实践指南》- 读书笔记(四)

DevOps实践指南

    • Part 3 第一步 :流动的技术实践
    • 11. 应用和实践持续集成
      • 11.1 小批量开发与大批量合并
      • 11.2 应用基于主干的开发实践
      • 11.3 小结
    • 12. 自动化和低风险发布
      • 12.1 自动化部署流程
        • 12.1.1 应用自动化的自助式部署
        • 12.1.2 在部署流水线中集成代码部署
      • 12.2 将部署与发布解耦
        • 12.2.1 基于环境的发布模式
        • 12.2.2 基于应用的发布模式更安全
      • 12.3 持续交付和持续部署实践的调查
      • 12.4 小结
    • 13. 降低发布风险的架构
      • 13.1 能提高生产力、可测试性和安全性的架构
      • 13.2 架构原型:单体架构与微服务
      • 13.3 安全地演进企业架构
      • 13.4 小结

<- 接前文 ->

Part 3 第一步 :流动的技术实践

第三部分的目标是创建必要的技术实践和架构,从而使开发到运维的工作能够稳定地快速流动,并确保不会造成生产环境的混乱或客户服务的中断。这意味着需要降低在生产环境中部署和发布变更的风险。这一点可以通过一套被称为持续交付的技术实践来实现。

11. 应用和实践持续集成

分支在版本控制系统中的主要作用是,让开发人员可以并行地工作在软件系统的各个组成部分,同时避免开发人员提交的代码对主干(trunk,有时候也被称为 master 或 mainline)的稳定性造成影响,或者引入错误。

然而,开发人员在自己的分支上独自工作的时间越长,就越难将变更并入主干。事实上,当分支个数和每个分支上的变更数同时增加时,合并难度会骤增。

集成问题会导致大量的返工,包括不得不通过手动合并解决变更冲突,以及多名开发人员共同解决导致自动化测试或手动测试失败的合并问题。因为在传统的开发模式里,代码集成工作通常发生在项目的末期,所以在集成工作消耗过多时间时,我们不得不为了按时发布而偷工减料。

这会导致另一个恶性循环:既然合并代码如此痛苦,那么大家索性就减少合并次数,而这会使未来的合并工作更加令人痛苦。持续集成旨在通过将合并融入日常工作来解决这个问题。

11.1 小批量开发与大批量合并

每当提交到版本控制系统的代码变更导致部署流水线失败时,我们就会群策群力地解决问题,力求尽快将部署流水线恢复到绿色状态。然而,如果开发人员长时间工作在自己的分支(也称为“特性分支”)上,只是偶尔将代码合并到主干,那么他们的每一次合并都会为主干引入大批量的变更,这会造成严重的问题。

尽管分支策略有很多种,但是可以分为以下两类

  • 提高个人生产力:所有人都在自己的分支上工作。每个人都独立地工作,并且不能干扰其他人;然而,代码合并将是一场噩梦。协作将变得相当困难,每个人都不得不谨小慎微地合并代码,即便是完成系统里最小的部分也是如此
  • 提高团队生产力:所有人都在同一个区域里工作。并没有分支,只有一条很长、不可被中断的主干;也没有规则,因此代码的提交过程很简单。但是,任何一次提交都有可能破坏整个项目,同时导致项目中断。

Ward Cunningham 开发了世界上第一个维基系统,也创造了“技术债务”一词。他在描述技术债务时说,如果不能主动地重构代码库,它就会慢慢地变得难以修改和维护,新特性的增加速度也会因此而下降。持续集成和基于主干的开发实践,其主要目的就是解决这些问题,从而在提高个人生产力的基础之上提高团队生产力

11.2 应用基于主干的开发实践

解决大批量合并问题的对策是,应用持续集成和基于主干的开发实践,让每个开发人员每天都至少向主干提交一次代码。这样做能够将代码提交量降低为开发团队每日的工作量。开发人员提交得越频繁,每次的提交量就越小,他们离理想的单件流状态也就越近。

频繁地向主干提交代码,意味着可以针对整个软件系统执行所有的自动化测试,并且在应用或接口的某个部分出现问题时,及时收到告警信息。由于合并问题能被及时发现,因此也能被及时解决。

我们甚至可以对部署流水线进行这样的配置:拒绝接受任何使系统偏离可部署状态的提交(例如代码变更或环境变更)。这种方式被称为门控提交,即部署流水线要确认所提交的变更能成功合并和正常构建,并且在合并到主干之前就已经通过了所有的自动化测试。如果测试失败,则开发人员将收到通知,这样就可以在不影响价值流中的其他人的情况下自己解决问题。

应用这些实践后,我们再来修订“完成”的定义(黑体文字为新增内容):“在每个迭代周期结束时,已经在类生产环境中集成和测试了可工作和可交付的代码;这些代码通过一键式流程在主干上创建,并已通过自动化测试。

11.3 小结

基于主干的开发方式可能是本书中最具争议的实践。许多工程师都认为它行不通,他们更喜欢在自己的分支上工作,不必与其他开发人员协作。然而,Puppet Labs 的《2015 年 DevOps 现状报告》表明,基于主干的开发方式能带来更高的生产力、更好的稳定性,甚至更高的工作满意度和更低的职业倦怠率。

虽然在开始时很难说服开发人员,但是一旦他们认识到显著的优势,就会彻底改变。持续集成实践为下一步实现低风险的自动化部署流程铺平了道路。

12. 自动化和低风险发布

本章旨在通过减小生产环境部署的阻力,使运维团队或开发团队能频繁、轻松地进行部署。我们通过扩展部署流水线来实现这一点。

与仅将代码持续集成到类生产环境中不同,我们将能够按需地(即一键式发布)或自动化地(即在构建和测试成功以后,直接进行自动化部署)将已通过自动化测试和验证流程的任何构建版本发布到生产环境中。

12.1 自动化部署流程

当完整记录目前的部署流程以后,下一步的目标便是尽可能地简化和自动化手动步骤,举例如下:

  • 将代码打包成便于部署的格式;
  • 创建预配置的虚拟机镜像或容器;
  • 将中间件的部署和配置自动化;
  • 将安装包或者文件复制到生产服务器;
  • 重启服务器、应用或者服务;
  • 基于模板生成配置文件;
  • 通过执行自动化冒烟测试,确保系统能正常运行,并且配置正确;
  • 运行各种测试程序;
  • 将数据库迁移工作脚本化和自动化。

大多数具有持续集成和测试功能的工具,也有扩展部署流水线的能力。通常在生产验收测试执行完之后,这些工具可以将验证过的构建版本发布到生产环境中(这样的工具包括 Jenkins Build Pipeline插件、ThoughtWorks的GoCD和Snap CI、Microsoft Visual Studio Team Services,以及Pivotal Concourse)

部署流水线有如下需求

  • 用相同的方式处理所有环境的部署:通过对所有环境(例如开发环境、测试环境和生产环境)采用相同的部署机制,可以提高生产环境部署的成功率,因为它已经在流水线中被成功地部署过很多次了。
  • 对部署执行冒烟测试:在部署过程中,应该测试依赖的所有系统(例如数据库、消息总线和外部服务)是否能正常访问,并通过单次测试看看系统是否能正常工作。如果以上任何一个测试失败,那么部署就是失败的。
  • 维持环境的一致性:上述步骤创建了一步搭建环境的流程,使得开发环境、测试环境和生产环境有了共同的搭建机制。必须持续保证这些环境的搭建方式是一致的

12.1.1 应用自动化的自助式部署

为了更好地促进工作,需要一个可以由开发人员或运维人员来执行的代码发布流程,并且在理想情况下,应该不需要任何手动操作或工作交接。这个流程的步骤如下。

  • 构建:部署流水线必须基于版本控制系统构建可部署到任何环境(包括生产环境)的软件包。
  • 测试:任何人都应该能够在他们的工作站上或测试系统中运行任何一个自动化测试套件。
  • 部署:任何人都应该能够将这些软件包部署到具有访问权限的任何环境,通过执行(已提交到版本控制系统中的)脚本来完成部署。

以上实践有助于成功地执行部署,谁来执行并不重要。

12.1.2 在部署流水线中集成代码部署

如果代码部署过程是自动化的,就能将其变成部署流水线的一部分。因此,自动化部署必须具备如下能力:

  • 保证在持续集成阶段构建的软件包可以部署到生产环境中;
  • 使生产环境的就绪情况一目了然;
  • 为能在生产环境中部署的任何代码,建立一键式和自助式的发布机制;
  • 自动记录审计和合规管理所需的相关内容,包括在哪台机器上运行了命令,运行了什么命令,是谁授权的,以及结果如何;
  • 通过冒烟测试验证系统正常工作,并且数据库连接字符串等配置正确;
  • 为开发人员快速提供反馈,使他们能够尽快了解部署结果(例如部署是否成功,应用是否能在生产环境中正常运行,等等)

我们的目标是实现快速部署——不用等待数小时之后才知道部署是否成功,也不用在修复代码上耗费数小时。运用 Docker 等容器技术,可以在几秒钟或几分钟内完成很复杂的应用部署。

在这里插入图片描述
通过构建上述能力,能够实现一键式代码部署,通过部署流水线将代码和环境变更一起安全、快速地发布到生产环境中

12.2 将部署与发布解耦

在实践中,人们通常交替使用“部署”和“发布”这两个词。然而,它们其实是不同的动作,并且有着截然不同的目标。

  • 部署是指在特定的环境中安装指定版本的软件(例如,将代码部署到集成测试环境中或生产环境中)。具体地说,部署可能与某个特性的发布相关,也可能无关。
  • 发布是指把一个特性(或者一组特性)提供给所有客户或者一部分客户(例如,向 5%的客户群开放特性)。代码和环境架构要能够满足这种要求:特性发布不需要变更应用的代码。

换句话说,如果我们混淆了部署和发布,就很难界定到底由谁来对结果负责。解耦这两个活动,可以提升开发人员和运维人员快速且频繁部署的能力,同时使产品负责人承担成功发布的责任(即确保构建和发布特性所花的时间是有价值的)。

如果部署周期过长,就会限制向市场频繁地发布新特性的能力。然而,假如能够做到按需部署,那么何时向客户发布新特性,就成了业务和市场决策,而不再是技术决策。通常使用的发布模式有以下两种

  • 基于环境的发布模式:在两个或更多的环境中部署系统,但实际上只有一个环境处理客户流量(例如,通过配置负载均衡器切换流量)。将新的代码部署到非生产环境中,然后再把生产流量切换到这个环境。这种模式非常强大,因为一般只需要对应用做很少的改变,或者几乎不用改变。这种模式包括蓝绿部署、金丝雀发布和集群免疫系统。我们随后将讨论这些模式。
  • 基于应用的发布模式:对应用进行修改,从而通过细微的配置变更,选择性地发布或开放应用特性。例如,可以通过特性开关逐渐地开放新特性——先开放给开发团队,再开放给所有内部员工,然后开放给 1%的客户;或者在确认特性完全符合设计后,直接发布给全体客户。这就是所谓的黑启动技术——在生产环境里将所有特性都部署完毕,并在发布前用生产环境的流量做测试。例如,在发布前的几周里,用生产环境的流量来测试新特性,以便在正式发布之前发现和解决所有问题。

12.2.1 基于环境的发布模式

解耦部署和发布将极大地改变我们的工作方式。我们不再需要为了降低对客户可能造成的负面影响而在三更半夜或周末做部署。相反,我们可以在正常的工作时段里进行部署。运维人员终于能像其他人一样正常下班了。

基于环境的发布模式,这种发布模式不需要更改应用的代码。我们使用多套环境来部署,但实际上只有一套环境处理客户流量。这种方式可以显著地降低生产环境发布的风险,并缩短部署时间。

  1. 蓝绿部署模式
    蓝绿部署是 3 种模式中最简单的一种。在这种模式下,我们有两个生产环境:蓝环境和绿环境。在任一时刻,只有其中的一个环境处理客户流量。在图 12-5 中,处理客户流量的是绿环境。
    在这里插入图片描述
    在发布新版本的服务时,先把它部署到非在线环境,以便在不影响用户体验的情况下执行测试。在确信一切都正常以后,再把客户流量切换到蓝环境,用这种方式来交付新版本。之后,蓝环境就变成了生产环境,绿环境则变为预生产环境。通过把客户流量再重定向回绿环境,还可以实现回滚。

    蓝绿部署模式比较简单,也非常易于在已有的系统中实现。它有很多好处,例如能使团队在正常的工作时段内执行部署工作,并在非高峰时段里轻松地实施版本切换(如变更路由配置或符号链接)。仅这些就能使部署团队的工作境遇得到巨大的改善。

  2. 处理数据库变更
    当应用的两个版本依赖同一个数据库时,就会出现问题。如果部署操作需要更改数据库模式,或者添加、修改或删除表或列,那么数据库将无法同时支持应用的两个版本。一般通过下面两种方法来解决这个问题。

    • 创建两个数据库(即蓝数据库和绿数据库):应用的每个版本——蓝色(旧版本)和绿色(新版本)——都有自己的数据库。在发布期间,将蓝数据库设置为只读模式,然后执行备份,再恢复到绿数据库,最后将流量切换到绿环境。这种模式的问题是,如果需要回滚到蓝色版本,就必须先手动地把事务数据从绿数据库迁移回蓝数据库,否则可能丢失这些数据。
    • 将数据库变更与应用变更解耦:与支持两个版本的数据库不同,通过执行以下两项操作,将数据库的变更发布和应用的变更发布解耦:首先,只对数据库进行增量式变更,不更改已有的数据库对象;其次,应用逻辑对生产环境里的数据库版本不做假设。这与我们对数据库一贯的思维方式有很大差异,这样做就避免了产生重复数据。
  3. 金丝雀发布模式和集群免疫系统发布模式
    蓝绿部署模式实现起来比较简单,而且可以显著地提高软件发布的安全性。它有一些变体,能通过自动化进一步提高安全性和缩短部署时间,但同时可能引入复杂性。

    金丝雀发布这个术语来自于煤矿工人把笼养的金丝雀带入矿井的传统。矿工通过金丝雀来了解矿井中一氧化碳的浓度。如果一氧化碳的浓度过高,金丝雀就会中毒,从而使矿工知道应该立刻撤离。

    金丝雀发布模式下,我们会监控软件在每个环境中的运行情况。一旦出现问题,就回滚;否则就在下一个环境中进行部署。
    在这里插入图片描述

    • A1 组:仅向内部员工提供服务的生产环境服务器。
    • A2 组:仅向一小部分客户提供服务的生产环境服务器,在软件达到某些验收标准后部署(自动化部署或手动部署均可)。
    • A3 组:其余的生产环境服务器,软件在 A2 组中达到某些验收标准后再部署。

    集群免疫系统发布模式扩展了金丝雀发布模式,将生产环境的监控系统和发布流程联系起来,并在面向用户的生产系统的性能超出预定范围时(如新用户的转化率低于 15%~20%),自动回滚代码。这种保护措施有两个明显优势:首先,避免了通过自动化测试难以发现的缺陷,例如使某些关键的页面元素不可见的页面变更(如 CSS 代码变更);其次,减少了排查和解决变更造成的性能下降问题所需的时间。

12.2.2 基于应用的发布模式更安全

上一小节介绍了基于环境的发布模式。它的特点是,通过使用多个环境并在其间切换流量,实现部署与发布的解耦。这是完全能在基础设施层面上实现的

本小节将介绍基于应用的发布模式,通过代码来更灵活、更安全地向客户发布新特性(通常是逐一发布特性)。因为基于应用的发布模式是在应用的代码里实现的,所以需要开发团队的参与

  1. 实现特性开关
    基于应用的发布模式主要是通过特性开关来实现的。特性开关机制使我们能在不进行生产环境代码部署的情况下,选择性地启用和禁用特性。通过特性开关,可以将应用的特性向某些特定用户(例如内部员工和某些客户群)开放。

    特性开关的实现机制通常是用条件语句封装应用逻辑或用户界面元素,并根据保存在某处的配置信息启用或禁用某个特性。可以使用简单的应用配置文件(例如 JSON 或 XML 格式的配置文件)存储配置信息,也可以通过服务目录来配置,甚至可以专门设计用于管理特性开关的Web 服务

    特性开关还具有如下优势

    • 轻松地回滚
    • 缓解性能压力
    • 采用面向服务架构提高恢复能力
    • 特性开关将代码部署与特性发布解耦
  2. 实现黑启动
    特性开关实现的效果是,将特性部署到生产环境中,但暂时使其不可用。它使黑启动技术成为可能——先把所有特性都部署到生产环境中,然后对客户不可见的特性执行测试。对于大规模或高风险的变更来说,黑启动过程往往持续数周,从而保证在正式发布之前使用类生产负载安全地进行测试。

    假设我们使用黑启动技术发布了一个有很大潜在风险的新特性,如新的搜索功能、账户创建流程或数据库查询。在将所有代码都部署到生产环境中之后,禁用新特性,然后通过修改用户会话代码调用新函数,不向用户显示调用结果,而仅记录或丢弃测试结果。

    通过这种方式,我们再也不用等到大规模的发布以后才能验证客户对产品的满意度。相反,在宣布进行重大发布时,我们已经完成了对业务假设的验证,并且在真实的客户中进行了无数次的改良实验,这些措施有助于提高产品和客户需求的匹配度

12.3 持续交付和持续部署实践的调查

持续交付和持续部署的新定义如下

  • 持续交付是指,所有开发人员都在主干上进行小批量工作,或者在短时间存在的特性分支上工作,并且定期向主干合并,同时始终让主干保持可发布状态,并能做到在正常的工作时段里按需进行一键式发布。开发人员在引入任何回归错误时(包括缺陷、性能问题、安全问题、可用性问题等),都能快速得到反馈。一旦发现这类问题,就立即加以解决,从而保持主干始终处于可部署状态。持续交付可以自动把已验证的代码发布到企业自己的存储库。
  • 持续部署是指,在持续交付的基础上,由开发人员或运维人员自助式地定期向生产环境部署优质的构建版本,这通常意味着每天每人至少做一次生产环境部署,甚至每当开发人员提交代码变更时,就触发一次自动化部署。

持续交付是持续部署的前提条件,就像持续集成是持续交付的前提条件一样。持续部署更适用于交付线上的 Web 服务,而持续交付适用于几乎任何对质量、交付速度和结果的可预测性有要求的低风险部署和发布场景,包括嵌入式系统、商用现货产品和移动应用。

12.4 小结

发布和部署不一定是高风险、状况百出的工作,也不一定需要几十个甚至几百个工程师加班加点地完成。相反,它们可以成为日常工作的一部分。将发布和部署融入日常工作,能够把部署时间从几个月缩短到几分钟,使组织能够快速地向客户交付价值,同时避免意外事故和服务中断。此外,开发人员和运维人员的紧密合作,能使运维工作变得人性化。

13. 降低发布风险的架构

本章将介绍可以逆转上述恶性循环的措施,同时回顾一些主要的架构原型,探究有助于提高开发生产力、可测试性、可部署性和安全性的架构特性,以及相关的架构迁移策略,以便从任何现有架构安全地迁移至能更好地实现组织目标的架构

13.1 能提高生产力、可测试性和安全性的架构

紧耦合架构不仅会降低生产力,还会影响安全变更的能力。接口定义清晰的松耦合架构则与之相反,它优化了模块间的依赖关系,提高了生产力和安全性,让小型且高产的“双比萨”团队可以执行小的变更,并能安全和独立地进行部署。因为每个服务都有一个定义明确的 API,所以更容易测试,团队之间的服务等级协议条款也更容易确定。

Google Cloud Datastor是世界上最大的一个 NoSQL 服务,但其支持团队只有大约 8 个人,这主要是因为它是构建在一层层可靠的基础服务之上的。面向服务的架构能让小型团队各自负责更小、更简单的开发任务,并且每个团队都可以独立、快速和安全地进行部署。
在这里插入图片描述

13.2 架构原型:单体架构与微服务

单体架构的本质并不坏。事实上,在产品生命周期的早期阶段,单体架构通常是最佳的选择。

适用于创业公司的单体架构(例如,需要为新特性快速创建原型,或者公司的战略目标可能出现重大改变)完全不同于拥有数百个开发团队的公司所采用的架构,后者的每一个团队都要能够独立地向客户交付价值。通过采用与时俱进的演进式架构,能够确保组织当下的需求得到满足。
在这里插入图片描述

13.3 安全地演进企业架构

如果确信已有的架构过于紧耦合,那么可以在其基础上安全地解耦部分功能。通过这种方式,负责这些功能的开发团队能够独立且安全地进行开发、测试和部署,同时减少了架构的熵。

如前所述,绞杀者应用模式涉及用 API 封装已有功能,并按照新架构实现新的功能,仅在必要时调用旧系统。在绞杀者应用模式下,所有服务都通过版本化 API 访问,也称为版本化服务不可变服务

版本化 API 能够在不影响调用者的情况下变更服务,这降低了系统的耦合度。如果需要修改参数,就创建一个新的 API 版本,并将依赖该服务的团队迁移至新版本。如果允许新的应用与其他任何服务发生紧耦合(例如直接连接到另一个服务的数据库),那么我们将无法实现重构架构的目标

通过不断地从已有的紧耦合系统中解耦功能,工作被逐渐转移到一个安全且充满活力的生态系统中,这使开发人员的生产力大大提高,同时已有的应用功能逐渐萎缩。当所有业务功能都迁移至新架构之后,旧应用甚至可能完全消失。

绞杀者应用这一术语。这源于他在澳大利亚旅行时由当地藤类绞杀植物得到的启发。他写道:“它们的种子落在无花果树的顶部,然后藤蔓逐渐沿树干向下生长,最后在土壤中生根。多年以后,藤蔓形成奇妙和美丽的形状,但同时绞杀了其宿主树。”

通过创建绞杀者应用,可以避免运用新架构或新技术复制已有功能。现有系统本身的特点使得业务流程变得过于复杂,因此复制现有流程不可取(通过研究用户,往往能够重新设计业务流程,用更简单的流程来实现业务目标)。

与其他任何转型一样,我们要力求速战速决,并在迭代中持续交付价值。前期分析有助于识别出最小的突破口,让新架构有效地帮助我们实现业务目标。

13.4 小结

在很大程度上,服务赖以生存的架构决定了代码的测试和部署方式。这一点已经在 Puppet Labs 的《2015 年 DevOps 现状报告》中得到了验证。该报告显示,架构是影响工程师生产力的首要因素,它还决定了是否能快速和安全地实施变更。

因为我们通常受制于追求不同方向的组织目标和长期存在的传统架构,所以必须安全地进行架构演进。本章介绍的案例描述了绞杀者应用模式等技术,这些技术可以帮助我们逐步地推进架构转型,从而跟上组织需求的变化

相关文章:

《DevOps实践指南》- 读书笔记(四)

DevOps实践指南 Part 3 第一步 &#xff1a;流动的技术实践11. 应用和实践持续集成11.1 小批量开发与大批量合并11.2 应用基于主干的开发实践11.3 小结 12. 自动化和低风险发布12.1 自动化部署流程12.1.1 应用自动化的自助式部署12.1.2 在部署流水线中集成代码部署 12.2 将部署…...

盲打键盘的正确指法指南

简介 很多打字初学者&#xff0c;并不了解打字的正确指法规范&#xff0c;很容易出现只用两根手指交替按压键盘的“二指禅”情况。虽然这样也能实现打字&#xff0c;但是效率极低。本文将简单介绍盲打键盘的正确指法&#xff0c;以便大家在后续的学习和工作中能够提高工作效率…...

【MySQL】索引 详解

索引 详解 一. 概念二. 作用三. 使用场景四. 操作五. 索引背后的数据结构B-树B树聚簇索引与非聚簇索引 一. 概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各…...

怎么通过ip地址连接共享打印机

在现代办公环境中&#xff0c;共享打印机已成为一种常见的需求。通过共享打印机&#xff0c;多个用户可以在网络上共享同一台打印机&#xff0c;从而提高工作效率并减少设备成本。下面虎观代理小二二将介绍如何通过IP地址连接共享打印机。 确定打印机的IP地址 首先&#xff0…...

迅为i.MX8mm小尺寸商业级/工业级核心板

尺寸&#xff1a; 50mm*50mm CPU&#xff1a; NXP i.MX8M Mini 主频&#xff1a; 1.8GHz 架构&#xff1a; 四核Cortex-A53&#xff0c;单核Cortex-M4 PMIC&#xff1a; PCA9450A电源管理PCA9450A电源管理NXP全新研制配&#xff0c;iMX8M的电源管理芯片有六个降压稳压器、五…...

vue中v-for循环数组使用方法中splice删除数组元素(错误:每次都删掉点击的下面的一项)

总结&#xff1a;平常使用v-for的key都是使用index&#xff0c;这里vue官方文档也不推荐&#xff0c;这个时候就出问题了&#xff0c;我们需要key为唯一标识&#xff0c;这里我使用了时间戳&#xff08;new Date().getTime()&#xff09;处理比较复杂的情况&#xff0c; 本文章…...

Python用GAN生成对抗性神经网络判别模型拟合多维数组、分类识别手写数字图像可视化...

全文链接&#xff1a;https://tecdat.cn/?p33566 生成对抗网络&#xff08;GAN&#xff09;是一种神经网络&#xff0c;可以生成类似于人类产生的材料&#xff0c;如图像、音乐、语音或文本&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 相关视频 最近我们…...

嵌入式Linux驱动开发(LCD屏幕专题)(一)

一、LCD简介 总的分辨率是 yres*xres。 1.1、像素颜色的表示 以下三种方式表示颜色 1.2、如何将颜色数据发送给屏幕 每个屏幕都有一个内存&#xff08;framebuffer&#xff09;如下图&#xff0c;内存中每块数据对用屏幕上的一个像素点&#xff0c;设置好LCD后&#xff…...

uniapp搜索功能

假设下方数据是我们从接口中获取到的&#xff0c;我们需要通过name来搜索&#xff0c;好我们看下一步。 data: [{"id": 30,"category_id": 3,"name": "日常家居名称","goods_num": 20,"integral_num": 20,&q…...

iframe 实现跨域,两页面之间的通信

一、 背景 一个项目为vue2&#xff0c;一个项目为vue3&#xff0c;两个不同的项目实现iframe嵌入&#xff0c;并实现通信 二、方案 iframe跨域时&#xff0c;iframe组件之间常用的通信&#xff0c;主要是H5的possmessage方法 三、案例代码 父页面-vue2&#xff08;端口号为…...

DevOps到底是什么意思?

前言: 当我们谈到 DevOps 时,可能讨论的是:流程和管理,运维和自动化,架构和服务,以及文化和组织等等概念。那么,到底什么是"DevOps"呢? 那么,DevOps是什么呢? 有人说它是一种方法,也有人说它是一种工具,还有人说它是一种思想。更有甚者,说它是一种哲学…...

03JVM_类加载

一、类加载与字节码技术 1.类文件结构 2.字节码指令 3.编译期处理 4.类加载阶段 5.类加载器 6.运行期优化 1.类文件结构 类文件结构 1.1 魔数magic 介绍 每个java class文件的前4个字节是魔数&#xff1a;0x CAFEBABE。魔数作用在于分辨出java class文件和非java clas…...

Mysql如何对null进行排序(mysql中null排序)

来源&#xff1a;Mysql如何对null进行排序&#xff08;mysql中null排序&#xff09; Mysql如何对null进行排序 Mysql是一种开源的关系型数据库管理系统&#xff0c;经常被用于Web开发和应用程序中。在使用Mysql进行数据处理的过程中&#xff0c;很多时候都会遇到需要对null进行…...

【基础计算机网络1】认识计算机网络体系结构,了解计算机网络的大致模型(下)

前言 在上一篇我们主要介绍了有关计算机网络概述的内容&#xff0c;下面这一篇我们将来介绍有关计算机网络体系结构与参考模型的内容。这一篇博客紧紧联系上一篇博客。 这一篇博客主要内容是&#xff1a;计算机网络体系结构与参考模型&#xff0c;主要是计算机网络分层结构、协…...

vscode 画流程图

文章目录 1、安装插件 draw2、新建文件3、开始画图4、另存为图片 vscode可以画流程图了&#xff0c;只需要安装插件就可以了。 1、安装插件 draw 2、新建文件 3、开始画图 4、另存为图片...

uniapp-一些实用的api接口

唤起导航 调用后可以跳转到地图页 uni.openLocation({latitude: res.data.data.latitude, //到达的纬度longitude: res.data.data.longitude, //到达的经度name: res.data.data.address, // 到达的名字scale: 12, // 缩放倍数success() { // 成功回调console.log(success) }…...

合宙Air724UG LuatOS-Air LVGL API控件-表格(Table)

表格&#xff08;Table&#xff09; 示例代码 --创建表格Table1 lvgl.table_create(lvgl.scr_act(),nil)--设置表格为4行5列lvgl.table_set_row_cnt(Table1,4)lvgl.table_set_col_cnt(Table1,5)--给每个单元格赋值lvgl.table_set_cell_value(Table1, 0, 0, "选手")l…...

前缀和思想

何为前缀和 有一个数组a, 为 ...... 前缀和 ...... 有两个问题: 1.如何求? 只需要从前往后遍历,令 就可以了,最开始是 ,定义 0 2. 有什么用? 能够快速地求出原数组中某一段的和,预处理的…...

Llama2-Chinese项目:1-项目介绍和模型推理

Atom-7B与Llama2间的关系&#xff1a;Atom-7B是基于Llama2进行中文预训练的开源大模型。为什么叫原子呢&#xff1f;因为原子生万物&#xff0c;Llama中文社区希望原子大模型未来可以成为构建AI世界的基础单位。目前社区发布了6个模型&#xff0c;如下所示&#xff1a; FlagAl…...

论文于祥读及复现——《VDO-SLAM: A Visual Dynamic Object-aware SLAM System》

论文详读之------《一个视觉动态对象感知SLAM系统》 0. 出发点&#xff08;暨摘要&#xff09;1.引言2. 相关工作2.1 探索针对动态环境的健壮SLAM2.2 分别执行SLAM和运动对象跟踪(MOT)&#xff0c;作为传统SLAM的扩展&#xff0c;用于动态场景理解。2.3 对象SLAM&#xff08;通…...

nuxt3项目使用pdfjs-dist预览pdf

使用的包的源代码是 pdfjs - npm 但是我们实际上项目中使用的是pdfjs打包后的dist文件&#xff0c;也就是pdfjs-dist - npm 所以我们需要使用这个命令 npm i pdfjs-dist 我们可以克隆pdfjs这个包来看源代码&#xff0c;里面有使用的例子&#xff0c;也可以根据源代码自己打…...

mybatis-generator-maven-plugin使用

前提说明 数据库&#xff1a;MYSQL57Mybatis : http://mybatis.org/generator/index.html 操作说明 引入插件 <plugins><!-- MyBatis 逆向工程 插件 --><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generat…...

基于SpringBoot开发的停车位管理系统(调用百度地图api)

文章目录 项目介绍主要功能截图:前台:后台部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot开发的停车位管…...

STC8单片机PWM定时器+EC11编码器实现计数

STC8单片机PWM定时器+EC11编码器实现计数 📌相关篇《STC单片机+EC11编码器实现调节PWM输出占空比》📍《stc单片机外部中断+EC11编码器实现计数功能》🔖STC8系列支持此功能的型号: ✨从上面的相关篇中有通过通用定时器加外部中断以及常规方法实现驱动EC11编码器的方法。本…...

MediaBox助力企业一站式获取音视频能力

以一只音视频百宝箱&#xff0c;应对「千行千面」。 洪炳峰、楚佩斯&#xff5c;作者 大家好&#xff0c;今天我分享的主题是MediaBox——行业音视频数字化再加速。 根据权威数据表明&#xff0c;65%的行业数字化信息来自视频&#xff0c;基于此&#xff0c;音视频技术对于行…...

仅做笔记用:Stable Diffusion 通过 ControlNet 扩展图片 / 扩图

发觉之前的 Outpainting 脚本效果仍旧不是很理想。这里又找了一下有没有效果更好的途径来扩图。于是就找到了通过 ControlNet 的方式来实现效果更好的扩图。这里临时记录一下在 Stable Diffusion 怎么使用 ControlNet 来扩展图片。 下载 control_v11p_sd15_inpaint_fp16.safet…...

代码随想录算法训练营19期第49天

121. 买卖股票的最佳时机 视频讲解&#xff1a;动态规划之 LeetCode&#xff1a;121.买卖股票的最佳时机1_哔哩哔哩_bilibili 代码随想录 初步思路&#xff1a;贪心。 总结&#xff1a; 分别考虑2种情况&#xff1a; 【1】dp[i][0] 表示第i天持有股票所得最多现金 【2】…...

用shell脚本实现一个对数组求和的函数,数组通过实参传递给函数,写一个函数,输出当前用户的uid和gid,并使用变量接收结果

目录 1.实现一个对数组求和的函数&#xff0c;数组通过实参传递给函数 结果为&#xff1a; 2.写一个函数&#xff0c;输出当前用户的uid和id&#xff0c;并使用变量接收结果 结果为&#xff1a; shell脚本指令前七个网页链接&#xff1a; 八、shell中的分支语句 【1】ife…...

运算符,switch

目录 算术运算符 逻辑运算符 强制类型转换 自增自减运算符 ​编辑 三目运算符 A&#xff1f;B:C 逗号表达式 switch 算术运算符 除法的运算结果和运算对象的数据类型有关&#xff0c;两个都是int商就是int&#xff0c;被除数或者除数只要有一个是浮点型数据&#xff0c;…...

运行java命令出现 Error: Invalid or corrupt jarfile XXX.jar

朋友 我当你一秒朋友 朋友 我当你一世朋友 奇怪 过去再不堪回首 怀缅 时时其实还有 运行java命令出现 Error: Invalid or corrupt jarfile XXX.jar 基本可以断定&#xff0c;是jar不完整导致的。不完整&#xff01;&#xff01;&#xff01;记住关键字 检查1&#xff1a; …...

网站建设管理与政府/超级优化大师下载

期待着,盼望着&#xff0c;五一劳动节终于要到来了&#xff01;开心&#xff01;让我们欢呼雀跃&#xff01; 小编此时此刻的心情&#xff0c;无法形容&#xff0c;唯有吟诗一首&#xff1a; 啊&#xff01;劳动节~~ 真高兴呀&#xff01; 真高兴&#xff01; 哎呀&#xff01;…...

网站内部数据搜索怎么做/站长工具seo排名查询

目录树 新建Maven项目及步骤修改方法启动测试新建Maven项目及步骤 我这里是从创建开始讲&#xff0c;使用的工具是Idea2017版本。如果是已经创建了Maven&#xff0c;想改为spring boot项目的请直接跳到【修改方法】 1.点击右上角的File&#xff0c;出来的列表选择New Object&am…...

建设手机网站/百度客户端官网

相信钓鱼邮件对于邮件管理员都不陌生&#xff0c;诸如此类那么怎么才能杜绝此类邮件呢&#xff1f;这里简单新建一条规则命名为 钓鱼邮件&#xff0c; 只要是包含 “升”“邮”“箱”“配”“额”这几个字的&#xff0c;统统重定向给管理员&#xff0c;并追加 Cheat Mail &…...

提供免费主页空间的网站/网络口碑营销的成功案例

2、深度优先和广度优先 深度优先DFS 1、访问顶点V 2、从V的未被访问的邻接点出发&#xff0c;对图进行深度优先遍历&#xff1b; 3、直到访问到与V相通的节点&#xff1b; 4、若此时图中尚有顶点未被访问&#xff0c;则从一个未被访问的顶点出发&#xff0c;重新进行深度优先…...

专业做网站/电子商务沙盘seo关键词

版权声明&#xff1a;本文为 小异常 原创文章&#xff0c;非商用自由转载-保持署名-注明出处&#xff0c;谢谢&#xff01; 本文网址&#xff1a;https://blog.csdn.net/sun8112133/article/details/84350216 好久没写博客咯&#xff0c;今天来写一写今天写代码中遇到的一个问题…...

郑州市重点项目建设办公室网站/软文网站推广法

NBearLite是NBearV4的几个核心组件之一&#xff0c;也是目前NBearV3中ORM部分的查询语法的核心。NBearLite本身并不是一个完整的ORM解决方案&#xff0c;配合目前Teddy正常开发的NBearMapping组件使用&#xff08;某个中间组件过渡&#xff09;&#xff0c;组成一套完整强大的O…...