普通视图

发现新文章,点击刷新页面。
昨天以前Jartto's Blog

好久不见,我想和你聊聊!

作者 Jartto
2025年8月31日 22:41

沉寂了好长时间,很多粉丝邮件问我最近在干啥,是不是转行了?倒是没有转行,只是现在退居幕后了,毕竟是年轻人的时代。既然来了,那就回顾下吧!

时间线

1、2021.9 - 2022.12,进入某互联网大厂,专注前端工程化,做出了基于大前端的DevOps基建。也算是填补了前端架构、工程化方向的空白。回想起来,从那会微前端、低代码、BFF、协同编辑,到工程化,再到架构,也算是完整见证了前端的发展。
2、2023.5 - 2025.5,跟随者AI时代的变革,投入了AI项目,从每周AI资讯,到AI会话基建,再到AI Coding应用,最后到出版AI作品,每一步都写满了故事。历史的长河是惊人的相似,又经历了一次从「人潮拥挤」到「回归平淡」的过程,就像AI的发展:短期被高估,长期被低估。这一步可能是我未来要坚定走下去的!
3、2025.5 - 至今,随着对AI的深入了解,开始喜欢创新类的事情。恰巧关注到3D打印,从此一发不可收拾,业余时间,搞出了很多经典好玩的艺术品,这条路我还会持续探索。如果你也有兴趣,不妨携手前行。

感悟:无从选择才是「贫穷」

年轻人最大的财富不是赚了多少钱,而是做了多少探索,有选择的资本。

利用业余时间折腾了两个公众号,一个搞AI,另一个还是搞AI。回顾起来,为什么走上了AI+3D打印这条路,其实也是从写公众号文章中找到的思路。不断的写,不断的思考,不断地交流,这才是我最大的收获!

1、AI公众号:「2AGI之路」

2、AI+3D打印公众号:「涛哥玩AI

两本代表作

如果你对AI感兴趣,欢迎关注我的实践书籍《AIGC大语言模型轻松学》,京东、当当各大平台热卖中~

如果你对工程化比较关注,这本《Docker实战派》可能会帮到你。


本书已入选『自学入门的编程书 TOP 榜』,京东当当,热卖中!

怎么找到我

如果你对AI+3D感兴趣,欢迎关注我的视频号「涛哥玩3D」。此外,如果你也想加入粉丝群,请加我微信(Jartto),备注:加粉丝群。




用 Tauri+Rust+Yew 来构建你的跨端桌面应用

作者 Jartto
2023年5月16日 06:38

Tauri 可以开发跨平台桌面应用。起先了解 Tauri 的时候,就被它「性能+包体积」的优势所吸引。正好之前有 Electron 开发经验,那不妨来尝试一下!

一、Tauri 是什么

Tauri 是一个框架,可以用于构建轻量级、安全的桌面应用程序。它与现代前端框架(如 Vue.jsReact.js 或者 Svelte)一起使用,使开发者可以用自己熟悉的 Web 技术创建桌面应用。

Tauri 的主要特点包括:

  • 轻量级:Tauri 应用程序比使用 Electron 构建的应用程序更小,更快。这是因为 Tauri 使用 Rust 构建,Rust 是一种性能优越且内存安全的编程语言。
  • 安全性:Tauri 的设计考虑了安全性。它有一个内置的安全层,可以防止一些常见的攻击。
  • 跨平台:Tauri 支持在 WindowsMacLinux 上构建应用程序。

总的来说,Tauri 提供了一种高效、安全的方式来使用 Web 技术构建桌面应用程序。

前置安装

说明文档

Rust + Tauri + Yew

1
2
3
cargo install create-tauri-app
# 初始化项目
cargo create-tauri-app

如果你还没有安装Tauri CLI

1
cargo install tauri-cli

运行项目

1
cargo tauri dev

日志信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Running BeforeDevCommand (`trunk serve`)
2023-03-19T12:51:19.075591Z INFO 📦 starting build
2023-03-19T12:51:19.075822Z INFO spawning asset pipelines
2023-03-19T12:51:19.486709Z INFO building rust-tauri-app-ui
2023-03-19T12:51:19.486759Z INFO copying directory path="public"
2023-03-19T12:51:19.486782Z INFO copying & hashing css path="styles.css"
2023-03-19T12:51:19.487151Z INFO finished copying & hashing css path="styles.css"
2023-03-19T12:51:19.487281Z INFO finished copying directory path="public"
Finished dev [unoptimized + debuginfo] target(s) in 0.17s
2023-03-19T12:51:19.701213Z INFO fetching cargo artifacts
2023-03-19T12:51:19.940618Z INFO processing WASM for rust-tauri-app-ui
2023-03-19T12:51:19.961661Z INFO calling wasm-bindgen for rust-tauri-app-ui
2023-03-19T12:51:20.120952Z INFO copying generated wasm-bindgen artifacts
2023-03-19T12:51:20.122868Z INFO applying new distribution
2023-03-19T12:51:20.123718Z INFO ✅ success
2023-03-19T12:51:20.124694Z INFO 📡 serving static assets at -> /
2023-03-19T12:51:20.124755Z INFO 📡 server listening at http://127.0.0.1:1420
Info Watching /Users/jartto/Documents/Project/rust-tauri-app/src-tauri for changes...
Compiling rust-tauri-app v0.0.0 (/Users/jartto/Documents/Project/rust-tauri-app/src-tauri)
Finished dev [unoptimized + debuginfo] target(s) in 2.29s

效果预览

如果看到如下窗口,意味着应用已经正常启动了。
效果预览

代码说明

Tauri 为您的前端开发提供了其他系统原生功能。 我们将其称作指令,这使得您可以从 JavaScript 前端调用由 Rust 编写的函数。 由此,您可以使用性能飞快的 Rust 代码处理繁重的任务或系统调用。

以下是一个简单示例:

1
2
3
4
5
// src-tauri/src/main.rs
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}

一个指令等于一个普通的 Rust 函数,只是还加上了 #[tauri::command] 宏来让其与您的 JavaScript 环境交互。
最后,我们需要让 Tauri 知悉您刚创建的指令才能让其调用。 我们需要使用 .invoke_handler() 函数及 Generate_handler![] 宏来注册指令:

1
2
3
4
5
6
7
// src-tauri/src/main.rs
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

现在前端可以调用刚注册的指令了!
我们通常会推荐使用 @tauri-apps/api 包,但由于本指南至此还没有使用打包工具,所以需要在 tauri.conf.json 文件中启用 withGlobalTauri 选项。

1
2
3
4
5
6
7
8
{
"build": {
"beforeBuildCommand": "",
"beforeDevCommand": "",
"devPath": "../ui",
"distDir": "../ui",
"withGlobalTauri": true
},

此选项会将已打包版本的 API 函数注入到前端中。接下来,可以修改 index.html 文件来调用指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1 id="header">Welcome from Tauri!</h1>
<script>
// access the pre-bundled global API functions
const { invoke } = window.__TAURI__.tauri

// now we can call our Command!
// You will see "Welcome from Tauri" replaced
// by "Hello, World!"!
invoke('greet', { name: 'World' })
// `invoke` returns a Promise
.then((response) => {
window.header.innerHTML = response
})
</script>
</body>
</html>

应用调试

应用程序调试

打包应用

执行命令

1
cargo tauri build

会报如下错误:

1
2
You must change the bundle identifier in `tauri.conf.json > tauri > bundle > identifier`. The default value `com.tauri.dev` is not allowed as it must be unique across applications.
您必须在 `tauri.conf.json > tauri > bundle > identifier` 中更改包标识符。 默认值 com.tauri.dev 是不允许的,因为它在应用程序中必须是唯一的。

按照提示修改标识符:com.tauri.dev ——> com.tauri.jartto,重新运行打包命令:

1
cargo tauri build

此时,程序已经开始编译:

1
2
3
4
5
6
7
8
9
Compiling serialize-to-javascript v0.1.1
Compiling rust-tauri-app v0.0.0 (/Users/jartto/Documents/Project/rust-tauri-app/src-tauri)
Compiling ignore v0.4.18
Compiling tauri-macros v1.2.1
Compiling serde_repr v0.1.12
Compiling encoding_rs v0.8.32
Compiling state v0.5.3
Compiling embed_plist v1.2.2
Building [=======================> ] 376/377: rust-tauri-app(bin)

我们重点关注最后两行:

1
2
3
Finished 2 bundles at:
/Users/jartto/Documents/Project/rust-tauri-app/target/release/bundle/macos/rust-tauri-app.app
/Users/jartto/Documents/Project/rust-tauri-app/target/release/bundle/dmg/rust-tauri-app_0.0.0_aarch64.dmg

顺着目录可以找到最终打包生成的文件地址,如下:
构建包地址

查看 APP 文件大小:
文件大小

选择 rust-tauri-app_0.0.0_aarch64.dmg 并双击安装,如下:
安装 APP

运行效果就不用说了,和上文效果预览一致。至此,起手项目大功告成!

Docker 新书上市一周年

作者 Jartto
2023年3月19日 12:12

我的新书Docker 实战派:容器入门七步法》上市已经一周年了,在这个里程碑的时刻,感谢各位朋友的支持。希望今年能够持续「大麦」,拿下同类书籍 Top1!


本书已入选『自学入门的编程书 TOP 榜』,京东当当,热卖中!

一、内容回顾

市场上不乏Docker技术相关的书籍,或围绕官方基础文档缺乏新意,或直入源码让新人望而却步。鲜有既满足读者入门需要,又结合企业实际案例的佳作。
Docker实战派:容器入门七步法》正是看到了这一点,另辟蹊径,从读者角度出发,首次提出了「七步法」的概念。

何谓「七步法」?七是人们最容易记住的数字,也是人类瞬间记忆的极限,本书正是立意于此。

第一步,从具象的故事开始,开门见山、降低认知门槛。
第二步,通过「第一个Docker项目」,帮助读者快速上手。在读者建立起体系概念后;
第三步,直切核心原理,围绕Docker架构展开,由浅入深的讲解了Docker底层隔离机制、容器生命周期、网络与通讯、存储原理以及源码。深入剖析,知其然而知其所以然。
第四步,趁热打铁,围绕前后端项目,从全栈角度进行项目实战。
第五步,从Docker容器运维角度出发,进一步补充读者知识图谱,这也是初学者最容易忽视的内容。
第六步,步入高级教程,该部分重点围绕Docker技术最佳实践展开,提供了容器与进程、文件存储与备份、网络配置、镜像优化以及安全策略等内容,示例丰富,操作性十足。
第七步,全书内容升华。通过云原生持续交付模型、企业容器标准化及两个实际的企业级方案,将本书所有内容进行串联。

至此,七步完成。读者可以清晰的感受每一步带来的技术提升,稳扎稳打,从而完全将Docker技术融会贯通。

二、本书亮点

Docker 实战派:容器入门七步法》最大的亮点就是:趣味易懂,案例丰富,实操性强。
(1)趣味易懂
书中较多的原理,剥除了Docker官方文档晦涩难懂的外衣,通过趣味的故事展开。如:通过「盖房子」的比方来理解Docker是什么,通过「别墅与胶囊旅馆」的例子来阐述容器与虚拟机的概念,通过「工厂和车间」来说明进程和线程等。读者无需记忆,就可轻松理解,这也正是本书想要传达的观点——技术并非晦涩难懂,而是缺乏技巧。
(2)案例丰富
本书第二、四、五、六、七章都包含大量的示例。不管是“第一个Docker项目”还是项目实战、或者是「企业案例」都包含了大量的代码讲解。读者完全可以按照教程逐步实现,体验Docker编程的乐趣。
(3)实操性强
值得一提的是,本书中案例均来自于实际的研发过程,为了让读者能够轻松掌握,去除了容器中包含的业务逻辑,保留了Docker容器最核心的架构,实操性强。熟练掌握书中的精彩案例,沉淀其所表现出来的方法论,相信读者一定能够在企业应用中灵活运用,事半功倍。

三、精彩书评

新书推荐

「毋庸讳言,现如今还不了解Docker就不是一个合格的开发者。DockerDevOps的飞速发展具有重要作用。本书结合作者多年一线“大厂”技术实践的经验,既有前端开发者的视角,又有上下游的相关案例,为读者提供了一个完整的DevOps“地图”,可以作为一线开发人员的案头用书。」——高途集团大前端技术通道负责人 黄后锦

Docker作为一种开源的应用容器引擎正在被广泛使用。本书由浅入深地介绍了相关的知识点,将很多不容易理解的概念用生活中的例子生动、形象地表达了出来,对于各个阶段的学习者来说都非常友好。同时,本书从研发岗位的不同视角,介绍了Docker的实践方案,对相关开发者的日常工作具有一定的指导作用。」——字节跳动商业技术营销工程团队负责人 赵龙

「云计算技术的普及,使企业和组织更聚焦于自身的核心业务。而云原生如同“集装箱改变世界”一样,通过标准化的方式来应对业务在打包、部署和管理等过程中遇到的各种挑战,从而帮助企业达到降本增效的目的。容器技术可以说是云原生技术体系结构的基础。而Docker则是容器技术落地的“先驱”,是非常重要的容器技术实现,在整个云原生技术体系中具有重要作用。本书通过一个故事让读者明白Docker是什么,之后通过一个项目带领读者快速上手实践,并帮助读者补充了解Docker的核心原理,而后从项目实践、持续集成与发布、Docker的高级应用、打造企业级应用等方面展开介绍。本书是帮助读者入门Docker的佳作。乐于见到有更多这样的图书来帮助更多有需求的人,帮助他们早日走上云原生的大舞台。」——阿里云边缘云原生技术负责人 周晶

了不起的 Istio

作者 Jartto
2020年7月29日 06:44

很多企业都会面临从单体应用向微服务架构的转型,也会衍生出更多的分布式场景需求。随着规模和复杂度的不断增长,如何才能更好的理解、高效的管理服务网格呢?

本节篇幅较长,我们主要围绕以下几点来展开:
1.什么是服务网格?
2.初识 Istio
3.核心特性
4.流程架构
5.核心模块
6.Envoy 进阶
7.方案畅想

对许多公司来说,DockerKubernetes 这样的工具已经解决了部署问题,或者说几乎解决了。但他们还没有解决运行时的问题,这就是服务网格(Service Mesh)的由来。

一、什么是服务网格?

服务网格(Service Mesh)用来描述组成这些应用程序的微服务网络以及它们之间的交互。它是一个用于保证服务间安全、快速、可靠通信的网络代理组件,是随着微服务和云原生应用兴起而诞生的基础设施层。

它通常以轻量级网络代理的方式同应用部署在一起。比如 Sidecar 方式,如下图所示:

Service Mesh

我们对上图做个解释:
Service Mesh 设计一般划分为两个模块,控制面数据面。对于应用来说,所有流量都会经过数据面进行转发。顺利转发的前提:数据面需要知道转发的目标地址,目标地址本身是由一些业务逻辑来决定的(例如服务发现)。

所以自然而然地,我们可以推断控制面需要负责管理数据面能正常运行所需要的一些配置:

  • 需要知道某次请求转发去哪里:服务发现配置;
  • 外部流量进入需要判断是否已经达到服务流量上限:限流配置;
  • 依赖服务返回错误时,需要能够执行相应的熔断逻辑:熔断配置;

Serivce Mesh 可以看作是一个位于 TCP/IP 之上的网络模型,抽象了服务间可靠通信的机制。但与 TCP 不同,它是面向应用的,为应用提供了统一的可视化和控制。

1.Service Mesh 具有如下优点:

  • 屏蔽分布式系统通信的复杂性(负载均衡、服务发现、认证授权、监控追踪、流量控制等等),服务只用关注业务逻辑;
  • 真正的语言无关,服务可以用任何语言编写,只需和 Service Mesh 通信即可;
  • 对应用透明,Service Mesh 组件可以单独升级;

2.Service Mesh 目前也面临一些挑战:

  • Service Mesh 组件以代理模式计算并转发请求,一定程度上会降低通信系统性能,并增加系统资源开销;
  • Service Mesh 组件接管了网络流量,因此服务的整体稳定性依赖于 Service Mesh,同时额外引入的大量 Service Mesh 服务实例的运维和管理也是一个挑战;

随着服务网格的规模和复杂性不断的增长,它将会变得越来越难以理解和管理。

Service Mesh 的需求包括服务发现、负载均衡、故障恢复、度量和监控等。Service Mesh 通常还有更复杂的运维需求,比如 A/B 测试、金丝雀发布、速率限制、访问控制和端到端认证。

Service Mesh的出现,弥补了 Kubernetes 在微服务的连接、管理和监控方面的短板,为 Kubernetes 提供更好的应用和服务管理。因此,Service Mesh 的代表 Istio 一经推出,就被认为是可以和 Kubernetes 形成双剑合璧效果的微服务管理的利器,受到了业界的推崇。

Istio 提供了对整个服务网格的行为洞察和操作控制的能力,以及一个完整的满足微服务应用各种需求的解决方案。Istio 主要采用一种一致的方式来保护、连接和监控微服务,降低了管理微服务部署的复杂性。

二、初识 Istio

Istio 发音「意丝帝欧」,重音在上。官方给出的 Istio 的总结,简单明了:

1
Istio lets you connect, secure, control, and observe services.

连接、安全、控制和观测服务。

初识 Istio

简单来说,Istio 针对现有的服务网格,提供一种简单的方式将连接、安全、控制和观测的模块,与应用程序或服务隔离开来,从而开发人员可以将更多的精力放在核心的业务逻辑上,以下是 Istio 的核心功能:

1.HTTPgRPCWebSocketTCP 流量的自动负载均衡;
2.通过丰富的路由规则、重试、故障转移和故障注入,可以对流量行为进行细粒度控制;
3.可插入的策略层和配置 API,支持访问控制、速率限制和配额;
4.对出入集群入口和出口中所有流量的自动度量指标、日志记录和追踪;
5.通过强大的基于身份的验证和授权,在集群中实现安全的服务间通信;

从较高的层面来说,Istio 有助于降低这些部署的复杂性,并减轻开发团队的压力。它是一个完全开源的服务网格,作为透明的一层接入到现有的分布式应用程序里。它也是一个平台,拥有可以集成任何日志、遥测和策略系统的 API 接口。

Istio 多样化的特性使我们能够成功且高效地运行分布式微服务架构,并提供保护、连接和监控微服务的统一方法。

三、核心特性

Istio 以统一的方式提供了许多跨服务网格的关键功能:
官方介绍

1.流量管理
Istio 简单的规则配置和流量路由允许我们控制服务之间的流量和 API 调用过程。Istio 简化了服务级属性(如熔断器、超时和重试)的配置,并且让它轻而易举的执行重要的任务(如 A/B 测试、金丝雀发布和按流量百分比划分的分阶段发布)。

有了更好的对流量的可视性和开箱即用的故障恢复特性,我们就可以在问题产生之前捕获它们,无论面对什么情况都可以使调用更可靠,网络更健壮。

2.安全

Istio 的安全特性解放了开发人员,使其只需要专注于应用程序级别的安全。

Istio 提供了底层的安全通信通道,并为大规模的服务通信管理认证、授权和加密。有了 Istio,服务通信在默认情况下就是受保护的,可以在跨不同协议和运行时的情况下实施一致的策略,而所有这些都只需要很少甚至不需要修改应用程序。

Istio 是独立于平台的,可以与 Kubernetes(或基础设施)的网络策略一起使用。但它更强大,能够在网络和应用层面保护 PodPod 或者服务到服务之间的通信。

3.可观察性
Istio 健壮的追踪、监控和日志特性让我们能够深入的了解服务网格部署。通过 Istio 的监控能力,可以真正的了解到服务的性能是如何影响上游和下游的。而它的定制 Dashboard 提供了对所有服务性能的可视化能力,并让我们看到它如何影响其他进程。

IstioMixer 组件负责策略控制遥测数据收集。它提供了后端抽象和中介,将一部分 Istio与后端的基础设施实现细节隔离开来,并为运维人员提供了对网格与后端基础实施之间交互的细粒度控制。

所有这些特性都使我们能够更有效地设置、监控和加强服务的 SLO。当然,底线是我们可以快速有效地检测到并修复出现的问题。

4.平台支持
Istio 独立于平台,被设计为可以在各种环境中运行,包括跨云、内部环境、KubernetesMesos 等等。我们可以在 Kubernetes 或是装有 ConsulNomad 环境上部署 Istio

Istio 目前支持:

  • Kubernetes 上的服务部署
  • 基于 Consul 的服务注册
  • 服务运行在独立的虚拟机上

5.整合和定制
Istio 的策略实施组件可以扩展和定制,与现有的 ACL、日志、监控、配额、审查等解决方案集成。

四、流程架构

Istio 服务网格逻辑上分为数据平面Control Plane)和控制平面Data Plane),架构图如下所示:

Istio 架构图

1.数据平面Data Plane由一组以 Sidecar 方式部署的智能代理 Envoy 组成。

Envoy 被部署为 Sidecar,和对应服务在同一个 Kubernetes pod 中。这允许 Istio 将大量关于流量行为的信号作为属性提取出来,而这些属性又可以在 Mixer 中用于执行策略决策,并发送给监控系统,以提供整个网格行为的信息。

这些代理可以调节和控制微服务及 Mixer 之间所有的网络通信。

2.控制平面Control Plane负责管理和配置代理来路由流量,此外配置 Mixer 以实施策略和收集遥测数据。主要包含如下几部分内容:

  • Mixer:策略和请求追踪;
  • Pilot:提供服务发现功能,为智能路由(例如 A/B 测试、金丝雀部署等)和弹性(超时、重试、熔断器等)提供流量管理功能;
  • Citadel:分发 TLS 证书到智能代理;
  • Sidecar injector:可以允许向应用中无侵入的添加功能,避免为了满足第三方需求而添加额外的代码;

五、核心模块

上文提到了很多技术名词,我们需要重点解释一下:

1.什么是 Sidecar 模式?
Sidecar 是一种将应用功能从应用本身剥离出来作为单独进程的设计模式,可以允许向应用中无侵入的添加功能,避免为了满足第三方需求而添加额外的代码。

在软件架构中,Sidecar 附加到主应用,或者叫父应用上,以扩展、增强功能特性,同时 Sidecar 与主应用是松耦合的。

Sidecar 是一种单节点多容器的应用设计形式,主张以额外的容器来扩展或增强主容器。

2.Envoy 的作用是什么?
Envoy 是一个独立的进程,旨在与每个应用程序服务器一起运行。所有 Envoy 组成了一个透明的通信网格,其中每个应用程序发送和接收来自本地主机的消息,并且不需要知道网络拓扑。

与传统的服务通信服务的库方法相比,进程外架构有两个实质性好处:

  • Envoy 支持任何编程语言写的服务。只用部署一个 Envoy 就可以在 JavaC++GoPHPPython 等服务间形成网格。
  • 任何使用过大型面向服务的体系结构的人都知道,部署库升级可能会非常痛苦。Envoy 可以在整个基础设施中迅速部署和升级。

Envoy 以透明的方式弥合了面向服务的体系结构使用多个应用程序框架和语言的情况。

3.Mixer
Mixer 是一个独立于平台的组件,负责在服务网格上执行访问控制使用策略,并从 Envoy 代理和其他服务收集遥测数据,代理提取请求级属性,发送到 Mixer 进行评估。有关属性提取和策略评估的更多信息,请参见 Mixer 配置。

Mixer 中包括一个灵活的插件模型,使其能够接入到各种主机环境和基础设施后端,从这些细节中抽象出 Envoy 代理和 Istio 管理的服务。

4.Pilot
控制面中负责流量管理的组件为 Pilot,它为 Envoy Sidecar 提供服务发现功能,为智能路由(例如 A/B 测试、金丝雀部署等)和弹性(超时、重试、熔断器等)提供流量管理功能。它将控制流量行为的高级路由规则转换为特定于 Envoy 的配置,并在运行时将它们传播到 Sidecar

5.Istio 如何保证服务通信的安全?

  • Istio 以可扩缩的方式管理微服务间通信的身份验证、授权和加密Istio 提供基础的安全通信渠道,使开发者可以专注于应用层级的安全。

  • Istio 可以增强微服务及其通信(包括服务到服务和最终用户到服务的通信)的安全性,且不需要更改服务代码。

    它为每个服务提供基于角色的强大身份机制,以实现跨集群、跨云端的互操作性。

  • 如果我们结合使用 IstioKubernetes(或基础架构)网络政策,PodPod 或服务到服务的通信在网络层和应用层都将安全无虞。IstioGoogle深度防御策略为基础构建而成,以确保微服务通信的安全。

    当我们在 Google Cloud 中使用 Istio 时,Google 的基础架构可让我们构建真正安全的应用部署。

  • Istio 可确保服务通信在默认情况下是安全的,并且我们可以跨不同协议和运行时一致地实施安全政策,而只需对应用稍作调整,甚至无需调整。

六、Envoy 进阶

Istio 使用 Envoy 代理的扩展版本,Envoy 是以 C++ 开发的高性能代理,用于调解服务网格中所有服务的所有入站和出站流量

Envoy 的许多内置功能被 Istio 发扬光大,例如:

  • 动态服务发现
  • 负载均衡
  • TLS 终止
  • HTTP2 & gRPC 代理
  • 熔断器
  • 健康检查、基于百分比流量拆分的灰度发布
  • 故障注入
  • 丰富的度量指标

Envoy 分为主线程、工作线程、文件刷新线程,其中主线程就是负责工作线程和文件刷新线程的管理和调度。而工作线程主要负责监听、过滤和转发,工作线程里面会包含一个监听器,如果收到一个请求之后会通过过滤链来进行数据过滤。前面两个都是非阻塞的,唯一一个阻塞的是这种 IO 操作的,会不断地把内存里面一些缓存进行落盘。

总结来说,我们可以围绕如下 5 方面:

1.服务的动态注册和发现

Envoy 可以选择使用一组分层的动态配置 API 来进行集中管理。

这些层为 Envoy 提供了动态更新,后端群集的主机、后端群集本身、HTTP 路由、侦听套接字和通信加密。为了实现更简单的部署,后端主机发现可以通过 DNS 解析 (甚至完全跳过) 完成,层也可以替换为静态配置文件。

2.健康检查
构建 Envoy 网格的建议方法是将服务发现视为最终一致的过程。 Envoy 包括一个运行状况检查子系统,该子系统可以选择对上游服务集群执行主动运行状况检查。

然后,Envoy 使用服务发现和运行状况检查信息的联合来确定健康的负载均衡服务器。Envoy 还支持通过异常检测子系统进行被动运行状况检查。

3.高级负载均衡

分布式系统中不同组件之间的负载平衡是一个复杂的问题。

由于 Envoy 是一个独立的代理而不是库,因此它能够在一个位置实现高级负载平衡技术,并使任何应用程序都可以访问。

目前 Envoy 包括支持自动重试、断路、通过外部速率限制服务限制全局速率、请求隐藏和异常值检测。未来计划为 Request Racing 提供支持。

4.前端/边缘系统代理支持
虽然 Envoy 主要是为服务通信系统而设计的,但对前端/边缘系统也是很有用的,如:可观测性、管理、相同的服务发现和负载平衡算法等。

Envoy 包含足够的功能,使其可用作大多数 Web 应用服务用例的边缘代理。这包括作为 TLS 的终点、HTTP/1.1HTTP/2 支持, 以及 HTTP L7 路由。

5.最好的观察统计能力
Envoy 的首要目标是使网络透明。但是在网络级别和应用程序级都无法避免的容易出现问题。Envoy 包含了对所有子系统的强有力的统计支持。 statsd 和其他兼容的数据提供程序是当前支持的统计接收器,插入不同的统计接收器也并不困难。

Envoy 可以通过管理端口查看统计信息,还支持通过第三方供应商进行分布式追踪。

更多详情请参考:什么是 Envoy ?

七、方案畅想

应用上面的原理,我们可以有很多具体的方案应用于日常开发。

1.方案一:应用 Istio 改造微服务
模仿在线书店的一个分类,显示一本书的信息。 页面上会显示一本书的描述,书籍的细节(ISBN、页数等),以及关于这本书的一些评论。

应用的端到端架构:Bookinfo 应用中的几个微服务是由不同的语言编写的。 这些服务对 Istio 并无依赖,但是构成了一个有代表性的服务网格的例子:它由多个服务、多个语言构成,并且 reviews 服务具有多个版本。

Bookinfo 架构图

Istio 改造后架构如下:要在 Istio 中运行这一应用,无需对应用自身做出任何改变。我们只需要把 Envoy Sidecar 注入到每个服务之中。最终的部署结果将如下图所示:

Istio 改造后架构图

所有的微服务都和 Envoy Sidecar 集成在一起,被集成服务所有的出入流量都被 Sidecar 所劫持,这样就为外部控制准备了所需的 Hook,然后就可以利用 Istio 控制平面为应用提供服务路由、遥测数据收集以及策略实施等功能。

更多细节,请移步 官网示例

2.方案二:用 Istio 改造 CI/CD 流程
Istio 架构图

对上述流程图简单解释一下:

  • 通过 Docker 对代码进行容器化处理;
  • 通过 Gitlab 托管代码;
  • Jenkins 监听 Gitlab 下的代码,触发自动构建,并执行 Kustomize 文件;
  • Kustomize 通过配置文件,设置了 Istio 的配置(染色识别、流量分发),并启动 K8s 部署应用;
  • 最终我们通过 Rancher 来对多容器进行界面化管理;
  • 打开浏览器进行访问;

看到这里,相信你也了解了,我们实现了一个前端多容器化部署的案例。它有什么意义呢?

  • 首先,当然是环境隔离了,研发每人一个容器开发,互不干扰;
  • 其次,我们可以做很多小流量、灰度发布等事情;
  • 自动化部署,一站式的流程体验;

如果你对容器化还不太了解,请先看看前面两篇文章:
Docker 边学边用
一文了解 Kubernetes

Istio 还是有很多可圈可点的地方,相信看到这里你也有了更全面的认识。如果你想深入了解,不妨仔细研究官方示例,并且在实际项目中不断打磨。

八、参考资料

1.Istio 官网
2.什么是 Envoy
3.微服务之 Service Mesh
4.什么是 Service Mesh
5.Istio 如何连接、管理和保护微服务 2.0?
6.在 MOSN 中玩转 dubbo-go

一文了解 Kubernetes

作者 Jartto
2020年7月15日 06:12

上一节我们着重讲解了 Docker,其实遗留了一个大问题。Docker 虽好用,但面对强大的集群,成千上万的容器,突然感觉不香了。

这时候就需要我们的主角 Kubernetes 上场了,先来了解一下 K8s 的基本概念,后面再介绍实践,由浅入深步步为营。

关于 K8s 的基本概念,我们将会围绕如下七点展开:
1.Docker 的管理痛点
2.什么是 K8s
3.云架构 & 云原生
4.K8s 架构原理
5.K8s 核心组件
6.K8s 的服务注册与发现
7.关键问题

一、Docker 的管理痛点

如果想要将 Docker 应用于庞大的业务实现,是存在困难的编排管理调度问题。于是,我们迫切需要一套管理系统,对 Docker 及容器进行更高级更灵活的管理。

Kubernetes 应运而生!Kubernetes,名词源于希腊语,意为「舵手」或「飞行员」。Google2014 年开源了 Kubernetes 项目,建立在 Google 在大规模运行生产工作负载方面拥有十几年的经验的基础上,结合了社区中最好的想法和实践。

K8s 是 Kubernetes 的缩写,用 8 替代了 「ubernete」,下文我们将使用简称。

二、什么是 K8s ?

K8s 介绍
K8s 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化K8s 拥有一个庞大且快速增长的生态系统。K8s 的服务、支持和工具广泛可用。

通过 K8s 我们可以:
1.快速部署应用
2.快速扩展应用
3.无缝对接新的应用功能
4.节省资源,优化硬件资源的使用

K8s 有如下特点:
1.可移植: 支持公有云,私有云,混合云,多重云 multi-cloud
2.可扩展: 模块化,插件化,可挂载,可组合
3.自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展

三、云架构 & 云原生

1.云和 K8s 是什么关系
云就是使用容器构建的一套服务集群网络,云由很多的大量容器构成。K8s 就是用来管理云中的容器。

2.常见几类云架构

  • On-Premises (本地部署)
  • iaas(基础设施即服务)
    • 用户:租用(购买|分配权限)云主机,用户不需要考虑网络,DNS,硬件环境方面的问题。
    • 运营商:提供网络,存储,DNS,这样服务就叫做基础设施服务
  • paas(平台即服务)
    • mysql/es/mq/...
  • saas(软件即服务)
    • 钉钉
    • 财务管理
  • serverless
    • 无服务,不需要服务器。站在用户的角度考虑问题,用户只需要使用云服务器即可,在云服务器所在的基础环境,软件环境都不需要用户关心。

常见云架构图示

如果觉得不好理解,推荐阅读这篇文章:如何通俗解释 IaaS、PaaS、SaaS 的区别

可以预见:未来服务开发都是 Serverless,企业都构建了自己的私有云环境,或者是使用公有云环境。

3.云原生
为了让应用程序(项目,服务软件)都运行在云上的解决方案,这样的方案叫做云原生

云原生有如下特点:

  • 容器化,所有服务都必须部署在容器中
  • 微服务,Web 服务架构式服务架构
  • CI/CD
  • DevOps

四、K8s 架构原理

1.K8s 架构
概括来说 K8s 架构就是一个 Master 对应一群 Node 节点。

K8s 架构图示

下面我们来逐一介绍 K8s 架构图中的 MasterNode

2.Master 节点结构如下:

  • apiserverK8s 网关,所有的指令请求都必须要经过 apiserver
  • scheduler 调度器,使用调度算法,把请求资源调度到某一个 node 节点;
  • controller 控制器,维护 K8s 资源对象;
  • etcd 存储资源对象;

3.Node节点

  • kubelet 在每一个 node 节点都存在一份,在 node 节点上的资源操作指令由 kubelet 来执行;
  • kube-proxy 代理服务,处理服务间负载均衡;
  • podk8s 管理的基本单元(最小单元),pod 内部是容器,k8s 不直接管理容器,而是管理pod
  • docker 运行容器的基础环境,容器引擎;
  • fluentd 日志收集服务;

在介绍完 K8s 架构后,我们又引入了很多技术名词。不要着急,先有整体概念,再各个击破。请耐心阅读下文,相信你一定会有不一样的收获。

五、K8s 核心组件

1.K8s 组件
K8s 是用来管理容器,但是不直接操作容器,最小操作单元是 Pod (间接管理容器)

  • 一个 Master 有一群 Node 节点与之对应
  • Master 节点不存储容器,只负责调度、网管、控制器、资源对象存储
  • 容器的存储在 Node 节点,容器是存储在 Pod 内部的)
  • Pod 内部可以有一个容器,或者多个容器
  • Kubelet 负责本地 Pod 的维护
  • Kube-proxy 负责负载均衡,在多个 Pod 之间来做负载均衡

2.Pod 是什么?

  • pod 也是一个容器,这个容器中装的是 Docker 创建的容器,Pod 用来封装容器的一个容器,Pod 是一个虚拟化分组;
  • Pod 相当于独立主机,可以封装一个或者多个容器;

Pod 有自己的 IP 地址、主机名,相当于一台独立沙箱环境。

3.Pod 到底用来干什么?
通常情况下,在服务部署时候,使用 Pod 来管理一组相关的服务。一个 Pod 中要么部署一个服务,要么部署一组有关系的服务。

一组相关的服务是指:在链式调用的调用连路上的服务。

4.Web 服务集群如何实现?
实现服务集群:只需要复制多方 Pod 的副本即可,这也是 K8s 管理的先进之处,K8s 如果继续扩容,只需要控制 Pod 的数量即可,缩容道理类似。

5.Pod 底层网络,数据存储是如何进行的?

  • Pod 内部容器创建之前,必须先创建 Pause 容器;
  • 服务容器之间访问 localhost ,相当于访问本地服务一样,性能非常高;

6.ReplicaSet 副本控制器
控制 Pod 副本「服务集群」的数量,永远与预期设定的数量保持一致即可。当有 Pod 服务宕机时候,副本控制器将会立马重新创建一个新的 Pod,永远保证副本为设置数量。

副本控制器:标签选择器-选择维护一组相关的服务(它自己的服务)

1
2
3
selector:
app = web
Release = stable

  • ReplicationController 副本控制器:单选
  • ReplicaSet 副本控制器:单选,复合选择

在新版的 K8s 中,建议使用 ReplicaSet 作为副本控制器,ReplicationController 不再使用了。

7.Deployment 部署对象

  • 服务部署结构模型
  • 滚动更新

ReplicaSet 副本控制器控制 Pod 副本的数量。但是,项目的需求在不断迭代、不断的更新,项目版本将会不停的的发版。版本的变化,如何做到服务更新?

部署模型:

  • ReplicaSet 不支持滚动更新,Deployment 对象支持滚动更新,通常和 ReplicaSet 一起使用;
  • Deployment 管理 ReplicaSetRS 重新建立新的 RS,创建新的 Pod

8.MySQL 使用容器化部署,存在什么样的问题?

  • 容器是生命周期的,一旦宕机,数据丢失
  • Pod 部署,Pod 有生命周期,数据丢失

对于 K8s 来说,不能使用 Deployment 部署有状态服务。

通常情况下,Deployment 被用来部署无状态服务,那么对于有状态服务的部署,使用 StatefulSet 进行有状态服务的部署。

什么是有状态服务

  • 有实时的数据需要存储
  • 有状态服务集群中,把某一个服务抽离出去,一段时间后再加入机器网络,如果集群网络无法使用

什么是无状态服务

  • 没有实时的数据需要存储
  • 无状态服务集群中,把某一个服务抽离出去,一段时间后再加入机器网络,对集群服务没有任何影响

9.StatefulSet
为了解决有状态服务使用容器化部署的一个问题。

  • 部署模型
  • 有状态服务

StatefulSet 保证 Pod 重新建立后,Hostname 不会发生变化,Pod 就可以通过 Hostname 来关联数据。

六、K8s 的服务注册与发现

1.Pod 的结构是怎样的?

  • Pod 相当于一个容器,Pod 有独立 IP 地址,也有自己的 Hostname,利用 Namespace 进行资源隔离,独立沙箱环境。
  • Pod 内部封装的是容器,可以封装一个,或者多个容器(通常是一组相关的容器)

2.Pod 网络

  • Pod 有自己独立的 IP 地址
  • Pod 内部容器之间访问采用 Localhost 访问

Pod 内部容器访问是 Localhost,Pod 之间的通信属于远程访问。

3.Pod 是如何对外提供服务访问的?
Pod 是虚拟的资源对象(进程),没有对应实体(物理机,物理网卡)与之对应,无法直接对外提供服务访问。

那么该如何解决这个问题呢?
Pod 如果想要对外提供服务,必须绑定物理机端口。也就是说在物理机上开启端口,让这个端口和 Pod 的端口进行映射,这样就可以通过物理机进行数据包的转发。

概括来说:先通过物理机 IP + Port 进行访问,再进行数据包转发。

4.一组相关的 Pod 副本,如何实现访问负载均衡?
我们先明确一个概念,Pod 是一个进程,是有生命周期的。宕机、版本更新,都会创建新的 Pod。这时候 IP 地址会发生变化,Hostname 会发生变化,使用 Nginx 做负载均衡就不太合适了。

所以我们需要依赖 Service 的能力。

5.Service 如何实现负载均衡?
简单来说,Service 资源对象包括如下三部分:

  • Pod IPPodIP 地址
  • Node IP:物理机 IP 地址
  • Cluster IP:虚拟 IP ,是由 K8s 抽象出的 Service 对象,这个 Service 对象就是一个 VIP 的资源对象

6.Service VIP 更深入原理探讨

  • ServicePod 都是一个进程,Service 也不能对外网提供服务;
  • ServicePod 之间可以直接进行通信,它们的通信属于局域网通信;
  • 把请求交给 Service 后,Service 使用 iptableipvs 做数据包的分发;

7.Service 对象是如何和 Pod 进行关联的?

  • 不同的业务有不同的 Service
  • ServicePod 通过标签选择器进行关联;
    1
    2
    3
    selector:
    app=x 选择一组订单的服务 pod ,创建一个 service;
    通过 endpoints 存放一组 pod ip;

Service 通过标签选择器选择一组相关的副本,然后创建一个 Service

8.Pod 宕机、发布新的版本的时候,Service 如何发现 Pod 已经发生了变化?
每个 Pod 中都有 Kube-Proxy,监听所有 Pod。如果发现 Pod 有变化,就动态更新(etcd 中存储)对应的 IP 映射关系。

七、关键问题

1.企业使用 K8s 主要用来做什么?

  • 自动化运维平台
    创业型公司,中小型企业,使用 K8s 构建一套自动化运维平台,自动维护服务数量,保持服务永远和预期的数据保持一致性,让服务可以永远提供服务。这样最直接的好处就是降本增效。

  • 充分利用服务器资源
    互联网企业,有很多服务器资源「物理机」,为了充分利用服务器资源,使用 K8s 构建私有云环境,项目运行在云。这在大型互联网公司尤为重要

  • 服务的无缝迁移
    项目开发中,产品需求不停的迭代,更新产品。这就意味着项目不停的发布新的版本,而 K8s 可以实现项目从开发到生产无缝迁移。

2.K8s 服务的负载均衡是如何实现的?
Pod 中的容器很可能因为各种原因发生故障而死掉。DeploymentController 会通过动态创建和销毁 Pod 来保证应用整体的健壮性。换句话说,Pod 是脆弱的,但应用是健壮的。每个 Pod 都有自己的 IP 地址。当 controller 用新 Pod 替代发生故障的 Pod 时,新 Pod 会分配到新的 IP 地址。

这样就产生了一个问题:如果一组 Pod 对外提供服务(比如 HTTP),它们的 IP 很有可能发生变化,那么客户端如何找到并访问这个服务呢?

K8s 给出的解决方案是 ServiceKubernetes Service 从逻辑上代表了一组 Pod,具体是哪些 Pod 则是由 Label 来挑选。

Service 有自己 IP,而且这个 IP 是不变的。客户端只需要访问 ServiceIPK8s 则负责建立和维护 ServicePod 的映射关系。无论后端 Pod 如何变化,对客户端不会有任何影响,因为 Service 没有变。

3.无状态服务一般使用什么方式进行部署?
DeploymentPodReplicaSet 提供了一个 声明式定义方法,通常被用来部署无状态服务。

Deployment 的主要作用:
定义 Deployment 来创建 PodReplicaSet 滚动升级和回滚应用扩容和索容暂停和继续。Deployment不仅仅可以滚动更新,而且可以进行回滚,如果发现升级到 V2 版本后,服务不可用,可以迅速回滚到 V1 版本。

Web「性能测试」知多少?

作者 Jartto
2020年4月5日 21:44

身为前端的你,是否会有这样的烦恼:随着访问用户的成倍增加,站点变得越来越脆弱。任何的访问过慢或崩溃都将是一场灾难。

这就对我们工程师提出了更高的要求,要保障网站的「可访问性」和「稳定性」都维持在一个较高水平。那么,是时候了解了解 Web 性能测试了!

一、情景再现

有一个大型推广活动来了,类似与抢火车票、淘宝双十一,你能否回答 Boss 的如下问题?
1.我们的网站是否能扛住如此的高并发?
2.服务器单机 QPS 是多少?
3.如果站点扛不住,扩容的话,需要几台?

一连串的问题,如果你招架不住,不妨仔细阅读本文

二、什么是性能测试?

要回答上面的问题,需要我们有一些知识储备。不着急,循序渐进,各个击破。

一般来说「性能测试」包括压力测试、负载测试、容量测试三种主要测试类型。

1.压力测试 StressTest
压力测试可以测试网站在某个特定的持续的压力下运行的稳定性。

2.负载测试 LoadTest
负载测试是为了检验系统在给定负载下是否能达到预期性能指标。

3.容量测试 CapabilityTest
容量测试针对数据库而言,是在数据库中有较大数量的数据记录情况下对系统进行的测试。

内容比较多,为了专注聚焦,我们本节主要来看一下压力测试。

三、压力测试

压力测试是通过不断向被测系统施加压力,测试系统在压力情况下的性能表现。主要考察当前软硬件环境下系统所能承受的最大负荷并帮助开发人员找出系统瓶颈所在。我们可以模拟巨大的流量请求以查看应用程序在峰值使用情况以及服务器状况。

有效的压力测试将应用以下这些关键条件:重复,并发,量级,随机变化。

需要注意的是:压力测试并不会报告是什么导致了问题。它只会报告这有了问题,例如:查询页面在并发 1000 个用户使用时变慢下来,但它不会显示什么导致了变慢。

捕获到的性能统计数据例如 CPU 和内存使用量只是强调了潜在的问题区域,但并不会指出实际的根源在应用程序的什么地方。

更多的概念可以查看:为什么要进行压力测试?

四、核心指标

了解了上述压力测试之后,我们先不着急进行网站压测,补充几个可以让你事半功倍的核心指标:

1.什么是 TPS
Transactions Per Second 的缩写,每秒处理的事务数目。一个事务是指一个客户机向服务器发送请求然后服务器做出反应的过程。客户机在发送请求时开始计时,收到服务器响应后结束计时,以此来计算使用的时间和完成的事务个数,最终利用这些信息作出的评估分。

一个事务可能对应多个请求,这与数据库的事务操作极其相似。

2.什么是 QPS
Queries Per Second 的缩写,每秒能处理查询数目,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。

需要注意的是:虽然名义上是查询的意思,但实际上,现在习惯于对单一接口服务的处理能力用 QPS 进行表述(即使它并不是查询操作)。

3.什么是 RT
响应时间,处理一次请求所需要的平均处理时间。我们一般会关注 90th 请求的的处理时间,因为可能因网络情况出现极端情况,长尾数据会对我们产生干扰。

4.系统 CPU 利用率
如果系统的 CPU 使用率已经很高,说明我们的系统是个计算度很复杂的系统,这时候如果 QPS 已经上不去了,就需要赶紧扩容,通过增加机器分担计算的方式来提高系统的吞吐量。

5.系统内存
如果 CPU 使用率一般,但是系统的 QPS 上不去,说明我们的机器并没有忙于计算,而是受到其他资源的限制,如内存、I/O。这时候首先看下内存是不是已经不够了,如果内存不够了,那就赶紧扩容了。

五、QPS 如何计算?

QPS 并没有准确的计算公式,但是实际压测中我们完全可以按照如下模型进行估算:

原理:每天 80% 的访问集中在 20% 的时间里,这 20% 时间叫做「峰值时间」。

公式:( 总 PV 80% ) / ( 每天秒数 20% ) = 峰值时间每秒请求数(QPS)
机器:峰值时间每秒 QPS / 单台机器的 QPS = 需要的机器

问:每天 300w PV 的在单台机器上,这台机器需要多少 QPS
答:( 3000000 * 0.8 ) / (86400 * 0.2 ) = 139 (QPS)

问:如果一台机器的 QPS58 ,需要几台机器来支持?
答:139 / 58 = 3

具体的计算公式可以参考这篇文章:峰值 QPS 和机器计算公式

六、推荐工具

压测工具有很多,JMeterLoadRunnerWebLoadNeoLoadLoadsterTcpCopyABWebBench 等等,恐怕一时间无法说完。但是论起上手能力,就要说说我们的主角 wrk 了。

wrk 是一款针对 Http 协议的基准测试工具,它能够在单机多核 CPU 的条件下,使用系统自带的高性能 I/O 机制,如 EpollKqueue 等,通过多线程和事件模式,对目标机器产生大量的负载。

有多容易,我们不妨试试看?

1.安装

1
2
3
git clone https://github.com/wg/wrk.git  
cd wrk
make

注意使用 ./wrk 命令启动。

2.基本使用

1
wrk -t12 -c400 -d30s http://127.0.0.1:8080/jartto

参数说明:
-cHTTP 连接数,每一个线程处理 N = 连接数/线程数
-d:持续时间,2s2m2h
-t:总的线程数
-s:脚本,可以是 Lua 脚本
-H:增加 HTTP header,例如:User-Agent: jartto
--latency:输出时间统计的细节
--timeout:超时时间

3.输出
上面我们使用 12 线程,保持打开 400Http 连接,执行 30s。脚本运行完毕会输出:

1
2
3
4
5
6
7
8
Running 30s test @ http://127.0.0.1:8080/jartto
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 635.91us 0.89ms 12.92ms 93.69%
Req/Sec 56.20k 8.07k 62.00k 86.54%
22464657 requests in 30.00s, 17.76GB read
Requests/sec: 748868.53
Transfer/sec: 606.33MB

输出说明:
Latency:响应时间
Req/Sec:每个线程每秒钟的完成的请求数
Avg:平均
Max:最大
Stdev:标准差
+/- Stdev: 正负一个标准差占比

标准差大说明样本离散程度高,系统性能波动大。

在压测过程中,一般线程数不宜过多,CPU 核数的 2-4 倍就可以了。 太多反而因为线程切换过多造成效率降低, 因为 wrk 不是使用每个连接一个线程的模型, 而是通过异步网络 I/O 提升并发量。

所以网络通信不会阻塞线程执行,这也是 wrk 可以用很少的线程模拟大量网路连接的原因。

七、高级定制

到这里,相信文章开头提出的问题,你已经可以很好的回答了。我们不妨继续升级,来一些高级定制。可能很多童鞋注意到了上面文档中提到的 -s 参数了,我们先看看官方文档:

1
2
An optional LuaJIT script can perform HTTP request generation, response processing, 
and custom reporting.

LuaJIT 脚本可以执行 HTTP 请求生成,响应处理和自定义报告。这里是 Lua 的一些案例。鉴于篇幅过长,本节我们先了解到这里,精彩部分我们就留到下一篇继续探讨吧!

文章最后,打个小广告吧。如果你想搭上在线教育的快车,快速成长,不妨加入我们。一起成长,一起学习,一起挑战更多有趣的事情,「跟谁学-高途课堂」欢迎你,请将简历私我~

聚焦 Web 性能指标 TTI

作者 Jartto
2020年3月29日 22:23

如果你经常做网站优化,可能会陷入一个性能指标的泥潭即「面向指标优化」。真正的用户体验从来不是指标决定,相反它应该最真实的反映用户行为。

所以本节我们就来研究 TTI(Time to Interactive),话题展开之前,我们先来了解一些背景知识。

一、RAIL 模型

RAIL 是一种以用户为中心的性能模型。每个网络应用均具有与其生命周期有关的四个不同方面,且这些方面以不同的方式影响着性能:
RAIL 性能模型

1.响应:输入延迟时间(从点按到绘制)小于 100 毫秒。
用户点按按钮(例如打开导航)。

2.动画:每个帧的工作(从 JS 到绘制)完成时间小于 16 毫秒。
用户滚动页面,拖动手指(例如,打开菜单)或看到动画。 拖动时,应用的响应与手指位置有关(例如,拉动刷新、滑动轮播)。 此指标仅适用于拖动的持续阶段,不适用于开始阶段。

3.空闲:主线程 JS 工作分成不大于 50 毫秒的块。
用户没有与页面交互,但主线程应足够用于处理下一个用户输入。

4.加载:页面可以在 1000 毫秒内就绪。
用户加载页面并看到关键路径内容。

如果要提升网站用户体验,RAIL 是个不错的评估模型。

二、解读 TTI(页面可交互时间)

TTI 指的是应用既在视觉上都已渲染出了,可以响应用户的输入了。要了解 TTI,我们需要知道它的计算规则,先来看下面这张图:
TTI

官方文档中找到了如下描述:
First Idle is the first early sign of time where the main thread has come at rest and the browser has completed a First Meaningful Paint.

Time to Interactive is after First Meaningful Paint. The browser’s main thread has been at rest for at least 5 seconds and there are no long tasks that will prevent immediate response to user input.

我们可以简单的理解一下:
1.First Idle 是主线程处于静止状态且浏览器已完成 First Meanfulful Paint 的第一个早期迹象;
2.TTIFMP 之后,浏览器主线程静止至少 5s,并且没有可以阻断用户交互响应的「长任务」。

如果你对 FMP 还不了解,不妨先看看这篇文章:网站性能指标 - FMP。除此之外,第二条中提到的「长任务」又是什么呢?

三、Long Task(长任务)

对于「长任务」,我们通过如下图示说明:
长任务

对于用户而言,任务耗时较长表现为滞后或卡顿,而这也是目前网页不良体验的主要根源。

如何测量 Long Task

1
2
3
4
5
6
7
8
9
// Jartto's Demo
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// TODO...
console.log(entry);
}
});

observer.observe({entryTypes: ['longtask']});

控制台输出结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"name": "self",
"entryType": "longtask",
"startTime": 315009.59500001045,
"duration": 99.9899999878835,
"attribution": [
{
"name": "unknown",
"entryType": "taskattribution",
"startTime": 0,
"duration": 0,
"containerType": "window",
"containerSrc": "",
"containerId": "",
"containerName": ""
}
]
}

Long Tasks API 可以将任何耗时超过 50 毫秒的任务标示为可能存在问题,并向应用开发者显示这些任务。 选择 50 毫秒的时间是为了让应用满足在 100 毫秒内响应用户输入的 RAIL 指导原则。

实际开发过程中,我们可以通过一个 hack 来检查页面中「长任务」的代码:

1
2
3
4
5
6
7
8
9
10
11
// detect long tasks hack
(function detectLongFrame() {
let lastFrameTime = Date.now();
requestAnimationFrame(function() {
let currentFrameTime = Date.now();
if (currentFrameTime - lastFrameTime > 50) {
// Report long frame here...
}
detectLongFrame(currentFrameTime);
});
}());

四、如何计算 TTI?

在计算之前,我们先来看一下 Timing API
Timing API

Google 官方文档中有一段描述:
Note: Lower Bounding FirstInteractive at DOMContentLoadedEndDOMContentLoadedEnd is the point where all the DOMContentLoaded listeners finish executing. It is very rare for critical event listeners of a webpage to be installed before this point. Some of the firstInteractive definitions we experimented with fired too early for a small number of sites, because the definitions only looked at long tasks and network activity (and not at, say, how many event listeners are installed), and sometimes when there are no long tasks in the first 5-10 seconds of loading we fire FirstInteractive at FMP, when the sites are often not ready yet to handle user inputs. We found that if we take max(DOMContentLoadedEnd, firstInteractive) as the final firstInteractive value, the values returned to reasonable region. Waiting for DOMContentLoadedEnd to declare FirstInteractive is sensible, so all the definitions introduced below lower bound firstInteractive at DOMContentLoadedEnd.

所以,我们可以通过 domContentLoadedEventEnd 来粗略的进行估算:

1
2
// 页面可交互时间 
TTI: domContentLoadedEventEnd - navigationStart,

domContentLoadedEventEnd:文档的 DOMContentLoaded 事件的结束时间。

The domContentLoadedEventEnd attribute MUST return a DOMHighResTimeStamp with a time value equal to the time immediately after the current document's DOMContentLoaded event completes.

如果你觉得上述计算过于复杂,可以通过 Google 实验室提供的 Polyfill 来获取。

五、TTI 指标监控

我们可以通过 Google TTI Polyfill来对 TTI 进行监测。
1.安装

1
npm install tti-polyfill

2.使用

1
2
3
4
import ttiPolyfill from './path/to/tti-polyfill.js';
ttiPolyfill.getFirstConsistentlyInteractive(opts).then((tti) => {
// Use `tti` value in some way.
});

很简单,就不细说了。推荐几篇 TTI 相关文章:
First Interactive and Consistently Interactive
User-centric performance metrics
Focusing on the Human-Centric Metrics

文章最后,打个小广告吧。如果你想搭上在线教育的快车,快速成长,不妨加入我们。一起成长,一起学习,一起挑战更多有趣的事情,「跟谁学-高途课堂」欢迎你,请将简历私我~

破局:技术视野与规划

作者 Jartto
2020年3月8日 18:32

有幸参加了 51CTO 的技术峰会,一天满满的干货,感觉收益颇多。于是将重点内容整理总结,分享给大家。

PPT
分享标题为《破局:技术视野与规划》,主要围绕峰会内容展开,中间夹杂一些个人见解与思考。

下文多图预警,建议小伙伴们 Wi-Fi 阅读。

一、目录

目录

我们将从以下四方面来展开说明:
1.2019 CTO 发展报告
2.技术团队模型
3.技术视野
4.技能发展与规划

二、2019 CTO 发展报告 - 2019 CTO Development Report

峰会开场就拿出了一份调查报告,主要围绕四方面:
1.宏观环境
2017-2019 年,下行经济环境市场缺口在收缩。向「公司管理驱动」和「科技创新驱动」转变。
宏观经济

从图中我们可以看出来,下行经济环境下市场缺口正在收缩。难道 CTO 要面临失业吗?不着急,我们接着往下看。

2.机遇与挑战
以「业务为中心」的延伸,向上是对商业战略的思考,向下是对技术管理、技术交付的落实。
机遇与挑战

3.胜任力
既懂得战略、又懂得组织管理、又懂得企业内部运营机制的技术负责人。
胜任力

我们可以看出:对 CTO 的胜任力要求,越来越趋向于一个既懂得战略、又懂得组织管理、又懂得企业内部运营机制的技术负责人。

所以,并不是需求变少,而是对高精尖人才的要求越来越高。

4.投资人视角
产业革命造就了帝国的崛起,前三次工业革命大家耳熟能详,那么第四次工业革命到底是什么?希望我们中有人可以来定义第四次工业革命~
投资人视角

下图列举了一些未来 10 年投资的一些方向,抓住机会,理财从现在开始。
投资领域

三、技术团队模型 - Technical team model

本节,我们将从技术团队模型来说:
技术团队

内容来自 4 位 CTO 的总结,我们集百家之长。

1.技术团队 ROI:领导的角度
领导的角度

不管问题如何回答,我们只有一个核心观点:对于公司来说,所有的事情都是赚钱相关的

2.技术团队 ROI:下属的角度
下属的角度

下属想法很淳朴,甚至很无辜。

3.技术团队 ROI
技术团队 ROI

4.BSC 模型
总结来说就是:以前瞻性和战略性为基础的平衡计分卡。
BSC 模型

我们简单补充一下:
平衡计分卡(The Balanced ScoreCard,简称 BSC),就是根据企业组织的战略要求而精心设计的指标体系。平衡计分卡是一种绩效管理的工具。

它将企业战略目标逐层分解转化为各种具体的相互平衡的绩效考核指标体系,并对这些指标的实现状况进行不同时段的考核,从而为企业战略目标的完成建立起可靠的执行基础。

BSC 模型

平衡计分卡中有一些条目是很难解释清楚或者是衡量出来的。财务指标当然不是问题,而非财务指标往往很难去建立起来。确定绩效的衡量指标往往比想象的更难。

我们来概括一下重点:

  • 全局战略思维(像 CEO 一样思考)
  • 持续提升技术驱动业务创新与增长,赋能企业可持续发展
  • 善用管理、效能与技术工具

5.大型科技团队的管理

大型科技团队中最重要的五部分:使命和定位,绩效管理,团队文化,技术决策,执行力。

这里收集了大型科技公司的组织架构,很有意思:
大型科技团队的管理

大概解释一下:

  • 亚马逊等级森严且有序;
  • 谷歌结构清晰,产品和部门之间却相互交错且混乱;
  • Facebook 架构分散,就像一张散开的网络;
  • 微软内部各自占山为王,军阀作风深入骨髓;
  • 苹果一个人说了算,而那个人路人皆知;
  • 庞大的甲骨文,臃肿的法务部显然要比工程部门更加重要;

这里推荐一本书,《信任五层波浪》:自我信任,关系信任,组织信任,市场信任,社会信任。

6.ToB 形态下的技术挑战
ToB

双活架构体系:
两个数据中心是对等的、不分主从、并可同时部署业务,可极大的提高资源的利用率和系统的工作效率、性能,双活是觉得备用数据中心只做备份太浪费了,所以让主备两个数据中心都同时承担用户的业务,此时,主备两个数据中心互为备份,并且进行实时备份。

一般来说,主数据中心的负载可能会多一些,比如分担 60~70% 的业务,备数据中心只分担 40%~30% 的业务。

四、技术视野 - Technical perspective

关于技术视野,峰会上提到了几个概念,下面我们来逐一解释。
技术视野

1.5G 时代
5G 时代,核心网采用微服务架构,也是和容器完美搭配——单体式架构 Monolithic 变成微服务架构Microservices,相当于一个全能型变成N个专能型。

每个专能型,分配给一个隔离的容器,赋予了最大程度的灵活。

5G

5G 的特点概括来说:高数据速率、减少延迟、节省能源、降低成本、提高系统容量和大规模设备连接。

2.工程效能
很多大厂都专门设立了这个部门,主要职责包括:需求治理、质量分析,量化管理,代码构建、代码搜索,开发测试、自动化、发布、舆情监控等。

工程效能

3.红蓝军对抗
类似于军事领域的红蓝军对抗,网络安全中,红蓝军对抗则是一方扮演黑客「蓝军」,一方扮演防御者「红军」。红蓝军对抗的目的就是用来评估企业安全性,有助于找出企业安全中最脆弱的环节,提升企业安全能力的建设。
红蓝军对抗

4.数字化转型
数字化转型

这里不得不说说什么是「数字领导力」,在我们正在经历的这场数字革命中,透明化、网络化、公开化和分享成为领导力文化的核心。

数字经济时代,数字化领导力是企业战略地使用数字资产达成商业目的的能力。对企业而言,清晰的数字化战略和强有力的数字化领导者将对该目标的实现起到关键作用。

五、技能发展与规划 - Skill development and planning

1.进化路径
进化路径

2.具备能力
数字化转型

3.提升途径
数字化转型

六、总结

好了,以上就是我分享的主要内容,感兴趣的童鞋欢迎深入交流。如果你需要 PPT ,可以去这里下载(提取码: i6ud)。

文章最后,打个小广告吧。如果你想搭上在线教育的快车,快速成长,不妨加入我们。一起成长,一起学习,一起挑战更多有趣的事情,「跟谁学-高途课堂」欢迎你,请将简历私我~

人工智能时代,Web 前端能做什么?

作者 Jartto
2020年1月1日 22:07

最近做了一个项目,通过爬虫去抓取页面快照,然后对页面兼容性进行全面测试。但是遇到一个问题,抓取到海量页面之后,难道还要人工去分析吗?

类似的场景并不会少,是否可以让机器去帮我们实现,最终输出一个可靠报告?答案是肯定的,快照生成后,我们可以对大量快照进行分析,结合 OpenCV 跨平台计算机视觉库,实现图像处理和计算机视觉方面的数据分析,最终输出结果。

我们总会找到一些合适的场景用机器来代替人,而 AI 正是这个支点。

AI 如果是这个时代的契机,那么作为 Web 前端,在这人工智能时代,我们能做什么?

一、什么是人工智能?

人工智能(Artificial Intelligence),英文缩写为 AI。它是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。

1.计算机科学
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。

2.智慧「容器」
人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大,可以设想,未来人工智能带来的科技产品,将会是人类智慧的「容器」。

3.信息加工
人工智能可以对人的意识、思维的信息过程的模拟。人工智能不是人的智能,但能像人那样思考、也可能超过人的智能。

4.研究目标
人工智能是包括十分广泛的科学,它由不同的领域组成,如机器学习,计算机视觉等等,总的说来,人工智能研究的一个主要目标是使机器能够胜任一些通常需要人类智能才能完成的复杂工作。

二、有哪些场景会涉及到 AI?

如果要列举一下有哪些场景会用到 AI,我想可能不仅仅是如下这些:
ai

机器视觉,指纹识别,人脸识别,人脸对比,手势检测,视网膜识别,虹膜识别,掌纹识别,专家系统,自动规划,智能搜索,定理证明,博弈,自动程序设计,智能控制,机器人学,语言和图像理解,遗传编程,物体检测,视频跟踪等。

人工智能就其本质而言,是对人的思维的信息过程的模拟。

对于人的思维模拟可以从两条道路进行,
1.结构模拟,仿照人脑的结构机制,制造出「类人脑」的机器;
2.是功能模拟,暂时撇开人脑的内部结构,而从其功能过程进行模拟。
现代电子计算机的产生便是对人脑思维功能的模拟,是对人脑思维的信息过程的模拟。

三、弱人工智能,强人工智能

弱人工智能如今不断地迅猛发展,尤其是 2008 年经济危机后,美日欧希望借机器人等实现再工业化,工业机器人以比以往任何时候更快的速度发展,更加带动了弱人工智能和相关领域产业的不断突破,很多必须用人来做的工作如今已经能用机器人实现。

强人工智能则暂时处于瓶颈,还需要科学家们和人类的努力。

人工智能是依赖机器学习的,数据和算法是机器学习的核心,而数据更为重要。按照解决问题的能力,我们可以把人工智能,分成两类:

  • 强人工智能:拥有自我意识,具备解决通用问题的能力
  • 弱人工智能:没有自我意识,具备解决特定问题的能力

目前,我们能看到的人工智能,几乎都是弱人工智能,在解决特定问题的能力上,超越了人类。

四、AI 如何影响前端

1.数据可视化,依赖 D3.jsEChartsWebGL
kael

2.模型可视化
用可视化的手段去解释模型,辅助算法同学调参。最简单的一个应用前端同学肯定非常熟悉,我们来看下图:
chrome-dev

是的,曲线函数和曲率我们很难记住,但是有相应的工具,会让一些数据和计算变得简单易懂

3.相关技术
提到人工智能,和前端密切相关的几个 JS 类库有:

  • tensorflow.js
    基于 tensorflow.js Nodetvnet 算法,可以提取视频中的稠密光流。
  • deeplearning.js
  • kera.js

高性能计算:

  • asm.js
  • WebAssembly
  • GPU
  • Opencv,前端做 CV 算法,物体跟踪、图像处理、特征检测等等

大家可能发现一个问题,一般的 tensorflow 模型动辄几百兆,在前端怎么跑呢?这就不得不提到 MobileNet,这是针对于移动端模型提出的神经网络架构,能极大地减少模型参数量,同理也能用到浏览器端上。

更多细节可以查看该文章:前端与人工智能,介绍非常到位。

五、如何做?

既然前端和人工智能有如此多的交集,那么我们该从何做起呢?不要着急,我们先来看一个完整的人工智能项目包含哪些内容。
aiweb

上图中,可以看到一个完整的人工智能项目是由:算法,数据,工程三部分构成。

工程部分我们可以理解为「大前端」,主要包含 5 部分:

  1. 人机交互
  2. 数据可视化
  3. 产品 Web
  4. 算法执行
  5. 模型训练

六、简单应用

pic
1.Tranck.js
就是纯浏览器的图像算法库,通过 JS 计算来执行算法逻辑

2.regl-cnn
浏览器端的数字识别类库,与 track.js 不同的是,它利用浏览器的 WebGL 才操作 GPU,实现了 CNN

cnn

3.ConvNetJS
浏览器端做深度学习算法训练的工具,官网地址

4.Amazon Rekognition
基于同样由 Amazon 计算机视觉科学家开发的成熟且高度可扩展的深度学习技术,每天能够分析数十亿张 Prime Photos 图像。

5.对比学习:Keras 搭建 CNNRNN 等常用神经网络

6.机器学习:MachineLearning

更多内容可以查看:
1.浏览器里运行的人工智能
2.前端在人工智能时代能做些什么

七、深度学习

深度学习,是英文 Deep Learning 的直译。它是实现机器学习的其中一种方式。机器学习还包含其它实现方案。

深度学习里,用到了人工神经网络,这是一个用计算机模拟大脑神经元运作模式的算法。同时,这个人工神经网络的隐藏层数量还必须足够多,才能构成深度神经网络。然后喂之以大量的训练数据,就是深度学习了。

换一个角度,如果隐藏层数量不多,而是每个隐藏层里包含的神经元数量很多,在形态上,它就是一个往宽度发展的神经网络结构。这时,可能就叫广度学习了。

目前,深度学习还是主流,它的训练效率,优于广度学习。

我们可以体验腾讯的一个深度学习案例:
pic

更多有趣应用:
1.TensorFlowJS 学习
2.如何利用 TensorFlow.js 部署简单的 AI 版「你画我猜」图像识别应用

八、明确几个概念

机器学习对我们来说确实陌生,所以一定要从明确一些常用的概念,这样才能提升学习的兴趣。我们来说一些可能会涉及到的内容(我也是正在摸索,目前就知道这些,逃~)

1.精确率
是针对我们预测结果而言的,它表示的是预测为正的样本中有多少是真正的正样本。

2.召回率
是针对我们原来的样本而言的,它表示的是样本中的正例有多少被预测正确了

3.监督学习
监督学习涉及到标注数据,计算机可以使用所提供的数据来识别新的样本。
监督学习的两种主要类型是分类和回归。在分类中,训练的机器将把一组数据分成特定的类。

4.无监督学习
在无监督学习中,数据是未标注的。由于现实中,大多数的数据都是未标注的,因此这些算法特别有用。
无监督学习分为聚类和降维。

5.强化学习
强化学习使用机器的历史和经验来做出决策。强化学习的经典应用是游戏。与监督和无监督学习相反,强化学习不注重提供「正确」的答案或输出。

九、机器学习算法有哪些?

提到机器学习,大家肯定都会自然联想到需要很强的算法功底。没错,确实如此,所以我们需要对算法有一些了解。

那么机器学习主要涉及到哪几类算法呢,我们来看看:

  • 模式识别
  • 计算机视觉
  • 数据挖掘
  • 统计学习
  • 语音识别
  • 自然语言处理

九、机器学习涉及学科

主要围绕在这几方面:线性代数、微积分、概率和统计。

线性代数概念Top 3:

  1. 矩阵运算
  2. 特征值/特征向量
  3. 向量空间和范数

微积分概念Top 3:

  1. 偏导数
  2. 向量值函数
  3. 方向梯度

统计概念Top 3:

  1. 贝叶斯定理
  2. 组合学
  3. 抽样方法

十、计算机视觉

OpenCV 是一个基于 BSD 许可(开源)发行的跨平台计算机视觉库,可以运行在 LinuxWindowsAndroidMac OS 操作系统上。

它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了 PythonRubyMATLAB 等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

应用领域:
1、人机互动
2、物体识别
3、图像分割
4、人脸识别
5、动作识别
6、运动跟踪
7、机器人
8、运动分析
9、机器视觉
10、结构分析
11、汽车安全驾驶

OpenCV 的应用领域非常广泛,包括图像拼接、图像降噪、产品质检、人机交互、人脸识别、动作识别、动作跟踪、无人驾驶等。

OpenCV 还提供了机器学习模块,你可以使用正态贝叶斯、K最近邻、支持向量机、决策树、随机森林、人工神经网络等机器学习算法。

这里推荐几个相关学习网站:
1.官网
2.OpenCV教程
3.图像对比

十一、总结

AI 涉及到很多的领域,并不是我们三言两语就能够说的明白。要真正的应用起来,还有很多的路要走。我相信,随着技术的发展,更多的场景将接入 AI,而 Web 则是其中的一个重要环节。加上 Web 跨平台特性,以及「算法-数据-工程」的驱动,未来在该领域一定会大放异彩。

很喜欢这句话:AI makes life better. FE makes AI better.

程序员如何减少开发中的 Bug?

作者 Jartto
2019年8月24日 11:35

周会上大家抛出了一个问题,程序员如何减少开发中的 Bug?很有意思的一个话题,本篇文章我们来进行探讨与总结。

一、概述

爱因斯坦曾经说过:「如果给我一个小时解答一道决定我生死的问题,我会花55分钟来弄清楚这道题到底是在问什么。一旦清楚了它在问什么,剩下的5分钟足够解答这个问题。」

虽然我们软件开发过程不会面临生死的抉择,但是却直接影响着用户的使用感受,决定着产品的走向。所以程序员如何减少开发中的 Bug,既反映了代码质量,也反映了个人综合能力

那么我们该如何有效的减少开发中的 Bug 呢?

我觉得应该从两方面说起:业务层和代码层。

二、业务层

软件开发过程我们就不细说了,直接来看最重要的几个节点:

1.需求讨论阶段
一定要明确需求,测试,开发,产品三方务必达成一致。前期如果存在没有明确的问题,那么后期就会造成无效返工和不必要的争执,这在日常开发尤为常见。

所以,软件开发前期,我们都会进行「评审,反讲,评估」三个阶段。

2.开发完成阶段
开发完成后,程序员首先要完成「自测」,也就是软件开发中的「冒烟测试」,确保主流程无误。否则,在开发工程师提交代码后,测试工程师步履维艰,无法有效开展测试,会造成极大的资源浪费。

更规范的流程需要测试工程师在需求明确之后写出「测试用例」,开发工程师在完成开发后,自行对照「测试用例」完成初步验证,之后就可以代码提测了。

这么做的好处就是既保证了「高质量的代码交付」,同时减少了测试工程师的工作量,我们何乐而不为呢?

3.提测
自测和提测有什么区别呢,从软件开发过程来看,其实开发工程师和测试工程师其实完成了不同阶段的测试:

开发工程师「白盒测试」:
是指实际运行被测程序,通过程序的源代码进行测试而不使用用户界面。这种类型的测试需要从代码句法发现内部代码在算法、溢出、路径和条件等方面的缺点或者错误,进而加以修正。

白盒测试需要从代码句法发现内部代码在算法,溢出,路径,条件等等中的缺点或者错误,进而加以修正。

测试工程师实际进行的是「黑盒测试」。那么什么是「黑盒测试」呢?
黑盒测试也称功能测试,它是通过测试来检测每个功能是否都能正常使用。在测试中,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,在程序接口进行测试

它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数据而产生正确的输出信息。黑盒测试着眼于程序外部结构,不考虑内部逻辑结构,主要针对软件界面和软件功能进行测试

黑盒测试是以用户的角度,从输入数据与输出数据的对应关系出发进行测试的。

很明显,如果外部特性本身设计有问题或规格说明的规定有误,用黑盒测试方法是发现不了的。黑盒测试法注重于测试软件的功能需求,主要试图发现下列几类错误。

  • 功能不正确或遗漏;
  • 界面错误;
  • 输入和输出错误;
  • 数据库访问错误;
  • 性能错误;
  • 初始化和终止错误等;

更多细节请查看文章:黑盒测试

三、代码层

代码层面,我们需要从以下几方面来说起:

1.Eslint 规避低级语法问题
这个显而易见,编写代码过程发现问题,避免因为简单语法,如:漏写了逗号,变量名写错,大小写问题等

2.边界处理
做好容错,必要的判空,还有就是代码边界问题。多想一想如果数组不存在,我们如何处理?如果数组越界,我们如何修复?如果数据缺失,我们如何使页面不崩溃?

3.单元测试
如果时间允许,我们可以做好单元测试,每次编译代码,或者提测前启动脚本,确定测试脚本都覆盖到了核心代码,尽可能减少代码出错率。

4.积累
为什么说要积累,其实道理很简单。随着开发经验的增长,你可能会碰到很多问题,那么如果细心积累,其实很多错误在不知不觉中就被处理了。反之,你会不断的掉入同一个坑里,在进坑与出坑中迷失自我。那么我们如何积累呢?

首先,碰到自己不会的问题,如果第一时间没有解决,通过查找或者请教别人解决了,那么一定要用小本本记下来,最好使用云笔记。好处不言自明。

其次,要积累自己的函数库,我们经常用到的一些方法,不妨自己做一个封装,不断沉淀。也许有一天,你会发现,自己不知不知觉中写出了一个 Lodash 函数库。

最后,你可以积累优秀的代码片段,嗯,「我们不生产代码,只是优秀代码的搬运工」。

5.学习
一句话,没有什么比学习优秀开源代码更有趣的事情了。阅读优秀源码,学习作者思想,站在巨人肩膀上,你才能走的更远!

做好上面这些,相信你一定会是一位出色的工程师。

四、总结

对于这类开放问题仁者见仁,智者见智,我相信每个人都会有自己的看法,也会有自己一套独特的方法。不管黑猫白猫,能抓住老鼠的就是好猫。对于程序员来说,能减少 Bug 的方法就是好方法。

程序员群体流传一句话:不写代码就有没有 Bug。

我们不能因为怕犯错误而减少写代码,更应该知难而上,越挫越勇。要知道日常开发中 「Bug 是不可避免的,只能减少」。

当然,这不应该成为我们写出 Bug 推脱的理由。不断超越,方是永恒。

Git 代码统计

作者 Jartto
2019年7月9日 15:09

当我们维护一个开源项目的时候,你肯定想知道哪些人比较活跃,哪些人贡献比较多。这时候就需要一个简单易用的工具,下面我来介绍几款。

一、场景

目前大部分的项目可能都会用到 Git 来做代码管理,那么我们在不断的修改项目的过程中,可能会关注如下几个问题:

1.每个参与者贡献代码量,按劳分配某些资源🙈;
2.参与者的代码增删量,提交次数等;
3.统计活跃度;

那么,如何来对代码量做统计呢?

二、常规操作

一般情况,我们可以直接通过 Git log 来统计,如:

1.统计个人代码量:

1
git log --author="jartto" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -

code

2.贡献值统计:

1
git log --pretty='%aN' | sort -u | wc -l

3.查看排名前 5 的贡献者:

1
git log --pretty='%aN' | sort | uniq -c | sort -k1 -n -r | head -n 5

更多 log 操作可以请移步:Git 代码统计

这时候,你可能在想:有没有省时省力的方式呢,顺便帮我生成报告。答案是肯定的,是时候请出我们的 git_stats 了。

三、使用 git_stats

1.首先,我们需要全局安装 git_stats

1
sudo gem install git_stats

2.接下来,运行

1
git_stats generate

3.打开 git_stats 目录

1
cd git_stats && open index.html

四、演示

1.概览
generate

2.Dashboard 可视化
activity

如果你对 git_stats 生成的一大堆文件不满意,我们还有一种方式可以「无侵入」,同时显得更加「高冷」。

五、补充:cloc

cloc 最优秀的地方就是「简洁粗暴」,我们来尝试一下。

1.尝试一下 cloc,首先,全局安装:

1
npm install -g cloc

2.简单用例

1
2
3
4
5
6
7
8
9
10
11
cloc [options] <file(s)/dir(s)/git hash(es)>
Count physical lines of source code and comments in the given files
(may be archives such as compressed tarballs or zip files) and/or
recursively below the given directories or git commit hashes.
Example: cloc src/ include/ main.c

cloc [options] --diff <set1> <set2>
Compute differences of physical lines of source code and comments
between any pairwise combination of directory names, archive
files or git commit hashes.
Example: cloc --diff Python-3.5.tar.xz python-3.6/

3.使用

1
Usage: cloc [options] <file(s)/dir(s)/git hash(es)> | <set 1> <set 2> | <report files>

进入项目,执行:

1
cloc .

稍等片刻,就会有一个输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
-----------------------------------------------------------------------------------
Language files blank comment code
-----------------------------------------------------------------------------------
JavaScript 10319 172724 254924 951843
HTML 679 120179 3665 224595
JSON 1714 256 0 182127
Markdown 1400 63461 2 171768
C++ 69 3538 3197 20331
Python 51 4292 7801 19137
C/C++ Header 117 3628 2033 18942
CSS 113 2011 823 16594
XML 32 4427 1300 11277
Sass 65 282 414 4255
Stylus 60 539 593 3215
YAML 189 324 413 3039
D 57 0 0 3003
EJS 113 43 8 2160
reStructuredText 18 681 51 2122
Bourne Shell 20 394 398 1875
SVG 5 0 1 1646
LESS 13 26 33 1343
make 42 378 245 1310
TypeScript 17 276 584 1161
Perl 1 87 170 582
DTD 1 179 177 514
m4 2 40 2 266
Lisp 3 42 38 264
Bourne Again Shell 8 43 24 161
C 4 40 37 149
Ruby 6 24 5 140
JSON5 2 0 0 123
CoffeeScript 3 18 28 99
Handlebars 4 18 0 96
Smarty 6 17 30 91
Windows Resource File 1 1 1 33
DOS Batch 5 2 0 16
IDL 1 1 0 11
zsh 1 4 13 7
-----------------------------------------------------------------------------------

4.更多的使用命令,可以查看帮助

1
cloc --help

六、总结

上文介绍了三种 Git 代码统计方式:

1.通过 Git log 统计,稍微会麻烦一些,需要有一些 awk 知识的储备;
2.使用插件 git_stats 来生成可视化报告,对用户友好。美中不足就是会在当前项目增加很多 html 统计可视化文件;
3.命令行工具 cloc,简单易用,无侵入,使用门槛低;

综上所述,我们可以按照自己的使用场景来灵活的选用不同方式。

七、参考文档

❌
❌