I'll take a quiet life. A handshake of carbon monoxide.

0%

原创文章,转载请标明出处:Soul Orbit
本文链接地址:一致性模型一句话总结

最近在一次分布式系统的线上交流中,发现居然有那么多种不同的一致性模型,而且因为种类太多,大家理解上也有很多不同,看了一些资料,虽然很多讲的很好,但是过于复杂或者书面,难以理解,所以在这里尝试着为每一个模型做一句话总结,希望可以帮助大家理解。如果我的理解有误,也请大家指正~

1. 啥?啥一致性?

一致性虽然是我们非常常用的一个词,但是非常不幸的是,这个词有太多的含义,在使用的非常容易混淆。所以在讨论一致性之前,我们需要先来看一下一致性的定义:

首先是我们常说的Consistency。这个词经常在两个地方出现:分布式系统的CAP和数据库的ACID。虽然其中“C”都叫一致性(Consistency),但是其含义却截然不同:

  • ACID中的一致性:这里主要说的是一种数据上的约束,比如主键是否唯一,或者外键关系是否保持等等
  • CAP中的一致性:这里主要说的是不同节点之间数据的同步状态,是不是能让客户端请求处理看上去像访问一个单体系统(Monolith)一样。

然后是Coherence。这个词虽然也翻译成一致性,但是它和上面的一致性截然不同。Coherence指的是多实体或者多层级的数据之间是否一致,比如:缓存一致性(Cache Coherence,缓存中的内容是否和原始内容保持一致)。而Consistency指的是一个单实体本身是否一致,比如上面提到的同一个数据库里的外键关系或者同一个服务不同节点之间的同步状态。

Read more »

原创文章,转载请标明出处:Soul Orbit
本文链接地址:Go语言学习笔记:深入对象模型之结构体

好了,在简单探索完基础类型之后,我们就来看一下我们最关心的Struct吧!

1. 简单结构体

我们先从最简单的开始,先定义一个简单的结构体,里面错落的放一些大小不一的字段:

1
2
3
4
5
6
7
8
type A struct {
FA1 bool
FA2 int32
FA3 int16
FA4 int64
FA5 byte
FA6 byte
}

然后定义一个变量a,再用上篇文章中的DumpObject函数来看一下其内存布局:

1
2
3
4
5
6
7
8
Var         Type           Address             RootOffset LocalOffset Size
a objmodelexp.A 0x000000c00000e520 0 0 32
a.FA1 bool 0x000000c00000e520 0 0 1
a.FA2 int32 0x000000c00000e524 4 4 4
a.FA3 int16 0x000000c00000e528 8 8 2
a.FA4 int64 0x000000c00000e530 16 16 8
a.FA5 uint8 0x000000c00000e538 24 24 1
a.FA6 uint8 0x000000c0001121f9 25 25 1
Read more »

原创文章,转载请标明出处:Soul Orbit
本文链接地址:Go语言学习笔记:深入对象模型之内置类型

也许是从C++转过来的习惯,学习一门语言,我总是比较喜欢先弄明白它的对象模型,所以自己就做了一些简单的实验,看看Go的对象模型~

1. 前置准备

为了查看对象的内存布局,我们这里先写一个非常简单的小函数,利用反射递归地遍历对象的所有成员,然后输出其内存位置,从而了解其在内存中的真实状态。

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
func PrintObjectDumpTableHeader() {
fmt.Printf("%-12s%-15s%-20s%-10s %-11s %-4s\n", "Var", "Type", "Address", "RootOffset", "LocalOffset", "Size")
}

func DumpObject(name string, p reflect.Value) {
v := p.Elem()
dumpObject(name, v, v.UnsafeAddr(), v.UnsafeAddr())
}

func dumpObject(path string, v reflect.Value, rootBaseAddr uintptr, localBaseAddr uintptr) {
dumpObjectDetail(path, v, rootBaseAddr, localBaseAddr)

switch v.Kind() {
case reflect.Struct:
childLocalBaseAddr := v.UnsafeAddr()

for i := 0; i < v.NumField(); i++ {
fieldPath := fmt.Sprintf("%s.%s", path, v.Type().Field(i).Name)
dumpObject(fieldPath, v.Field(i), rootBaseAddr, childLocalBaseAddr)
}
}
}

func dumpObjectDetail(path string, v reflect.Value, rootBaseAddr uintptr, localBaseAddr uintptr) {
fmt.Printf("%-12s%-15s0x%016x %10v %11v %4v\n", path, v.Type().String(), v.UnsafeAddr(),
v.UnsafeAddr() - rootBaseAddr, v.UnsafeAddr() - localBaseAddr, v.Type().Size())
}

这样,我们就可以非常简单的调用这个函数来查看任何对象的内存布局了,如下:

1
2
3
4
PrintObjectDumpTableHeader()

var b bool
DumpObject("b", reflect.ValueOf(&b))
Read more »

原创文章,转载请标明出处:Soul Orbit
本文链接地址:Go语言学习笔记:学习资料汇总

最近难得放假,想好好学习一下Go,毕竟C++用的我欲仙欲死,而平时比较常用的.NetCore也不是编译语言(Compiled Language),经常遇到一些神奇的限制……

学一门新语言说容易也容易,毕竟语法也就那么一些,而且Go非常精简,只有仅仅25个保留字,但是说难也难,要真正理解一门语言真的需要花费不少的心思,特别我属于那种不了解到一定程度连用都不敢用的人(在工作中经常因为需要使用一些库,就把这些库的实现通读一遍……),于是查找了不少的学习资料。我觉得这些资料对于新手上路真的非常有用,所以把他们都记录在这,希望也会对其他对Go感兴趣的朋友有所帮助。

那就让我们开始吧!
Gopher

1. 基础入门

首先,我们先从最基础的开始:

  • 弄明白怎么使用是第一步,官方的示例讲解必不可少:A Tour of Go
  • 接下来,可以系统的看看Go语言的方方面面,Go语言圣经gopl当仁不让:gopl.io,而且还有中文版
  • 在了解了Go语言本身之后,我们还可以看看语言的一些最佳实践,官方的Effective Go绝对值得一读:https://golang.org/doc/effective_go.html

至此,基础入门肯定是没有问题了,但是如果你是从C/C++这种比较传统的编译语言转过来的,估计到这里会一头雾水 —— 语法我都懂了,但是为什么呢?比如,为什么Go的struct成员变量和函数不提供const修饰?为什么没有信号量?使用嵌入代替继承看着很好,但是多态用起来经常却经常踩坑?这些问题我们就需要更多的资料来帮忙了。

Read more »

原创文章,转载请标明出处:Soul Orbit
本文链接地址:后台服务扩展入门 —— 原则篇

服务扩展是几乎每个做后台服务的开发都遇到过的问题,当业务大到一定的水平,当前的服务快要承受不住业务压力的时候,我们就要进行扩展了。一聊起服务扩展,很多人的第一想法都是增加运行实例,但是服务扩展有很多种方法,增加实例只是里面最简单的一种,而有时增加实例并不能改善问题,反而会让情况变得更糟。最近我们项目也在做类似服务扩展的事情,所以想把我之前学的东西大概总结一下,希望也能对项目有所帮助。内容比较粗浅,希望大家不要介意~

在对服务扩展时,我发现有些原则如果扩展过程中可以遵守,对整个过程会很有帮助,所以在讨论具体的方法论之前,我们先来了解一下它们。

1. 业务驱动

首先,我们必须得了解一个事实——业务才是解决用户问题的核心,后台服务的目的是为业务提供支撑。因为如此,一个后台的架构好不好并不是看它看起来有多么的华丽,有没有用到最前沿的技术,有什么技术情节和情怀,而是看它是不是能真正好的服务于产品,服务于业务,所以无论是后台服务的设计还是扩展,都必须由业务驱动,而所有的架构和设计都必须是为了解决实际的问题。有技术追求是好事,但是千万不要为了技术而技术,为了架构而架构。

1.1. 奥卡姆剃刀和康威定律

在执行业务驱动的时候,有两个理论特别好用:奥卡姆剃刀和康威定律。

很多时候我们在设计服务的时候都会纠结,一些地方要不要设计的更灵活一些,但是如果真的那么设计了,实现起来可能会复杂很多,这里我们就可以运用奥卡姆剃刀了。奥卡姆剃刀告诉我们:“如无必要,勿增实体”。要是一个服务可有可无,那么我们就把他砍掉,千万不要为了架构而架构,并不是越大型的架构就越好,后面我们说折中的时候会更详细的讨论这一点。不过,也请不要忘记奥卡姆提出奥卡姆剃刀时的后半句话,过分精简也是不好的。所以请了解自己的业务,做出最适合自己业务的决定。

另外在设计服务的时候,还要注意康威定律的使用。康威定律告诉我们:软件架构是组织架构的一种反映。所以在做任何服务设计和扩展时,我们都应该把组织架构考虑进去,这样我们才能设计出真正“高内聚,低耦合”的服务,让组织之间的沟通成本降到最低。

Read more »

原创文章,转载请标明出处:Soul Orbit
本文链接地址:使用Azure Pipeline来编译和发布npm包

两年半没有更新过博客了,趁着最近难得的假期赶紧除除草,结果发现………………之前给hexo写的包有各种神奇的bug,于是更新博客变成了修bug…………然后对于我这种超级懒人,烦人的事情就来了————每次在本地执行npm的命令发布安装包真的好烦人,要是可以自动化就好了,于是就抱着试一试的心情看了一下Azure Pipeline,结果工作的相当好,而且还在一定额度之内免费(对我来说真的够用了)!所以在这里记录一下,也算是个安利了~

这里就拿我的hexo-asset-path举例子吧(https://github.com/r12f/hexo-asset-path)。

1. 在Azure DevOps上创建项目(Azure DevOps用户请跳过)

因为hexo-asset-path的代码在github上,所以在使用Azure Pipeline之前需要先在Azure DevOps上创建一个项目。没有账号的童鞋可以和我一样直接用GitHub的账号注册。

在登录之后的主界面上点击右上角的“New Project”按钮就可以创建新项目了。
01-new-project-button-on-azure-devops

Read more »

原创文章,转载请标明出处:Soul Orbit
本文链接地址:使用Azure Pipeline在每次编译时自动升级版本号

Azure Pipeline是一个非常强大而且部分免费的编译和发布工具,我们可以用它来连接GitHub或者Azure DevOps上的项目进行CI和CD的实践。我们经常需要的一个功能就是在CI Build中自动升级版本号,而在Azure Pipeline中,这个功能的实现却不是那么的直接,在尝试了多种方法之后,我终于找到了一种简单而且有效的方法,于是记录一下。

为了解决这个问题,我们需要用到Azure Pipeline的变量(Variable)和计数器(Counter)。

Read more »

原创文章,转载请标明出处:Soul Orbit
本文链接地址:《技术领导力:程序员如何才能带团队》知识总结

以前从未真正接触过技术团队的管理,所以趁着年末假期,先选了一本比较简单的书入个门。这本书写的比较浅显,但是非常适合第一次接触技术管理的人来读,能帮助新人迅速建立起一些概念,避免很多雷区,虽然有很多不足的地方,不过都还算可以接受,毕竟这种书主要就是看个思想,细节并不是那么的重要,比如结尾的例子结束的过于唐突,看完的时候还以为是我看的版本不全;比如很多技术介绍的部分过于泛泛,比如研发管理体系,另外有些技术也有点过于落后,作为2018年出版的书,源码管理还在讨论vss和cvs,这些难以让读者对其产生同感和共鸣;此外有些观念我也不是特别的认同,比如技术和架构的进化,我觉得理解成演化会更加合适,也能帮助理解技术并没有有高下之分,而主要在于使用的场景。不过总之,对于刚接触基础管理的人来说,这本书还是值得一读的。

和以前一样,读完之后也还是在这里稍稍把这本书的知识点总结一下,方便以后复习:

1. 技术管理工作

1.1. 技术管理

  • 需求方太多
    • 刚通过校招进入团队的小组成员
    • 团队内工作3~4年的小组成员
    • 团队内工作5~6年的小组长
    • 产品团队管理者
    • 直属领导
    • 部门最高领导
    • 兄弟部门领导
    • 文档评委
    • HR接口人
  • 所需技能
    • 深入理解一门或多门编程语言
    • 深入理解多种流行的框架
    • 系统架构能力强,拥有复杂系统的设计经验
    • 积极跟随开源社区
    • 沟通能力强、情商高
    • 有产品意识,不是技术迷
    • 会带人,服从领导,责任心强
    • 会写专利
Read more »

原创文章,转载请标明出处:Soul Orbit
本文链接地址:《微服务架构》知识总结

虽然之前做过后台开发,很喜欢微服务的概念,也用了部分微服务的思想,但是回头再看之前很多事情的做法,觉得路子还是相当野的,特别是在微软呆了几年之后,对于Engineering System的理解加深了不少。最近看到了这本书,感觉算是对于这种后台设计思路有了一个非常好的总结,所以写一个小博客把所有的知识点总结一下。

1. 什么是微服务

  • 定义:微服务是一些协同工作的小而自治的服务。通过将单一职责原则应用在独立的服务上,从而避免由于代码库过大而衍生出的各种问题。
  • 服务多小合适:一个微服务应该可以在两周内被完全重写。但是服务越小,微服务架构的优点和缺点也就越明显。使用的服务越小,独立性带来的好处就越多,但是管理也会越复杂。
  • 微服务的自治性:一个微服务是一个独立的实体;服务之间通过网络调用进行通信,避免紧耦合;服务可以彼此间独立进行修改和部署,而不影响其他服务。
  • 微服务的好处:
    • 技术异构性:微服务帮助你轻松地采用不同的技术。
    • 弹性:如果系统中一个组件不可用,不会导致级联故障,而影响其他组件。
    • 扩展:可以只对需要扩展的服务进行扩展,把那些不需要扩展的服务运行在更小的、性能稍差的硬件上。
    • 简化部署:可以更快地对特定部分的代码进行部署。出了问题,也只会影响一个服务,并且容易快速回滚。
    • 与组织结构相匹配:自治性,简化管理,提高团队工作热情。
    • 可组合性:在微服务架构中,系统会开放很多接缝供外部使用。人们可以通过不同的方式使用同一个接缝,从而当情况发生改变时,可以使用不同的方式构建应用。
    • 对可替代性的优化:可以在需要时轻易地重写服务,或者删除不再使用的服务。
  • 微服务不是银弹:了解你的系统,找到最适合自己业务的方式。
Read more »

原创文章,转载请标明出处:Soul Orbit
本文链接地址:ChakraCore学习笔记(四):使用JSRT API (二)

在了解了如何注入API之后,我们来看一下一些比较复杂的JSRT API的用法吧。

在这一篇里,我们会来尝试做如下几件事情:

  1. 支持Promise,并用它来创建异步API
  2. 创建多个执行上下文,并创建一个API用以获取其他执行上下文里面的JS对象

1. 异步调用

Javascript现在在后台都如此被广泛的应用,其最大的好处就在于方便实现异步调用,随着promise和async function的加入,现在在JS中实现异步也越来越方便,代码逻辑也越来越清晰,那么现在我们也来跟上时代,把我们的storage.get API改造成promise吧。

1.1. 修改storage.get的polyfill script

首先,我们把我们注入的API修改成promise的形式,内部实现我们依然可以使用回调函数,这样我们C++的实现部分就不需要做任何的修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class APIStorageGet : public API
{
public:
// ...
const wchar_t * GetPolyFillScript() const override
{
return
L"(() => {"
L" var executeAPI = apiUtils.executeAPI;"
L" try { storage = storage } catch(err) { storage = {}; };"
L" storage.get = function() { "
L" return new Promise(function(resolve) {"
L" var apiArguments = [ arguments[0], function (data) { resolve(data); } ];"
L" executeAPI('storage.get', apiArguments);"
L" });"
L" };"
L"})()";
}
// ...
};
Read more »