对一次发布失败的反思
近期所在的项目,在进行近 4 个月的紧张交付后,与客户一起安排并进行了一次发布上线。在上线过程中出现了一个较为严重的事故,好在没有对客户造成太大的损失,本文期望针对完整的事件进行复盘与反思,以加强自己对线上环境的敬畏。
近期所在的项目,在进行近 4 个月的紧张交付后,与客户一起安排并进行了一次发布上线。在上线过程中出现了一个较为严重的事故,好在没有对客户造成太大的损失,本文期望针对完整的事件进行复盘与反思,以加强自己对线上环境的敬畏。
本文是对 Pete Hodgson 的文章 Feature Toggles (aka Feature Flags) 的全文翻译,一切版权归原作者所有。
Feature Toggles(也经常被称为 Feature Flags)是一项强大的技术,它允许团队不改动代码就能改变系统的行为。Feature Toggles 分为了许多种使用类别,当实现和管理他们时,考虑这些类别是十分重要的。Toggle 会引入复杂性。我们可以通过更聪明的实现方法与合适的工具来管理 Toggle 配置,以此来使 Toggle 带来的复杂性可控,但是我们也应该限制系统中 Toggle 的总量。
“Feature Toggling” 是一组模式,它能帮助团队更快且更安全的将新功能交付给用户。在下文中,我们会以一个小故事开头,来展现一些 Feature Toggling 适用的典型场景。之后我们会深入细节,这包括有助于团队成功实施 Feature Toggle 的特定模式与实践。
Feature Toggles 也被称为 Feature Flags, Feature Bits, 或 Feature Flippers。他们都是同一类技术的同义词。 在下文中我会交替使用 feature toggles 和 feature flags。
Guava 的common.graph
库对图结构进行了建模,图,是一种包含实体及其之间关系的数据结构。这种结构的例子包括
web
页面与超链接、科学家和他们写的论文、机场以及机场之间的航路、以及个人与其家庭关系(谱系树)。图结构的目的在于能提供一种通用且可扩展的语言来描述上述这类数据。
以某种分隔符连接连接字符串序列通常不应该那么麻烦,当序列中包含 null
值的时候尤甚。流式风格的 Joiner
简化了这种操作。
1 | Joiner joiner = Joiner.on("; ").skipNulls(); |
上述代码将返回字符串:”Harry; Ron;
Hermione“。除了skipNulls
以外,还可以用useForNull(String)
来指定将
null 替换为给定的字符串。
你也可以直接对对象使用 Joiner
,这会自动调用对象的toString()
方法后进行拼接。
1 | Joiner.on(",").join(Arrays.asList(1, 5, 7)); // returns "1,5,7" |
注意:joiner 实例是不可变的。因此 joiner
的配置方法总会返回一个新的
Joiner
,并通过这种方式来获取所需语义的
joiner。这种特性让Joiner
能够线程安全,并可以将之定义为一个static final
的常量。
在我的文章 虚拟工厂:Java 线程池 中简单介绍了采用
”工厂“ 这样一个现实生活中的概念来抽象具体的线程操作,并定义了
Worker
TaskQueue
等概念。用这种方式拉近了计算机域和真实世界域之间的距离,让代码表现现实的意图。
不仅仅是线程池,从 Java 8
开始引入的Stream
也一样,它用代码构建了一套流水线体系,通过流水线环节的叠加来实现对流水线上元素的各种处理。
现实生活中,存在大大小小的工厂,他们提供特定的服务,根据用户的需求生产、加工出产品,交付给客户,并赚取服务费。
通常,我们只需要交给工厂一份图纸,工厂就会根据图纸来生产产品,而生产的过程我们是无需关心的,作为客户,我们只关心这间工厂什么时候把产品交付给我们。
类似的,在代码里我们也会存在以下场景:主流程代码将需要做的事情分成一件件任务,并交由对应的代码工厂去执行,这里的任务可以是代码逻辑的执行步骤,而最基本的代码工厂就是各种方法。合并起来,代码工厂执行任务,实际上就是调用方法执行业务逻辑。
不过有时我们期望代码工厂能够异步执行任务,这样主流程就不用一直等待它执行完成了:让互相之间不存在依赖的任务并行执行能大大缩短总体的执行时间。
Java 提供了线程机制允许我们将方法调用放在与主流程独立的线程中执行,不过直接使用线程代码写起来略为繁琐,线程本身也是较低层的概念,所以在 JDK 1.5 之后,提供了对异步任务执行的高层抽象:线程池,通过线程池我们可以更方便的执行异步任务,而不必关心线程的使用细节。
线程池以清晰的设计与简洁的代码优雅的封装了线程并实现了任务执行逻辑。阅读它的代码,就好像走进了一间虚拟的工厂,工人挥舞工具的画面似乎就在眼前。
在本站早期的文章Build your own blog site by using GithubPages + Hexo + Travis CI中描述了如何使用 Hexo 和 Travis 来在 Git Pages 服务上搭建自己的个人博客。
但使用了一段时间之后,发现 Git Pages 的方案存在一些问题: - 访问速度慢。不走 VPN 访问 Github 速度感人,Git Pages 也一样,各种资源、图片加载缓慢。 - 难以被 Baidu 收录。网友提供了各种办法来解决,但都挺麻烦。
所以当我了解到 Gitee 也提供了免费的静态网页服务后,决定试试看,但毕竟一边在 github 上更新,一边在 gitee 更新,既麻烦又容易出错,所以期望能够直接把 github 上的更新自动同步到 gitee 上。
经过一些实验后,我成功的实现了把 Git Pages 镜像到 Gitee Pages 的需求。
在前一篇有关 Redis 分布式锁的文章中,我们讨论了几点有关分布式锁的要求: 1. 操作原子性 2. 可重入性 3. 效率
为了满足上述条件,采用 本地锁 + Redis 锁
的方式解决了问题。不过在文章末尾提到,Redis
不保证强一致性,因此对一致性要求很高的场景会存在安全隐患。
本文将讨论使用满足 CP 要求的 ZooKeeper 来实现强一致性的分布式锁。
rust 的 module system,类似 java 的 package,可以用于将代码分别放置在适合他们的单元内。同时 rust 还允许用户控制 module 之间的可见性(public/private)。
在 module 内,rust 允许用户放置 function,struct,trait,struct implement 以及 child module。
rust 对 module 的要求是任何 module 都应处在一颗以 root module 为根的 module tree 中。期望访问某个 module 时,能够找到一条通路从root一路向下直到该 module。