首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

极简 Java 工作流概念入门

关于 Flowable 松哥已经更新了好几篇文章了,不过考虑到有的小伙伴可能还从来没接触过流程引擎,因此有一些基础的内容我再来和小伙伴们梳理一下。 1. 为什么需要工作流 松哥将之前的文章转发到朋友圈后,有小伙伴评论说一直不理解为什么需要工作流,今天我们就先来说说这个话题。 假设我有一个请假需求,流程如下: 请假可以提交给我的上司,上司可以选择批准或者拒绝,无论批准还是拒绝,都会给我一个通知。 这个流程比较简单,我们很容易想到解决方案,不用工作流也能解决,有一个专门的请假表,当 A 要请假的时候,就往请假表中添加一条记录,这条记录的内容包含了请假的天数、原因、请假的审批人 B 以及一个名为 status 的字段,这个 status 字段表示这个请假申请目前的状态(待审批、已批准还是已拒绝),然后 B 登录系统之后,在请假表中查询到了 A 的请假信息,然后选择批准,此时将 status 字段的值改一下就行了。 这个流程很简单,相信小伙伴们都能想到。 然而,这是一个非常简单的流程,对于这样的流程,一般来说也确实没有必要使用工作流,但是现实中,我们涉及到的工作流往往都是非常复杂的,我举个例子,就说报销审批吧,这个可能很多小伙伴都经历过。 小伙伴们看到,这个流程相对来说还是比较复杂的,此时你再用一个 status 字段去描述,就很难说的请到底是怎么回事了。每一步审批,都有可能批准也有可能拒绝,拒绝并不意味着流程结束,员工修改报销资料之后,还可以继续提交。此时如果还用 status 去描述,那么 status 将有 N 多个值去表示不同的情况,这个维护起来非常不便。 这就复杂了吗?非也非也,我们再来看一个生产笔记本电脑的例子,假设公司研发了一款新型笔记本电脑,整个研发到生产的流程可能是这样: 相比上面两个,这个就更复杂一些了,不仅有串行任务还有并行任务,如何去设计这样一个系统?单纯的通过状态字段去描述显然已经不够用了,此时我们就得考虑一种通用的、更易维护的方案来实现这样的系统了,这种通用的、易维护的方案,也就是工作流。 2. 三大工作流 一个比较早的工作流是 jBPM,这是一个由 Java 实现的企业级流程引擎,是 JBoss 公司开发的产品之一。 jBPM 的创建者是 Tom Baeyens,这个大佬后来离开了 JBoss,并加入到 Alfresco,并推出了基于 jBPM4 的开源工作流系统 Activiti,而 jBPM 则在后续的代码中完全放弃了 jBPM4 的代码。从这个过程中也能看出来,jBPM 在发展过程中,由于意见相左,后来变成了两个 jBPM 和 Activiti。 然而戏剧的是,Activiti5 没搞多久,从 Activiti 中又分出来一个 Camunda,Activiti 继续发展,又从中分出来一个 Flowable。。。 由于开发 jBPM、Activiti、Camunda 以及 Flowable 的人多多少少有一些关联性,让人不得不猜测意见相左拉一票人出来单干是他们的企业文化。 所以现在市面上主流的流程引擎就一共有三个: Activiti Flowable Camunda 这三个各有特点: Activiti 目前是侧重云,他目前的设计会向 Spring Cloud、Docker 这些去靠拢。 Flowable 核心思想还是在做一个功能丰富的流程引擎工具,除了最最基础的工作流,他还提供了很多其他的扩展点,我们可以基于 Flowable 实现出许多我们想要的功能(当然这也是小伙伴们觉得 Flowable 使用复杂的原因之一)。 Camunda 相对于前两个而言比较轻量级,Camunda 有一个比较有特色的功能就是他提供了一个小巧的编辑器,基于 bpmn.io 来实现的(松哥之前已经发文讲过了)。如果你的项目需求是做一个轻巧的、灵活的、定制性强的编辑器,工作流是嵌入式的,那么可以选择 Camunda。 如果仔细比较起这三个的差异,能列一个长长的表格,这个网上也有不少人都总结过了,松哥这里也就不啰嗦了。 3. 流程图 既然有三个不同的工作流,那么三个不同的工作流画出来的流程图是否都各不相同呢? 不是的。 工作流程图这块其实有一个统一的标准,那就是 BPMN。BPMN 全称是 Business Process Model and Notation,中文译作业务流程模型和标记法,这个中文太绕口了,还是简称 BPMN 吧。 这是一套图形化表示法,用图形来表示业务流程模型。BPMN 最初由业务流程管理倡议组织(BPMI, Business Process Management Initiative)开发,BPMI 于 2005 年与对象管理组织(OMG, Object Management Group)合并,并于 2011 年 1 月 OMG 发布 2.0 版本,同时改为现在的名称。 一句话,就是流程图这块有一个特别古老的规范,那就是 BPMN,而我们前面所说的无论是 Activiti、Flowable 还是 Camunda,都是支持这个规范的,所以呢,无论你使用哪一个流程引擎,都可以使用同一套流程图。 那么这个规范究竟都说了些什么事情呢? 我们以上面生产笔记本的流程图为例,来和小伙伴们做一个简单介绍: 从上图中可以看到,一个流程图中主要包含四方面的内容: 事件 连线 任务 网关 我们一个一个来说。 事件 首先在一个流程图中应该有开始事件和结束事件,也就是上图大家看到的两个圆圈。另外还有一些中间事件、边界事件等。举个中间定时事件的例子,比如用户下单之后,可以有一个中间定时事件,延迟 5 分钟发货。 连线 连线就是将事件、任务、网关等连在一起的线条,一般情况下就是普通连线,有的时候连线会有一些条件,例如松哥之前文章和大家分享的请假,如果经理同意请假申请,就走哪一个线条,如果经理不同意请假申请,就走哪一个线条。对应上图的笔记本生产,如果经理审批通过,就载入图纸准备生产,如果经理审批不通过,就重新设计。 任务 任务这块其实有很多分类。 如果细分大致上可以分为如下几种: 接收任务 在上面的流程图中,等待准备工作完成这一项就是一个接收任务。这个任务里并不需要额外做什么事情,流程到这一步就自动停下来了,需要人工去点一下,推动流程继续向下执行。 发送任务 这个一般用来把消息发送给外部参与者。 服务任务 这个一般由系统自动完成,其实说白了就是我们的一个自定义类,可以在一个自定义类里边完成想要做的事情。 脚本任务 一个自动化活动。当流程执行到脚本任务时,自动执行相应的脚本。 业务规则任务 BPMN2.0 新引入用来对接业务规则引擎,业务规则任务用于同步执行一个或多个规则。 用户任务 用于为那些需要由人工参与者完成的工作建模。 虽然细分类别很多,但是仔细看,其实这几种又可以归为两大类: 用户任务:表示人工要介入做的事情。比如同意与否,或者输入一些参数,要让人工完成任务,就需要一个表单系统,让人工输入数据,或者显示数据给人看,这也是为什么用户任务和表单系统结合在一起的原因,用户任务需要用户向引擎提交一个完成任务的动作,否则流程会暂停在这里等待。 服务任务:表示机器自动做的事情。调用服务的任务,这个服务可以是一个 Spring JavaBean,也可以是一个远程 REST 服务,流程会自动执行服务任务。 活动 活动可以算是一种特殊的任务。活动可以调用另外一个流程使之作为当前流程的子流程去运行。活动也可以分为用户活动、脚本活动等等。从显示上来说,活动比任务边框深一些。仅此而已。 网关 网关要是细分起来,也有很多不同类型的网关。 互斥网关 这种网关也叫排他性网关,我们之前请假流程中的那个网关,就是互斥网关。这种网关有且仅有一个有效出口。 相容网关 这种网关会有多个出口,只要条件满足,都会执行。 事件网关 事件网关是通过中间事件驱动,它在等待的事件发生后才会触发决策。基于事件的网关允许基于事件作出决策。 并行网关 并行网关一般是成对出现的,上面生产笔记本的那个流程中,生产屏幕、键盘等并行操作,就是通过并行网关来实现的。 好啦,这就是关于流程引擎的一些基本概念,捋顺了这些基本概念,在回过头看我们前面几篇关于流程引擎的文章,应该会有一些不一样的理解: Spring Boot 整合流程引擎 Flowable,so easy! SpringBoot+Vue+Flowable,模拟一个请假审批流程! 49张图带领小伙伴们体验一把 Flowable-UI Spring Security + Vue + Flowable 怎么玩?

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

RPC 框架 Kitex 实践入门:性能测试指南

2021 年 9 月 8 日,字节跳动宣布正式开源 CloudWeGo。CloudWeGo 是一套字节跳动内部微服务中间件集合,具备高性能、强扩展性和稳定性的特点,专注于解决微服务通信与治理的难题,满足不同业务在不同场景的诉求。CloudWeGo 第一批开源了四个项目:Kitex、Netpoll、Thriftgo 和 netpoll-http2,以 RPC 框架 Kitex 和网络库 Netpoll 为主。 日前,字节跳动服务框架团队正式开源CloudWeGo,在抖音、今日头条均有深度应用的 Golang 微服务 RPC 框架 Kitex 也包含在其中。 本文旨在分享开发者在压测 Kitex 时需要了解的场景和技术问题。这些建议有助于用户更好地结合真实 RPC 场景对 Kitex 进行调优,使之更贴合业务需要、发挥最佳性能。用户也可以参考官方提供的压测项目kitex-benchmark了解更多细节。 微服务场景的特点 Kitex 诞生于字节跳动大规模微服务架构实践,面向的场景自然是微服务场景,因此下面会先介绍微服务的特点,方便开发者深入理解 Kitex 在其中的设计思考。 RPC 通信模型 微服务间的通信通常以 PingPong 模型为主,所以除了常规的吞吐性能指标外,每次 RPC 的平均时延也是开发者需要考虑的点。 复杂的调用链路 一次 RPC 调用往往需要多个微服务协作完成,而下游服务又会有其自身依赖,所以整个调用链路会是一个复杂的网状结构。 在这种复杂调用关系中,某个中间节点出现的延迟波动可能会传导到整个链路上,导致整体超时。当链路上的节点足够多时,即便每个节点的波动概率很低,最终汇聚到链路上的超时概率也会被放大。所以单一服务的延迟波动 —— 即 P99 延迟指标,也是一个会对线上服务产生重大影响的关键指标。 包体积大小 虽然一个服务通信包的大小取决于实际业务场景,但在字节跳动的内部统计中,我们发现线上请求大多以小包(<2KB)为主,所以在兼顾大包场景的同时,也重点优化了小包场景下的性能。 针对微服务场景进行压测 确定压测对象 衡量一个 RPC 框架的性能需要从两个视角分别去思考:Client 视角与 Server 视角。在大规模的业务架构中,上游 Client 不见得使用的也是下游的框架,而开发者调用的下游服务也同样如此,如果再考虑到 Service Mesh 的情况就更复杂了。 一些压测项目通常会把 Client 和 Server 进程混部进行压测,然后得出整个框架的性能数据,这其实和线上实际运行情况很可能是不符的。 如果要压测 Server,应该给 Client 尽可能多的资源,把 Server 压到极限,反之亦然。如果 Client 和 Server 都只给了 4 核 CPU 进行压测,会导致开发者无法判断最终得出来的性能数据是哪个视角下的,更无法给线上服务做实际的参考。 对齐连接模型 常规 RPC 的连接模型主要有三种: 短连接:每次请求都创建新连接,得到返回后立即关闭连接 长连接池:单个连接同时只能处理一次完整请求与返回 连接多路复用:单个连接可以同时异步处理多个请求与返回 每类连接模型没有绝对好坏,取决于实际使用场景。连接多路复用虽然一般来说性能相对最好,但应用上必须依赖协议能够支持包序列号,且一些老框架服务可能也并不支持多路复用的方式调用。 Kitex 最早为保证最大程度的兼容性,在 Client 端默认使用了短连接,而其他主流开源框架默认使用连接多路复用,这导致一些用户在使用默认配置压测时,出现了比较大的性能数据偏差。 后来为了契合开源用户的常规使用场景,Kitex 在 v0.0.2 中也加入了默认使用长连接的设置。 对齐序列化方式 对于 RPC 框架来说,不考虑服务治理的话,计算开销主要都集中在序列化与反序列化中。 Kitex 对于 Protobuf 的序列化使用的是官方的Protobuf库,对于 Thrift 的序列化,则专门进行了性能优化,这方面的内容在官网博客中有介绍。 当前开源框架大多优先支持 Protobuf,而部分框架内置使用的 Protobuf 其实是做了许多性能优化的gogo/protobuf版本,但由于 gogo/protobuf 当前有失去维护的风险,所以出于可维护性角度考虑,我们依然决定只使用官方的 Protobuf 库,当然后续我们也会计划对 Protobuf 进行优化。 使用独占 CPU 虽然线上应用通常是多个进程共享 CPU,但在压测场景下,Client 与 Server 进程都处于极端繁忙的状况,如果同时还共享 CPU 会导致大量上下文切换,从而使得数据缺乏可参考性,且容易产生前后很大波动。 所以我们建议是将 Client 与 Server 进程隔离在不同 CPU 或者不同独占机器上进行。如果还想要进一步避免其他进程产生影响,可以再加上 nice -n -20 命令调高压测进程的调度优先级。 另外如果条件允许,相比云平台虚拟机,使用真实物理机会使得测试结果更加严谨与具备可复现性。 性能数据参考 在满足上述要求的前提下,我们对多个框架使用 Protobuf 进行了压测对比,压测代码在 kitex-benchmark 仓库。在充分压满 Server 的目标下,Kitex 在连接池模式下的 P99 Latency 在所有框架中最低。而在多路复用模式下,Kitex 在各指标上也都具有更加明显的优势。 配置: Client 16 CPUs,Server 4 CPUs 1KB 请求大小,Echo 场景 参考数据: KITEX:连接池模式(默认模式) KITEX-MUX:多路复用模式 其他框架均使用多路复用模式 结语 在当前主流的 Golang 开源 RPC 框架中,每个框架其实在设计目标上都各有侧重:有些框架侧重于通用性,有些侧重于类似 Redis 这种轻业务逻辑的场景,有些侧重于吞吐性能,而有些则更侧重 P99 时延。 字节跳动的业务在日常迭代中,常常会出现因某个 feature 导致一个指标上升,另一个指标下降的情况,因此 Kitex 在设计之初就更倾向于解决大规模微服务场景下各种问题。 Kitex 发布后,我们接到了大量来自用户的自测数据,感谢社区对我们的关注和支持,也欢迎广大开发者基于本文提供的测试指南,针对自己的实际场景选择合适的工具。更多问题,请在 GitHub 上提 Issue 交流。 相关链接 CloudWeGo 官网:https://www.cloudwego.io Kitex:https://github.com/cloudwego/kitex Netpoll:https://github.com/cloudwego/netpoll kitex-benchmark:https://github.com/cloudwego/kitex-benchmark netpoll-benchmark:https://github.com/cloudwego/netpoll-benchmark 官方 Protobuf 库:https://github.com/golang/protobuf Thriftgo:https://github.com/cloudwego/thriftgo

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

4个小技巧带你轻松入门kafka!

前言 Kafka 是一个消息系统,原本开发自 LinkedIn,用作 LinkedIn 的活动流(Activity Stream)和运营数据处理管道(Pipeline)的基础。现在它已被多家不同类型的公司 作为多种类型的数据管道和消息系统使用。 活动流数据是几乎所有站点在对其网站使用情况做报表时都要用到的数据中最常规的部分。活动数据包括页面访问量(Page View)、被查看内容方面的信息以及搜索情况等内容。这种数据通常的处理方式是先把各种活动以日志的形式写入某种文件,然后周期性地对这些文件进行统计分析。运营数据指的是服务器的性能数据(CPU、IO 使用率、请求时间、服务日志等等数据)。运营数据的统计方法种类繁多。 近年来,活动和运营数据处理已经成为了网站软件产品特性中一个至关重要的组成部分,这就需要一套稍微更加复杂的基础设施对其提供支持。 Kafka 简介 Kafka 是一种分布式的,基于发布 / 订阅的消息系统。主要设计目标如下: 以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对 TB 级以上数据也能保证常数时间复杂度的访问性能。 高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒 100K 条以上消息的传输。 Java中间件学习笔记集锦 支持 Kafka Server 间的消息分区,及分布式消费,同时保证每个 Partition 内的消息顺序传输。 同时支持离线数据处理和实时数据处理。 Scale out:支持在线水平扩展。 Kafka 基础概念 概念一:生产者与消费者 对于 Kafka 来说客户端有两种基本类型:生产者(Producer)和消费者(Consumer)。除此之外,还有用来做数据集成的 Kafka Connect API 和流式处理的 Kafka Streams 等高阶客户端,但这些高阶客户端底层仍然是生产者和消费者API,它们只不过是在上层做了封装。 这很容易理解,生产者(也称为发布者)创建消息,而消费者(也称为订阅者)负责消费or读取消息。 概念二:主题(Topic)与分区(Partition) 在 Kafka 中,消息以**主题(Topic)**来分类,每一个主题都对应一个「消息队列」,这有点儿类似于数据库中的表。但是如果我们把所有同类的消息都塞入到一个“中心”队列中,势必缺少可伸缩性,无论是生产者/消费者数目的增加,还是消息数量的增加,都可能耗尽系统的性能或存储。 我们使用一个生活中的例子来说明:现在 A 城市生产的某商品需要运输到 B 城市,走的是公路,那么单通道的高速公路不论是在「A 城市商品增多」还是「现在 C 城市也要往 B 城市运输东西」这样的情况下都会出现「吞吐量不足」的问题。所以我们现在引入**分区(Partition)**的概念,类似“允许多修几条道”的方式对我们的主题完成了水平扩展。 概念三:Broker 和集群(Cluster) 一个 Kafka 服务器也称为 Broker,它接受生产者发送的消息并存入磁盘;Broker 同时服务消费者拉取分区消息的请求,返回目前已经提交的消息。使用特定的机器硬件,一个 Broker 每秒可以处理成千上万的分区和百万量级的消息。(现在动不动就百万量级..我特地去查了一把,好像确实集群的情况下吞吐量挺高的..摁..) 若干个 Broker 组成一个集群(Cluster),其中集群内某个 Broker 会成为集群控制器(Cluster Controller),它负责管理集群,包括分配分区到 Broker、监控 Broker 故障等。在集群内,一个分区由一个 Broker 负责,这个 Broker 也称为这个分区的 Leader;当然一个分区可以被复制到多个 Broker 上来实现冗余,这样当存在 Broker 故障时可以将其分区重新分配到其他 Broker 来负责。下图是一个样例: Kafka 的一个关键性质是日志保留(retention),我们可以配置主题的消息保留策略,譬如只保留一段时间的日志或者只保留特定大小的日志。当超过这些限制时,老的消息会被删除。我们也可以针对某个主题单独设置消息过期策略,这样对于不同应用可以实现个性化。 概念四:多集群 随着业务发展,我们往往需要多集群,通常处于下面几个原因: 基于数据的隔离; 基于安全的隔离; 多数据中心(容灾) 当构建多个数据中心时,往往需要实现消息互通。举个例子,假如用户修改了个人资料,那么后续的请求无论被哪个数据中心处理,这个更新需要反映出来。又或者,多个数据中心的数据需要汇总到一个总控中心来做数据分析。 上面说的分区复制冗余机制只适用于同一个 Kafka 集群内部,对于多个 Kafka 集群消息同步可以使用 Kafka 提供的 MirrorMaker 工具。本质上来说,MirrorMaker 只是一个 Kafka 消费者和生产者,并使用一个队列连接起来而已。它从一个集群中消费消息,然后往另一个集群生产消息。

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

一文回顾 Java 入门知识(下)

### 前言 这是`推荐学java` 系列的第三篇,这节的内容很多,对于小白来说,都是新概念,要熟练掌握的话,需要大量的练习。本节内容的导图会很大,小编会在讲解每个知识点之前单独提供导图,当然全图也有,除此之外,这节内容会涉及很多系统的API,而我们要学会看 jdk 文档,所以也会给大家提供 jdk1.8 的帮助文档,下载见文末。 ![知识点枝节数目](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/078ec09a86c54da983443ba1dbc1259b~tplv-k3u1fbpfcp-zoom-1.image) 有图有真相就不多说了,知识点基本是上一篇的两倍。 ### 设计模式 ![Java设计模式导图](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1197972f43304cf8b7a13a745b7509a1~tplv-k3u1fbpfcp-zoom-1.image) Java中的 23 种设计模式在开发中应用很多,不仅仅是我们平时的应用开发,还包括一些框架和系统源码中都有应用,具体的内容不能生搬硬套,而是在经验中去体会这个过程,思考应用设计模式的时机和场景。 其中单例设计模式最常用,也最简单,几乎可以说但凡用Java语言开发的程序,都会用到单例设计模式。没有必要死磕概念,重要的是理解其思想,随着开发经验的累积,就会慢慢体悟到其中的奥妙! ```java /** * 懒汉式 */ public class SingletonLazy { private static SingletonLazy singletonHungry; private SingletonLazy() { } public static SingletonLazy getInstance() { if (singletonHungry == null) { singletonHungry = new SingletonLazy(); } return singletonHungry; } } ``` ```java /** * 饿汉式 */ public class SingletonHungry { private static SingletonHungry singletonHungry = new SingletonHungry(); private SingletonHungry() { } public static SingletonHungry getInstance() { return singletonHungry; } } ``` ### 多态 ![Java多态导图](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1b355732cc3e4722808ff4185e670b96~tplv-k3u1fbpfcp-zoom-1.image) `多态` 是 Java 面向对象中的三大特点之一,上一篇中讲了 `封装` 和 `继承` ,多态是本节的第一重点内容。其要表达的意思简而言之:一种事务的多种形态展现形式就叫多态。 抽象起来不好理解,举例实际场景比较好理解: > 比如我们软件开发者本身就是抽象一类,因为其他行业的人理解起来就不容易,而且还分不清楚,你到底是开发啥的?(是前端开发还是后端开发?是Java开发还是PHP开发?是系统层开发还是游戏开发?等等),这个概念总体给人是一种抽象的,但还大概知道这个词具有哪些 **共性** ,而这里的 `共性` 就是抽象出来的具体能力,Java中叫抽象方法,因为每个具体的开发者所具有的同一个方法内部能力表现不同,这就是具体子类要实现的。这里的子类可以理解为 `java开发工程师` 、`PHP开发工程师` 等等。 在我们实际开发中,根据业务场景,我们要自己去提取抽象类,进而实现分离的能力,而所分离出来的多个子类,具有不同的表现形式,就是多种形态的,故名 `多态` 。 #### 关键字 instanceof 相信你能明白,我们抽离出来了抽象类(父类),那么子类的表现各异,而父类如何判断一个子类是否是它的子类呢?这就是关键字 `instanceof` 的用处。 学习多态可能听到最多的一句话就是:**父类引用指向子类对象**。 什么叫**引用**,老版本教材中叫做`句柄`,新点的教程都称为 `引用`,其实就是创建的对象的变量,比如: ```java // programmer 就是句柄,也叫引用 Programmer programmer = new Programmer(); ``` 再举个父类引用指向子类对象的例子: ```java // new 是用来创建对象的,上一节大家都用过 Programmer javaProgrammer = new JavaProgrammer(); ``` #### interface 这块内容大家看导图,记住用法和为什么用。实际开发中,定义接口的场景太多了,必须熟练掌握使用规则。 #### 小结 `多态` 的内容是重中之重,必须搞明白下面这几个概念和为什么?这也是常见的面试题。 1. Java中的多态你是怎么理解的? 2. 你对抽象类怎么理解?抽象类有什么特点? 3. Java为什么会有接口(interface)? 4. 接口的使用规则和接口中方法的定义 5. 内部类的应用场景? ### 异常 ![Java中的异常知识导图](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/64b3c179040f41a483aedadddd2cf60e~tplv-k3u1fbpfcp-zoom-1.image) 这块内容现在开发中依靠 IDE 的只能提示已经可以搞定了,更多的应用情况是自己开发SDK或者封装组件时候的处理,明确出现异常时,程序的执行顺序,以及父类方法抛出异常,子类重写时抛异常的规则。 ### 包装类 ![Java中的包装类知识导图](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5bbed13d0bc2479dbaf49d16e7b2c6df~tplv-k3u1fbpfcp-zoom-1.image) - **明确为什么要有包装类?** - **熟练掌握装箱与拆箱的规则和类型转换方法的使用** 导图中提到的转换方法,开发中经常用到,大家要多练习,最起码基本数据类型要全部尝试一次。 以下代码是本节的重点: ```java private static void compareDemo() { Integer num1 = 20; /** * 相当于执行了 Integer num2 = Integer.valueOf(2021); * * Double 和 Float 不具备这个特性(常量池) */ Integer num2 = 2021; Integer num3 = 20; Integer num4 = 2021; System.out.println("num1 与 20 相等吗 " + (num1 == 20)); // 自动拆箱比较 System.out.println("num2 与 2021 相等吗 " + (num2 == 2021)); /** * 结果不同的原因:Integer在 -128~127 之间时,参与两个 Integer 对象比较前会自动拆箱,超过这个范围则不会 */ System.out.println("num1 与 num3 相等吗 " + (num1 == num3)); // 30 数字在比较 System.out.println("num2 与 num4 相等吗 " + (num2 == num4)); // 对象在比较 } ``` ### 字符串 ![Java中的字符串知识导图](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ee0e88652b624452ae4daca6b9187bd2~tplv-k3u1fbpfcp-zoom-1.image) 这部分内容每个Java开发者必须熟练掌握,字符串的**截取、替换、匹配、大小写转换、查找、拼接**等是最最常用的操作,导图中列出来的方法必须熟练运用。 ### 集合 ![Java中的集合知识导图](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/011a5247b1054dd6ad026817d301fb03~tplv-k3u1fbpfcp-watermark.image) 导图中的重点内容都有标记,是属于重中之重,Java中的集合内容也是面试问的最多的知识点之一,必须牢记于心,熟练运用。`ArrayList` 和 `HashMap` 是开发中最常用到的集合,**必须要明白它们各自的特点和常用方法以及特有方法**,大多数场景是两者结合来使用,比如:条件过滤操作等。 ### 线程 ![Java中的线程知识点导图](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/04f241c324944a8ba833dce4e21dc792~tplv-k3u1fbpfcp-zoom-1.image) 首先要搞清楚程序执行的默认顺序和主线程之间的关系;其次要明白当有多个线程的时候,程序又是如何执行的;这两个问题搞清楚后,你就会明白什么时候需要创建线程了。 知识点(同样是面试题): - **创建线程的方式** - **线程的执行顺序** - **对synchronized关键字的理解** - **线程死锁问题** ### IO ![Java中的IO流知识导图](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/91fc2cb425fe4d89a82ae15cae550dc8~tplv-k3u1fbpfcp-zoom-1.image) 这部分内容实际开发中与网络请求结合使用,比如下载文件、上传文件、修改头像等,这里的具体API使用都是最原生的,也就是底层实现逻辑是这样的,往往实际开发中我们会使用别人封装的框架,看不到最里面的API实现,框架会暴漏给我们一些方法,也许就是一句话就实现了下载或者上传;但是有些场景还是需要我们手动撸一遍,所以这些原理的核心代码还是要掌握,偶尔面试也会让你口述流程。 以下代码是关于 `File` 类创建文件的三种方式,根据业务都有可能会用到: ```java /** * 创建文件 File 的几种方式 * * @param parentPath 前端路径 * @param fileNamePath 后端路径 */ private static void createFile(String parentPath, String fileNamePath) { File file1 = new File(parentPath + "\\" + fileNamePath); System.out.println("file1 is exit ? " + file1.exists()); File file2 = new File(parentPath, fileNamePath); System.out.println("file2 is exit ? " + file2.exists()); File file3 = new File(new File(parentPath), fileNamePath); System.out.println("file3 is exit ? " + file3.exists()); } ``` ### 总结 jdk1.8 帮助文档下载:`https://pan.baidu.com/s/12JHAlmwZbtBiJlPNZPlf3Q` 取密码:d5ya(这个文档是小编从网上下的,里面如有其他内容请勿相信哈) 这三篇内容,对于小白建议15天学完,必须稳扎稳打,这就是Java最基础的东西,不管是后面要接触的多么牛逼的框架,底层都离不开基础的支撑。 **补充内容**:Java中的枚举(Enum) 相对比较简单,自行搜索熟悉写法,后续的项目篇章就会应用。 > 小编特意创建了一个公众号:`推荐学java`,会分享与`java`相关的内容,并且以原创为主,欢迎大家搜索关注(关注即送小编挑选的精品视频教程),一起学Java!

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

每日一博 | 梯度下降极简入门

导 语 梯度下降及其变体被用作训练过程的关键部分在机器学习中广泛使用。梯度下降中的“梯度”是指单变量导数的推广形式,即多元变量求导。 梯度下降法是解决“优化问题”的迭代方法,其中优化问题是指围绕寻找函数的全局最小值或最大值而展开的数学问题。我们将很快看到,对于简单的优化问题可以不用梯度下降。当事情变得复杂时,我们则需要用诸如梯度下降之类的迭代法,当然和神经网络相关的优化问题确实足够复杂。 01 重新回顾优化问题 假设你已经购买了200米的铁丝网。您想使用此围栏为羊群创建一个矩形牧场。如何确定使牧场内部面积最大化时,牧场对应的长度和宽度? 使用标准的分析方法来解决这个问题,我们首先要写一个方程式来表示我们的问题。首先,我们知道两件事: area(面积)=length(长度)*width(宽度)(2 * length)+(2 * width)= 200 但是我们想用一个变量而不是两个变量来表示面积,所以我们可以求解这两个方程中的第二个变量的宽度: 2 * width = 200–2 * lengthwidth = [200-2 * length] / 2width = 100 - length 现在我们可以用100- length代替width,则: area= length * [100–length]area = f(length)=100 * length- length² 取面积的导数: area’=100-2*length;length=50 现在,我们找到了函数的“临界点”,即一阶导数等于零时对应的长度,当然函数在该点处的斜率也为零。我们关心这种值,因为它们是唯一能对应函数最小值或函数最大值的数。在临界点处,该点两侧的值可能都小于或都大于临界点处的值。因为函数中该点外的斜率都不为零,这意味着临界点上一边的点对应的面积将小于该临界点对应的面积,而另一边的点对应的面积将大于该临界点对应的面积。也就是说,该函数在非临界点处正在增加或减少,因此不能为最大值或最小值。 area’=100-2*length=0-->length=50 这表明如果存在全局最大值或最小值,则必须在长度= 50时发生。也就是说,如果矩形的长度存在最佳选择,则为50米。可能存在临界点既不是最小值也不是最大值,所以应该检测已发现的临界点确实是最值。在微积分课程中,有相关的检验方法(比如二阶导数检验),现在用更简单的方法(类似梯度下降法)来解决该问题,比如在临界点长度= 50的左右两侧测试2个点。 f(49)= 4900–2401 = 2499f(50)= 5000–2500 = 2500f(51)= 5100–2601 = 2499 这并不能确认矩阵面积最大时对应长度值就是50,或者某些时候有比50更好的点,不过这种近似的方法最终将应用于训练模型。对于这个简单的问题,通过绘制函数了解该方法和实际的误差: 02 梯度下降—迭代式猜测 那么这与梯度下降方法有什么关系呢?梯度下降方法比较粗糙,就像刚才所做的那些不精确的猜测一样。看上去它是比随机猜测稍强一点的显得杂乱的体系,不过它将最终成为我们解决围栏问题的方法: 猜测围栏的最佳长度 计算此时的梯度值 根据梯度的值,调整猜测 重复猜测直到满足条件则终止 假设我们随机选取57当作长度的第一个猜测值,在57处,面积函数的导数为: f(57)=100*57 - 57*57 = 2451f'(57)=100–2*(57)=-14 ‍ length = 57处的斜率不为0,因此不是临界点。此外斜率为-14表示如果将长度增加 1,则面积将减小 14(假设函数的斜率不变)。梯度下降使用此值作为进行下一个猜测的指导。比如要增加面积的值,因为斜率是负数,所以应该57基础上减小长度,以此增加面积的值。 然而即使知道当前应该减少length的值,也没有先验的方法可以确切地知道“合适”的数来调整我们的当前的猜测(length=57)。在像TensorFlow这样的软件包中,我们用来调整当前length的快慢将由一个称为“学习率”的超参数控制,可以在训练时设置该参数。提高学习率将导致梯度下降对当前当前length调整很快;减小学习率会导致梯度下降对当前当前length调整较慢。现在假设将当前length减少3,虽然有点武断,但实际上效果可以接受。 57–3 = 54f(54)= 5400–(54²)-->f(54)= 5400–2916 -->f(54)= 2484 2484大于2451,说明找到的面积比上次大。再次使用导数来检查是否处于临界点,如果不是,则调整猜测值: f'(54)= 100–2 * 54 = 100–108 = -8 我们的当前猜测值(54)仍然很大,斜率-8低于-14,应该适当减缓对当前猜测值的更改幅度,比如在54基础上减少2,则: f(52)= 5200–52² --> f(52)= 5200–2704 -->f(52)= 2496 我们将重复此过程,直到找到一个临界点。或者直到f'(length)的值非常接近零,才能认为length已足够接近临界点。手工完成此过程是重复且繁琐的,但是计算机善于解决重复繁琐的任务。通俗点说,将像在爬山和滚球,一直沿着抛物线上升,直到无法进一步上升为止。 请注意导数(蓝色),它在最大值的右边是负数,在最大值的左边是正数。在这种情况下,很容易找到最大值。 由于试图找到面积的最大值,上面的示例称之为“梯度上升”更好。在梯度下降中,每次计算梯度值时都将其相反数。 马上将提到的梯度下降和在神经网络里面用到的梯度下降有两个不一样的地方。首先,神经网络对应的函数比f(length)更复杂。我们的神经网络具有成千上万的可调参数,而其中f(length)只有一个。我们使用诸如梯度下降之类的迭代方法主要是因为神经网络模型非常复杂,而不是选用之前查找临界点时的分析过程。计算当前如此庞大规模的神经网络所表示的一般性的函数导数根本不可行。第二个区别是,在此示例中,有一个充当标准结果的实函数,并且发现了该函数的最佳值。在神经网络中,没有显式的函数;取而代之的是,我们尝试创建一个不存在标准结果的函数。 03 用于函数查找的梯度下降 在前面的示例中,使用梯度下降方法沿该曲线可以找到最佳值。在机器学习中,对于训练集中的数据,我们希望创建一条曲线来更好地拟合这些数据。回顾一下刚刚研究的围栏问题,将它转化为我们更倾向于用机器学习解决的问题。 我们从围栏数据库中收集了很多数据样本。我们数据集中的每个数据点的背景都是来自用100米围栏材料来建造矩形牧场。每个数据点有2个参数:围栏一侧的长度和围栏的面积。在这个问题中,不是尝试找到围栏的最佳长度,而是试图找到一个函数,该函数可以根据给定的边长来预测矩形围栏的面积。我们的输入数据如下所示: 看起来数据中有一个模式,我们可以使用机器学习来定义模式吗? 机器学习解决此问题的方法是认为:“看起来有点像某种数学函数,想知道到底是哪个函数?”,更进一步,我们猜测该函数是某种抛物线函数,则该函数的一般表达式是: F(x)=ax²+ bx 在数据集中已知x值和y值,现在我们将使用梯度下降法来找到a和b的最佳值。为此,我们引入了另一个函数--损失函数,并运行梯度下降以最小化损失函数。将F(x)当作“正在进行训练的函数”,其中x仍然是围栏一侧的长度,y是围栏的真实面积。单次预测的绝对误差为: L(x)= | F(x)- y | 我们需要给误差加上绝对值。如果不这样做且连续做两次预测,假设一次错了1000,另一次错了-1000,则两次错误刚好抵消,实际上这样一共错了两次。 最终我们会用这样的一个损失函数:平均绝对误差,它是数据集中所有的点对应L(x)的平均值。使用诸如均方误差之类的指标更为常见,但是不同的损失函数对不同的数据集。 假设我们随机选择权重的起始值:a = -2和b = 30。在对应的F(x)变为: L(x)= | -2x²+ 30x-y | 接下来的内容略带技巧性。我们想要调整a和b的值以最小化损失函数。因此我们需要计算损失函数对a和b的梯度(偏导数)。以前的函数中,x的值可以不断变化。但是这个问题里面,情况并非如此。x的值始终只是我们数据集中的某个固定值。因此单个数据点对应的损失函数为:L(a, b) = ax² + bx – y,其中x、y是常数。 使用平均绝对误差的损失函数为: L(a,b)=1/m*SUM(|F(a,b)—yi|)L(a,b)=(1 / m)* SUM(|axi²+ bxi — yi |) 其中xi和yi代表我们数据集中的单个数据点,而m是我们数据集中点的总数。这里有两个细节上的问题:一个是我们必须使用链式规则来计算涉及绝对值的梯度;另一个是绝对值函数在预测值恰好等于真实值的点上是不可求导的,并且。 如果平均绝对误差为0,可以通过停止计算梯度来解决不可导的问题。这是有实际意义的。如果我们在这个数据点上的预测值与实际值都符,那么就不需要用改善绝对误差的方式来调整模型: d | x |/ dx = 1,如果x为正d | x |/ dx = -1,如果x为负则损失函数对a、b求偏导数可以写成:L(a, b) = (1/m) * SUM( | axi² + bxi — yi | )L’_a(a, b) = (1 / m) * SUM( 1 * xi² ); F(xi) > yiL’_a(a, b) = (1 / m) * SUM( -1 * xi² ); F(xi) < yiL’_b(a, b) = (1 / m) * SUM( 1 * x ); F(xi) > yL’_b(a, b) = (1 / m) * SUM( -1 * x );F(xi) < yi 这些公式实际上为我们提供了一个非常简单的更新规则:如果我们的预测太小,则将a和b都增大。如果我们的预测太大,则将a和b都减小。 深刻地理解梯度下降以及优化损失函数的思路可以更好地理解过拟合之类的问题,同时它还可以帮助我们更好地了解神经网络训练的过程。 1 END 1 长 按 关 注 获取最新AI资讯与实战案例 实用AI客栈 小编微信号 : langu86 本文分享自微信公众号 - 实用AI客栈(gh_0b0b5e56231f)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

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

Git 入门最佳实践

点击上方“民工哥技术之路”,选择“设为星标” 回复“1024”获取独家整理的学习资料! Git简介 Git 是一种分布式版本控制系统,它可以不受网络连接的限制,加上其它众多优点,目前已经成为程序开发人员做项目版本管理时的首选,非开发人员也可以用 Git 来做自己的文档版本管理工具。 2013年,淘宝前端团队开始全面采用 Git 来做项目管理,我也是那个时候开始接触和使用,从一开始的零接触到现在的重度依赖,真是感叹 Git 的强大。 Git 的api很多,但其实平时项目中90%的需求都只需要用到几个基本的功能即可,所以本文将从 实用主义 和 深入探索 2个方面去谈谈如何在项目中使用 Git,一般来说,看完 实用主义 这一节就可以开始在项目中动手用。 说明:本文的操作都是基于 Mac 系统 准备阶段 进入 Git官网下载合适你的安装包,当前我下载到的版本是 2.11.0,本文也将在这个版本上演示效果。安装好 Git 后,打开命令行工具,进入工作文件夹(为了便于理解我们在系统桌面上演示),创建一个新的demo文件夹。进入 Github网站 注册一个账号并登录,进入: https://github.com/gafish/gafish.github.com 点击 Clone or download ,再点击 Use HTTPS,复制项目地址 : https://github.com/gafish/gafish.github.com.git 备用。 再回到命令行工具,一切就绪,接下来进入本文的重点。 常用操作 所谓实用主义,就是掌握了以下知识就可以玩转 Git,轻松应对90%以上的需求。以下是实用主义型的Git命令列表,先大致看一下 gitclonegitconfiggitbranchgitcheckoutgitstatusgitaddgitcommitgitpushgitpullgitloggittag 接下来,将通过对:https://github.com/gafish/gafish.github.com 仓库进行实例操作,讲解如何使用 Git 拉取代码到提交代码的整个流程。 git clone 从git服务器拉取代码 gitclonehttps://github.com/gafish/gafish.github.com.git 代码下载完成后在当前文件夹中会有一个 gafish.github.com 的目录,通过 cd gafish.github.com 命令进入目录。 git config 配置开发者用户名和邮箱 gitconfiguser.namegafishgitconfiguser.emailgafish@qqqq.com 每次代码提交的时候都会生成一条提交记录,其中会包含当前配置的用户名和邮箱。 git branch 创建、重命名、查看、删除项目分支,通过 Git 做项目开发时,一般都是在开发分支中进行,开发完成后合并分支到主干。 gitbranchdaily/0.0.0 创建一个名为 daily/0.0.0 的日常开发分支,分支名只要不包括特殊字符即可。 gitbranch-mdaily/0.0.0daily/0.0.1 如果觉得之前的分支名不合适,可以为新建的分支重命名,重命名分支名为 daily/0.0.1 git branch 通过不带参数的branch命令可以查看当前项目分支列表 gitbranch-ddaily/0.0.1 如果分支已经完成使命则可以通过 -d 参数将分支删除,这里为了继续下一步操作,暂不执行删除操作 git checkout 切换分支 gitcheckoutdaily/0.0.1 切换到 daily/0.0.1 分支,后续的操作将在这个分支上进行 git status 查看文件变动状态 通过任何你喜欢的编辑器对项目中的 README.md 文件做一些改动,保存。 git status 通过 git status 命令可以看到文件当前状态 Changes not staged for commit: (改动文件未提交到暂存区) Onbranchdaily/0.0.1Changesnotstagedforcommit:(use"gitadd<file>..."toupdatewhatwillbecommitted)(use"gitcheckout--<file>..."todiscardchangesinworkingdirectory)modified:README.mdnochangesaddedtocommit(use"gitadd"and/or"gitcommit-a")gitadd 添加文件变动到暂存区 gitaddREADME.md 通过指定文件名 README.md 可以将该文件添加到暂存区,如果想添加所有文件可用 git add . 命令,这时候可通过 git status 看到文件当前状态 Changes to be committed: (文件已提交到暂存区) Onbranchdaily/0.0.1Changestobecommitted:(use"gitresetHEAD<file>..."tounstage)modified:README.md git commit 提交文件变动到版本库 gitcommit-m'这里写提交原因' 通过 -m 参数可直接在命令行里输入提交描述文本 git push 将本地的代码改动推送到服务器 gitpushorigindaily/0.0.1 origin 指代的是当前的git服务器地址,这行命令的意思是把 daily/0.0.1 分支推送到服务器,当看到命令行返回如下字符表示推送成功了。 Countingobjects:3,done.Deltacompressionusingupto8threads.Compressingobjects:100%(2/2),done.Writingobjects:100%(3/3),267bytes|0bytes/s,done.Total3(delta1),reused0(delta0)remote:Resolvingdeltas:100%(1/1),completedwith1localobjects.Tohttps://github.com/gafish/gafish.github.com.git*[newbranch]daily/0.0.1->daily/0.0.1 现在我们回到Github网站的项目首页,点击 Branch:master 下拉按钮,就会看到刚才推送的 daily/00.1分支了 git pull 将服务器上的最新代码拉取到本地 gitpullorigindaily/0.0.1 如果其它项目成员对项目做了改动并推送到服务器,我们需要将最新的改动更新到本地,这里我们来模拟一下这种情况。 进入Github网站的项目首页,再进入 daily/0.0.1 分支,在线对 README.md 文件做一些修改并保存,然后在命令中执行以上命令,它将把刚才在线修改的部分拉取到本地,用编辑器打开 README.md ,你会发现文件已经跟线上的内容同步了。 如果线上代码做了变动,而你本地的代码也有变动,拉取的代码就有可能会跟你本地的改动冲突,一般情况下 Git 会自动处理这种冲突合并,但如果改动的是同一行,那就需要手动来合并代码,编辑文件,保存最新的改动,再通过 git add . 和 git commit -m 'xxx' 来提交合并。 git log 查看版本提交记录 gitlog 通过以上命令,我们可以查看整个项目的版本提交记录,它里面包含了提交人、日期、提交原因等信息,得到的结果如下: commitc334730f8dba5096c54c8ac04fdc2b31ede7107aAuthor:gafish<gafish@qqqq.com>Date:WedJan1109:44:132017+0800UpdateREADME.mdcommitba6e3d21fcb1c87a718d2a73cdd11261eb672b2aAuthor:gafish<gafish@qqqq.com>Date:WedJan1109:31:332017+0800test..... 提交记录可能会非常多,按 J 键往下翻,按 K 键往上翻,按 Q 键退出查看 git tag 为项目标记里程碑 gittagpublish/0.0.1gitpushoriginpublish/0.0.1 当我们完成某个功能需求准备发布上线时,应该将此次完整的项目代码做个标记,并将这个标记好的版本发布到线上,这里我们以 publish/0.0.1 为标记名并发布,当看到命令行返回如下内容则表示发布成功了 Total0(delta0),reused0(delta0)Tohttps://github.com/gafish/gafish.github.com.git*[newtag]publish/0.0.1->publish/0.0.1.gitignore 设置哪些内容不需要推送到服务器,这是一个配置文件 touch.gitignore .gitignore 不是 Git 命令,而在项目中的一个文件,通过设置 .gitignore 的内容告诉 Git 哪些文件应该被忽略不需要推送到服务器,通过以上命令可以创建一个 .gitignore 文件,并在编辑器中打开文件,每一行代表一个要忽略的文件或目录,如: demo.htmlbuild/ 以上内容的意思是 Git 将忽略 demo.html 文件 和 build/ 目录,这些内容不会被推送到服务器上 小结 通过掌握以上这些基本命令就可以在项目中开始用起来了,如果追求实用,那关于 Git 的学习就可以到此结束了,偶尔遇到的问题也基本上通过 Google 也能找到答案,如果想深入探索 Git 的高阶功能,那就继续往下看 深入探索 部分。 深入探索 基本概念 工作区(Working Directory) 就是你在电脑里能看到的目录,比如上文中的 gafish.github.com 文件夹就是一个工作区 本地版本库(Local Repository) 工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。 暂存区(stage) 本地版本库里存了很多东西,其中最重要的就是称为 stage(或者叫index)的暂存区,还有 Git 为我们自动创建的第一个分支 master,以及指向 master 的一个指针叫 HEAD。 远程版本库(Remote Repository) 一般指的是 Git 服务器上所对应的仓库,本文的示例所在的github仓库就是一个远程版本库 以上概念之间的关系:工作区、暂存区、本地版本库、远程版本库之间几个常用的 Git 操作流程如下图所示: 分支(Branch) 分支是为了将修改记录的整个流程分开存储,让分开的分支不受其它分支的影响,所以在同一个数据库里可以同时进行多个不同的修改 主分支(Master)前面提到过 master 是 Git 为我们自动创建的第一个分支,也叫主分支,其它分支开发完成后都要合并到 master标签(Tag) 标签是用于标记特定的点或提交的历史,通常会用来标记发布版本的名称或版本号(如:publish/0.0.1),虽然标签看起来有点像分支,但打上标签的提交是固定的,不能随意的改动,参见上图中的1.0 / 2.0 / 3.0 HEAD HEAD 指向的就是当前分支的最新提交 以上概念了解的差不多,那就可以继续往下看,下面将以具体的操作类型来讲解 Git 的高阶用法 操作文件 gitadd#添加文件到暂存区gitadd-i#通过此命令将打开交互式子命令系统,你将看到如下子命令***Commands***1:status2:update3:revert4:adduntracked5:patch6:diff7:quit8:help 通过输入序列号或首字母可以选择相应的功能,具体的功能解释如下: status:#功能上和gitadd-i相似,没什么鸟用update:#详见下方gitadd-urevert:#把已经添加到暂存区的文件从暂存区剔除,其操作方式和update类似add untracked:#可以把新增的文件添加到暂存区,其操作方式和update类似patch:#详见下方gitadd-pdiff:#比较暂存区文件和本地版本库的差异,其操作方式和update类似quit:#退出gitadd-i命令系统help:#查看帮助信息 gitadd-p 直接进入交互命令中最有用的 patch 模式 这是交互命令中最有用的模式,其操作方式和 update 类似,选择后 Git 会显示这些文件的当前内容与本地版本库中的差异,然后您可以自己决定是否添加这些修改到暂存区,在命令行 Stage deletion [y,n,q,a,d,/,?]? 后输入 y,n,q,a,d,/,? 其中一项选择操作方式,具体功能解释如下: y:接受修改 n:忽略修改 q:退出当前命令 a:添加修改 d:放弃修改 /:通过正则表达式匹配修改内容 ?:查看帮助信息 gitadd-u 直接进入交互命令中的 update 模式 它会先列出工作区 修改 或 删除 的文件列表,新增 的文件不会被显示,在命令行 Update>> 后输入相应的列表序列号表示选中该项,回车继续选择,如果已选好,直接回车回到命令主界面 gitadd--ignore-removal.#添加工作区修改或新增的文件列表,删除的文件不会被添加gitcommit#把暂存区的文件提交到本地版本库gitcommit-m'第一行提交原因'-m'第二行提交原因'#不打开编辑器,直接在命令行中输入多行提交原因gitcommit-am'提交原因'#将工作区修改或删除的文件提交到本地版本库,新增的文件不会被提交gitcommit--amend-m'提交原因'#修改最新一条提交记录的提交原因gitcommit-CHEAD#将当前文件改动提交到HEAD或当前分支的历史IDgitmv#移动或重命名文件、目录gitmva.mdb.md-f#将a.md重命名为b.md,同时添加变动到暂存区,加-f参数可以强制重命名,相比用mva.mdb.md命令省去了gitadd操作gitrm#从工作区和暂存区移除文件gitrmb.md#从工作区和暂存区移除文件b.md,同时添加变动到暂存区,相比用rmb.md命令省去了gitadd操作gitrmsrc/-r#允许从工作区和暂存区移除目录gitstatusgitstatus-s#以简短方式查看工作区和暂存区文件状态,示例如下:Mdemo.html??test.htmlgitstatus--ignored#查看工作区和暂存区文件状态,包括被忽略的文件 操作分支 gitbranch#查看、创建、删除分支gitbranch-a#查看本地版本库和远程版本库上的分支列表gitbranch-r#查看远程版本库上的分支列表,加上-d参数可以删除远程版本库上的分支gitbranch-D#分支未提交到本地版本库前强制删除分支gitbranch-vv#查看带有最后提交id、最近提交原因等信息的本地版本库分支列表 gitmerge#将其它分支合并到当前分支gitmerge--squash#将待合并分支上的commit合并成一个新的commit放入当前分支,适用于待合并分支的提交记录不需要保留的情况 gitmerge--no-ff#默认情况下,Git 执行"快进式合并"(fast-farward merge),会直接将 Master 分支指向 Develop 分支,使用--no-ff 参数后,会执行正常合并,在 Master 分支上生成一个新节点,保证版本演进更清晰。 gitmerge--no-edit#在没有冲突的情况下合并,不想手动编辑提交原因,而是用Git自动生成的类似Mergebranch'test'的文字直接提交gitcheckout#切换分支gitcheckout-bdaily/0.0.1#创建daily/0.0.1分支,同时切换到这个新创建的分支gitcheckoutHEADdemo.html#从本地版本库的HEAD(也可以是提交ID、分支名、Tag名)历史中检出demo.html覆盖当前工作区的文件,如果省略HEAD则是从暂存区检出gitcheckout--orphannew_branch#这个命令会创建一个全新的,完全没有历史记录的新分支,但当前源分支上所有的最新文件都还在,真是强迫症患者的福音,但这个新分支必须做一次 git commit 操作后才会真正成为一个新分支。gitcheckout-pother_branch#这个命令主要用来比较两个分支间的差异内容,并提供交互式的界面来选择进一步的操作,这个命令不仅可以比较两个分支间的差异,还可以比较单个文件的差异。gitstash#在 Git 的栈中保存当前修改或删除的工作进度,当你在一个分支里做某项功能开发时,接到通知把昨天已经测试完没问题的代码发布到线上,但这时你已经在这个分支里加入了其它未提交的代码,这个时候就可以把这些未提交的代码存到栈里。gitstash#将未提交的文件保存到Git栈中gitstashlist#查看栈中保存的列表gitstashshowstash@{0}#显示栈中其中一条记录gitstashdropstash@{0}#移除栈中其中一条记录gitstashpop#从Git栈中检出最新保存的一条记录,并将它从栈中移除gitstashapplystash@{0}#从Git栈中检出其中一条记录,但不从栈中移除gitstashbranchnew_banch#把当前栈中最近一次记录检出并创建一个新分支gitstashclear#清空栈里的所有记录gitstashcreate#为当前修改或删除的文件创建一个自定义的栈并返回一个ID,此时并未真正存储到栈里gitstashstorexxxxxx#将create方法里返回的ID放到store后面,此时在栈里真正创建了一个记录,但当前修改或删除的文件并未从工作区移除$gitstashcreate09eb9a97ad632d0825be1ece361936d1d0bdb5c7$gitstashstore09eb9a97ad632d0825be1ece361936d1d0bdb5c7$gitstashliststash@{0}:Createdvia"gitstashstore". 操作历史 gitlog#显示提交历史记录gitlog-p#显示带提交差异对比的历史记录gitlogdemo.html#显示demo.html文件的历史记录gitlog--since="2weeksago"#显示2周前开始到现在的历史记录,其它时间可以类推gitlog--before="2weeksago"#显示截止到2周前的历史记录,其它时间可以类推gitlog-10#显示最近10条历史记录gitlogf5f630a..HEAD#显示从提交IDf5f630a到HEAD之间的记录,HEAD可以为空或其它提交IDgitlog--pretty=oneline#在一行中输出简短的历史记录gitlog--pretty=format:"%h"#格式化输出历史记录 Git 用各种 placeholder 来决定各种显示内容,我挑几个常用的显示如下: %H:#commithash%h:#缩短的commithash%T:#treehash%t:#缩短的treehash%P:#parenthashes%p:#缩短的parenthashes%an:#作者名字%aN:#mailmap的作者名%ae:#作者邮箱%ad:#日期(--date=制定的格式)%ar:#日期,相对格式(1dayago)%cn:#提交者名字%ce:#提交者email%cd:#提交日期(--date=制定的格式)%cr:#提交日期,相对格式(1dayago)%d:#ref名称%s:#commit信息标题%b:#commit信息内容%n:#换行 gitcherry-pick#合并分支的一条或几条提交记录到当前分支末梢gitcherry-pick170a305#合并提交ID170a305到当前分支末梢gitreset#将当前的分支重设(reset)到指定的<commit>或者HEADgitreset--mixed<commit>#--mixed是不带参数时的默认参数,它退回到某个版本,保留文件内容,回退提交历史gitreset--soft<commit>#暂存区和工作区中的内容不作任何改变,仅仅把HEAD指向<commit>gitreset--hard<commit>#自从<commit>以来在工作区中的任何改变都被丢弃,并把HEAD指向<commit>gitrebase#重新定义分支的版本库状态gitrebasebranch_name#合并分支,这跟 merge 很像,但还是有本质区别,看下图: 合并过程中可能需要先解决冲突,然后执行 git rebase --continue gitrebase-iHEAD~~#打开文本编辑器,将看到从HEAD到HEAD~~的提交如下pick9a54fd4添加commit的说明pick0d4a808添加pull的说明#Rebase326fc9f..0d4a808ontod286baa##Commands:#p,pick=usecommit#r,reword=usecommit,buteditthecommitmessage#e,edit=usecommit,butstopforamending#s,squash=usecommit,butmeldintopreviouscommit#f,fixup=like"squash",butdiscardthiscommit'slogmessage#x,exec=runcommand(therestoftheline)usingshell# 将第一行的 pick 改成 Commands 中所列出来的命令,然后保存并退出,所对应的修改将会生效。 如果移动提交记录的顺序,将改变历史记录中的排序。 gitrevert#撤销某次操作,此次操作之前和之后的commit和history都会保留,并且把这次撤销作为一次最新的提交gitrevertHEAD#撤销前一次提交操作gitrevertHEAD--no-edit#撤销前一次提交操作,并以默认的Revert"xxx"为提交原因gitrevert-nHEAD#需要撤销多次操作的时候加-n参数,这样不会每次撤销操作都提交,而是等所有撤销都完成后一起提交gitdiff#查看工作区、暂存区、本地版本库之间的文件差异,用一张图来解释 gitdiff--stat#通过--stat参数可以查看变更统计数据test.md|1-1filechanged,1deletion(-)gitreflog#reflog可以查看所有分支的所有操作记录(包括commit和reset的操作、已经被删除的commit记录,跟gitlog的区别在于它不能查看已经删除了的commit记录 远程版本库连接 如果在GitHub项目初始化之前,文件已经存在于本地目录中,那可以在本地初始化本地版本库,再将本地版本库跟远程版本库连接起来 gitinit#在本地目录内部会生成.git文件夹gitremote-v#不带参数,列出已经存在的远程分支,加上-v列出详细信息,在每一个名字后面列出其远程urlgitremoteaddoriginhttps://github.com/gafish/gafish.github.com.git#添加一个新的远程仓库,指定一个名字,以便引用后面带的URLgitfetch#将远程版本库的更新取回到本地版本库gitfetchorigindaily/0.0.1#默认情况下,git fetch 取回所有分支的更新。如果只想取回特定分支的更新,可以指定分支名。 问题排查 gitblame#查看文件每行代码块的历史信息gitblame-L1,10demo.html#截取demo.html文件1-10行历史信息gitbisect#二分查找历史记录,排查BUGgitbisectstart#开始二分查找gitbisectbad#标记当前二分提交ID为有问题的点gitbisectgood#标记当前二分提交ID为没问题的点gitbisectreset#查到有问题的提交ID后回到原分支 更多操作 gitsubmodule#通过Git子模块可以跟踪外部版本库,它允许在某一版本库中再存储另一版本库,并且能够保持2个版本库完全独立gitsubmoduleaddhttps://github.com/gafish/demo.gitdemo#将demo仓库添加为子模块gitsubmoduleupdatedemo#更新子模块demogitgc#运行Git的垃圾回收功能,清理冗余的历史快照gitarchive#将加了tag的某个版本打包提取gitarchive-v--format=zipv0.1>v0.1.zip#--format 表示打包的格式,如 zip,-v 表示对应的tag名,后面跟的是tag名,如 v0.1。 总结 本文只是对 Git 的所有功能中的部分实用功能做了一次探秘,Git非常强大,还有很多功能有待我们去发现,限于本文篇幅,咱就此打住吧,预知更多好用功能,请善用谷歌。 转自:gafish 链接:https://github.com/gafish/gafish.github.com 推荐阅读点击标题可跳转 这款老牌国产软件,凉了!!! 刚刚,美团道歉了! 2021 年第一天,华为跟腾讯“干起来”了。。 彻底炸锅!比特币突破3万美元大关,100元狂赚12亿! 审计 Linux 系统的操作行为的 5 种方案对比 每天学一个 Linux 命令(15):man Git重磅推荐!5 款强大的开源报表工具 你知道吗?du 和 df 的统计结果为什么不一样 本文分享自微信公众号 - 民工哥技术之路(jishuroad)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

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

持续部署入门:基于 Kubernetes 实现滚动发布

前言 软件世界比以往任何时候都更快。为了保持竞争力,需要尽快推出新的软件版本,而不会中断活跃用户访问,影响用户体验。越来越多企业已将其应用迁移到 Kubernetes。 在 Kubernetes 中有几种不同的方式发布应用,所以为了让应用在升级期间依然平稳提供服务,选择一个正确的发布策略就非常重要了,本篇文章将讲解如何在 Kubernetes 使用滚动更新的方式更新镜像。 原理 策略定义为 RollingUpdate 的 Deployment。滚动更新通过逐个替换实例来逐步部署新版本的应用,直到所有实例都被替换完成为止,会有新版旧版同时存在的情况。 spec: replicas: 4 strategy: type: RollingUpdate rollingUpdate: maxSurge: 0 # 决定了配置中期望的副本数之外,最多允许超出的 pod 实例的数量 maxUnavailable: %25 # 决定了在滚动升级期间,相对于期望副本数能够允许有多少 pod 实例处于不可用状态 上述更新策略执行结果如下图所示 实践 使用 Kubernetes 原生方式升级应用 准备 image bebullish/demo:v1 bebullish/demo:v2 deployment apiVersion: apps/v1 kind: Deployment metadata: name: demo-dp spec: selector: matchLabels: app: demo replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxSurge: 25% maxUnavailable: 25% template: metadata: labels: app: demo spec: containers: - name: demo image: bebullish/demo:v1 ports: - containerPort: 8080 service apiVersion: v1 kind: Service metadata: name: demo-service spec: selector: app: demo type: LoadBalancer ports: - port: 80 targetPort: 8080 protocol: TCP 将上述 deployment 以及 service 保存为 yaml 文件,使用 kubectl apply -f 命令创建 yaml 资源,等待创建成功后,使用 kubectl get svc 获取 EXTERNAL-IP。 测试 如果使用浏览器测试的话,你会发现每次调用都会返回同一个 pod 的名字,那是因为浏览器发出的请求包含 keepAlive,所以需要使用 curl 来保证每次发出的请求都是重新创建的。 curl -X GET http://${EXTERNAL-IP} 升级 升级之前先执行命令,以便查看镜像更新过程 while true; do curl -X GET http://${EXTERNAL-IP} ; done 更新镜像 kubectl set image deployment demo-dp demo=bebullish/demo:v2 查看日志 请求流量 结论 首先可以发现在更新过程中,程序保持一直可用的状态,在出现了 v2 版本之后,还会出现 v1 版本的日志,说明在这个期间 v1 和 v2 版本是同时存在的,等到 v2 版本的 pod 全部处于就绪状态之后,可以看到所有的请求就都是 v2 版本的了。 使用 CODING CD 方式升级应用 配置制品 使用 docker 官方镜像需要以 docker.io 开头 配置 yaml 及绑定制品 deployment apiVersion: apps/v1 kind: Deployment metadata: name: demo-dp spec: selector: matchLabels: app: demo replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxSurge: 25% maxUnavailable: 25% template: metadata: labels: app: demo spec: containers: - name: demo image: docker.io/bebullish/demo ports: - containerPort: 8080 readinessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 30 # 延迟 30 秒检测,以便更好的观察更新过程 periodSeconds: 5 livenessProbe: httpGet: path: / port: 8080 initialDelaySeconds: 30 # 延迟 30 秒检测,以便更好的观察更新过程 periodSeconds: 5 terminationGracePeriodSeconds: 1 # 处于 Terminating 状态多久后,强制杀死 pod 阶段中选择 部署(Manifest) ,输入上述 yaml 文件(主要增加了就绪探针和存活探针),这里需要把镜像的版本删除掉,在需要绑定的制品选择之前配置的制品。这样配置之后,每次执行的时候版本是动态传入的。 发布制品 选择应用和部署流程,输入版本 v1。 查看结果 等待一小段时间后,就可以在部署控制台中看到发布的资源了。 更新镜像版本 再次执行发布,版本输入 v2。 更新过程 可以看到此时 v2 版本的 pod 有一个正在启动,而 v1 版本的 pod 全部处于就绪状态。 v2 版本的 pod 有一个已经就绪,同时正在启动另一个新的 pod,与此同时 v1 版本的有一个 pod 已经关机了,而另外两个 pod 仍处于就绪状态。 v2 版本的 pod 有两个已经就绪,同时正在启动最后一个新的 pod,与此同时 v1 版本的有两个 pod 已经关机了,而另外一个 pod 仍处于就绪状态。 v2 版本的 pod 已经全部处于就绪状态了,同时 v1 版本的 pod 已经全部关机,至此,一次滚动更新结束。 总结 使用 Kubernetes 原生方式实现滚动更新更加简单方便,但也容易出错(人工),推荐使用 coding.net 提供的 CD 功能,配置一次,永久使用。不仅可以直观的观察到 pod 更新过程,还提供了非常丰富的 CD 功能,推荐使用哦~ 参考文章 Kuerbenetes CODING 持续部署 【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!

资源下载

更多资源
Mario

Mario

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

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册