【置顶】个人阶段性学习和规划总结(技能树)

  本人专注后台服务端开发一晃已经好久了,自我感觉上不仅经验增加了很多,同时接触到的东西确实不少,在增加见识的同时博文也批量更新了很多。大多人看来内容很多很杂,此处做一阶段性整理和总结吧,给自己也梳理梳理一下。
  其实不仅仅是后台服务端开发这个方向,就整个软件开发来说,其知识构成也是有所层次的。个人毕竟不是正规计算机科班出身,也就是大家所说的半路出道、自学成才的野程序员,优点就是不会被那些所谓正规计算机教育的所束缚禁锢住,但是很多时候感觉自己的知识构成还是有所缺陷。既然励志要靠撸代码吃饭养家,那么长痛不如短痛,晚补不如早补,该学的终究跑不掉!

【置顶】博客资源收录大全

  虽然当下微信公众号席卷自媒体市场之势如火如荼,但是针对文章展示的话个人还是偏向于独立博客的形式,主要是因为个人可控制化的东西比较多。我想,在被条条框框束缚的无以喘息的情况下,这个时代没有什么比个性和自由更为重要的了吧。
  下面是一些网络知名人士的博客,以及平时在搜索资料过程中遇到的好站点,都被一一记录下来了,真心喜欢的话可以用RSS订阅这些站点,其中很多都是全文输出的。因为个人的兴趣取向问题,除了将不感兴趣的前端、移动端外,过于偏向于Java/Nodejs等语言化的博客也被KO了(即使编程思想是独立于语言而存在的),希望平时没事多看看吧!

【置顶】架构师成长之路

  上个月公司组织我和另外一个同事有幸参加了每年一度的全球架构师峰会,姑且算是架构师们的一场盛宴吧,不过确实感觉这个峰会挺水的,和自己当初的期望相差甚远。虽然近一百多个场次中零星夹杂着一些产品、质量方面的主题,但是绝大多数会场都是架构师在秀技术,当然这也折射出来:在国内,架构师常常被狭隘成技术能力强的那一拨人群。
  虽然不知道国外的架构师是否真如书本上说的那样,是一个偏向技术族的高端(几近全能)管理型人才,但是理想总需要有的,而且我觉得能做到那种标准的人肯定是企业稀缺的人才。这就整理收集了一些所谓架构师的职责和所需技能,就置顶当做自己努力的目标吧,希望能早日实现梦想!

1. 系统架构师是技术领导
  这意味着架构师除了需要有技术能力,同时还必须有领导能力。在项目中架构师具有做出技术方面决策的权力,相比而言项目经理则更加注重于在资源、排期、成本方面的规划和跟踪。
  架构师还需要参与到架构团队的组织管理,除了在较高层次设计系统架构外还,需要对各种工作和活动做出策划,因为架构实现最终会被落实分解成一个个的任务去执行。团队的质量对整个架构的成败有至关重要的影响,所以架构师还最好参与到团队员工的培养和新员工的面试选拔上去。
  架构师的领导力还体现在和团队成员的沟通交互上面,给员工的工作方向做出指引,给予他们充分明确的信息,并在需要的时候能够做出样例师范。成功的架构师都是以人为本的,每个架构师都会作为导师、教练的角色来带领团队的成员,成员的成长进步会推动项目的顺利进行,同时也让员工自身、整个团队、整个项目大大获益;同时架构师还需要发掘团队中各个成员的长处优势,鼓励大家相互分享相互学习。
  架构师在技术角度上要是整个项目推动的驱动力,架构师必须能够适时做出决策,并且保证这些决策能够被充分的讨论和论证,内容明确,最终落实实现下来。
  架构师需要和不同领域的人协同工作,需要对商务环境、需求的变更做出快速的响应,所以架构师的压力回是比较大的,需要寻求方式来释放消极情绪,努力使自身和团队成员积极向上的工作态度。

构建自己的CA

  最近的项目在做通过银联接入牛逼哄哄的人行“CNAPS2”系统,不过他们强制要求通信报文采用国家标准SM2进行硬件签名,所以公司折腾了两家硬件签名机设备来玩,这边就做了相关的机器评测,看看相关的指标是否虚标了。
  因为SM2实在是太非主流了,而且密码学相关的东西本来就复杂的要死,所以这边就先用RSA进行签名和验签测试。同时因为硬件签名机其证书所用的私钥是通过硬件产生并保存在机器当中(而且通常都导不出来),然后通过硬件产生证书请求文件来让CA核发证书的,所以这边为了折腾方便就自己建了一个CA,然后可以按照各种姿势核发证书了!

一、构建CA步骤

1.1 openssl相关配置

  对于几乎所有的Linux系统都会默认已经安装好了openssl工具了,而其相关配置文件和工作路径在系统的/etc/pki/目录下面。
  openssl默认情况下就可以使用,不过通过修改/etc/pki/tls/openssl.conf配置文件的一些配置信息,比如证书的有效期、默认国家地区等参数,以及对新证书请求的规则检查策略配置好,后面在签发新证书会比较方便,很多参数直接使用默认值变可以一路回车了。

1
2
3
4
5
6
7
8
default_days = 1095 # how long to certify for, 3 years
dir = /etc/pki/CA # Where everything is kept

countryName_default = CN
stateOrProvinceName_default = Guangdong
localityName_default = Shenzhen
0.organizationName_default = cpplus.cc Co.LTD
organizationalUnitName_default = R&D

  从上面的配置可知,/etc/pki/CA是整个CA的工作路径,然后我们切换到该目录下,执行如下操作:

1
2
[root@cpplus CA] touch index.txt serial
[root@cpplus CA] echo 0001 > serial

  上面的index.txt文件会罗列出后面新签发证书的序列号和DN信息,而serial是一个全局递增的索引记录文件,每签发一个证书该文件中的序列号就会执行递增操作。

人人都是管理者

  前几天公司高管做了一个针对基层管理者的培训,培训中讲到自己是如何放弃当时相对安稳的生活工作环境,来到公司后制定具有战略性、挑战性的年度目标,然后在实施过程中自己是如何面对和克服种种困难和不利,并最终超额三倍地完成预定计划的。当然这个计划如此漂亮地完成有一定外部环境因素的促成,因为支付行业属于国家强监管环境的行业,但是所罗列的项目启动之初从零开始所面对的各种困难和挑战是客观存在且比较常见的,所以相对于那些只会引经据典、套用IBM、GE这些跟我们遥不可及的案例来剖析佐证的刻板式灌输相比,这场培训的案例就发生在我们的身边,当然也更触动、更具说服力。
  在结尾向我们推荐了管理学教父德鲁克的《卓有成效的管理者》,这本被誉为管理学的“圣经”的读物,其实早就已经买了,只不过一直拖拉着没有看完,这两天晚上乘着哄娃睡觉的时间看完了。之前对管理总给人一种错觉,那就是管理学是尽量让组织和员工提高效率、增加产出的目的,就是公司用来更加剥削和压迫的工具,再或者这类书都是给领导准备的,对技术族基层员工没有太大的作用。但当系统地看完这本书之后就会发现管理不仅仅局限于狭义上的领导,被管理的对象也不局限于基层员工,在当今知识类工作越来越多,与传统体力、机械性的劳动性质不同,现在的知识工作内容都是差异性很强的,而且在组织中工作者之间的关联性更强更复杂,除了领导在宏观层面上要对人事、工作等内容进行管理之外,每一个知识工作者个体也需要有管理自己、管理身边同事、甚至是管理自己领导的意识和能力,只有这样工作的效率才会提高、个人的价值才会得到实现、同事之间的合作才会有效和愉快,整个组织才能向着好的、积极的方向发展。

一、有效的管理

  现代社会知识劳动形的职位越来越多,这种类型的工作者不像传统体力劳动行业一样容易被严密的督导,知识类型的工作没有办法使用数量、成本来衡量,只能通过结果、产出来衡量,所以很大程度上需要工作者本人对自我管理、自我监督和自我提高效率。德鲁克在书中将管理者的角色进行了扩充,管理者的特点是能够做出决策,并且承担做出贡献的责任,所以管理者不仅仅是领导干部,对于知识工作者、专业技术人员都可以被称为管理人员,而且由于知识类工作者职位的特殊性,这类人员在工作中的决策不仅仅影响到自身,还影响到整个集体的绩效和成果输出。

再说Go语言

  当前如火如荼的Raft最成功得意之作莫属基于Go语言实现的etcd了,以目前形式看来大有挑战ZooKeeper作为企业级通用分布式协调组件之势。从社区状态看来etcd的更新也十分活跃,而且不少公司的分布式组件也是基于etcd中实现的Raft的基础之上再开发,所以说应该算是久经磨练考验了吧。etcd项目在其README.md中还描述到其Raft实现除了微小的变更优化之外,基本是完全按照原作者的论文设计来实现的,所以除了logcabin之外,从etcd的实现开始接触企业级的Raft实现也是一个门路(主要是logcabin好久没更新了,折腾的人少让人感觉好孤单……)
  背这次算是真刀实枪、认真系统性地学习了一下Go语言,同之前蜻蜓点水不同,随着对这个语言了解的更加深入,结合同C++相对比还是有一些心得和想法的,下面就简单聊聊自己的感受吧。

a. 数据类型表面形式上宽松

  Go语言提供了短变量声明语法,形式上看就感觉跟Python这类脚本语言一样弱化了数据类型的概念,但同时它确实是个静态编译语言,会有严格的检查机制确保强类型安全性。大家可能会说这同C++的auto自动类型推导没啥区别嘛!其实我觉得也是这样的,简短变量句法也就是个语法糖而已。
  另一方面Go语言的多重赋值确实是一个很好用的特性,可以使函数同时返回多个值,也从语法上让Go有使用error代替exception成为了可能。在做C++开发的时候,我们经常需要使用一个int或bool返回类型表明函数调用是否成功,确保调用处理成功后再通过引用或者指针来获取有意义的数据,这种写法相当的蹩脚,即便后来在开发的时候使用boost::optional部分缓解上述问题,但还是限制在只能返回一个值的情况。相比之下Go语言这种多重赋值的功能,才是真正满足编程习惯的设计。至于程序出错是使用错误标识还是使用异常机制就可谓仁者见仁了,没有绝对的好与坏,不然的话也不会出现很多boost库同时提供跑出异常和返回错误码两种API了,也有可能我个人对异常了解的还不够深刻,在习惯上基本倾向于使用错误码返回,所以Go的错误标识机制还是挺喜欢用的,只不过Go对于某些比较严重的错误直接宕机的做法表示惊讶。
  默认行为下Go语言为各种类型的变量都提供了定义良好的初始化值,防止变量随机初始化给程序带来不确定的行为。当初C语言设计出来的时候,为了性能考虑某些情况下定义的变量是未初始化的,C++也延续了这个传统,不过当前的计算能力下这种省略初始化带来的性能增益可能微乎其微,所以个人对这些语言的新标准中迟迟不提供变量的默认初始化表示比较费解。对于这个问题,目前我写C++的习惯是将所有的变量定义都附加一个统一初始化语法{},以确保变量是良好初始化的。

一个简单的互联网架构样例图

  咋看标题感觉像是一个伪命题,因为在之前我就描述过:架构永远是服务于业务的,不同的业务类型、不同的业务体量、甚至不同的管理层价值观和公司文化都会对最终的架构产生重要影响。但是从另外一方面说,互联网行业是开放、发展迅速同时在技术上同质化较强的行业,所以相当多的公司可能最初都像传统行业一样对工程进行功能确定和架构的详细设计,而是以近似野蛮的方式快速开发和部署业务系统,待到业务量快速上升的时候再借鉴类似行业的解决方案去做演化更新和扩容,因此来说大部分互联网企业的架构还是有章法可循的,只是会根据具体的业务逻辑做一些变更,或者组件集群化,甚至对某些组件进行二次定制开发等,也就是随着业务规模的越庞大、运营的越精细,架构才会演化的越来越复杂。
  最近在看一本书《Designing Data-Intensive Applications》,因为目前只有英文原版所以啃起来还是有点慢。这本书是一个英国人写的,因此书的内容偏重于从理论、宏观概念上对现代Data-Intensive类服务开发面临的挑战进行描述,同时对现在各个企业、开源服务、学术论文等给出的解决方案进行介绍。虽然这本书可能不是那种看了就立马技能提升并在实践中操刀用起来的那种,不过有一定工作经验的人看的过程中能获得很大的共鸣感,可以说是对工作中一些遇到的问题进行了更高层次的一种总结归纳。之前有人说,计算机科班出身和野路子出身的程序员很大的区别就是:前者会从理论慢慢走向实践,而后者会从实践再慢慢回归理论。现在仔细想来,盖莫如此啊……
arch
  上面的这张图总结的是目前我所认识到的互联网系统的常用架构,就当是一个系统架构设计的起点吧,原设计我是使用Draw.io工具进行绘制的,源文件可以从这里下载。可能现在看起来还算十分简单,有些东西可能还不够完善,但希望随着自己知识和经验的积累,其内容也能更加的丰满精细。

本文完!

自己拼凑的一个分布式存储服务

  现代互联网的发展对服务质量的要求越来越高,后台开发中对基础组件和服务的可靠性要求也越来越严格,在这类需求下通过多副本的分布式协议提高服务整体可靠性也越来越被证实为行之有效的解决手段。虽然Lamport早在上个世纪就提出了Paxos算法,但一直被觉得因为难以理解,所以工业上基本也就几个技术实力雄厚的大厂将其实现并应用在生产环境中,不过随着Stanford的Diego Ongaro提出Raft一致性算法后,因为其在Paxos的基础上做出了很多的假设和约束,使得该协议更容易被理解和工程实现,因此近年来基于Raft实现的分布式系统突如百花齐放,使人感觉上高端无比的分布式系统也可以被我们这技术菜鸟们学习、研究甚至实现了。
  之前通读过不少分布式系统的设计和实现论文,其实可以发现处于稳定状态的分布式系统工作原理很简单明了,通常整个论文的绝大部分则是用于解释和证明系统运行过程中各种异常、突发情况下的正确性,以及可以部署在工业级生产环境下一个可靠性强、便于实现和维护的分布式系统的各种细节性问题。其实在仔细研读作者的博士论文之后,同时参照一些开源实现代码,觉得自己实现Raft协议还是没啥问题的,不过对于分布式系统除了实现算法,后续正确性验证还需要更多的工作量去完成。这里我就投了一个巧:使用Diego Ongaro的logcabin这个样例项目工程,剥离出其中Raft协议之后,再将自己的业务代码添加进入,就可以快速得到一个具备分布式能力的服务了,而且我想作者自己操刀实现的Raft协议库应当比绝大多数人的实现都更加完整可靠吧。
  logcabin是基于Raft协议实现的一套驻留于内存、树状层次结构的存储系统,类似于UNIX文件系统中的目录和文件层次结构,通过自带工具可以实现目录和文件的操作管理。为了将这个项目折腾的更加好玩,于是在原作者项目基础上做了一些更改操作,并命名为RaftStore,立志将其实现为一个可靠的静态资源存储服务。当然折腾不是最终目的,自己的初衷就是在折腾中加深对Raft协议以及分布式系统的理解,能够在折腾中有所习得吧。


再学设计模式

  这篇打算从Uncle Bob的大作中再学习整理一下设计模式,主要是感觉这本书相比起GoF的《设计模式》更容易入口一些,书中会使用简短精悍的例子告诉我们带有腐臭味的设计有什么样的毛病,然后通过之前的SOLID原则怎样演化改进这些问题设计。之前自己总是贪心着想把23种设计模式一下子学全,但是这种囫囵吞枣式地大满贯感觉收效甚微,毕竟设计模式具有极强的实践操作性,是需要不断地在学习中思考、在使用中感受的东西,所以与其贪多还不如找几个实用的模式研究透了更实在。任何时候我们都需要记住:我们需要的不是最初承诺的豪言壮语,而是在今后的行动中不忘初心,践行当初自己一点一滴的承诺。
  其实现在再仔细审视一下这些设计模式,也会发现一些有趣的现象:不少模式在项目中感觉也不会太多用到了,尤其现在微服务化浪潮下每个服务都设计的尽可能轻巧简洁,每一个服务的整体复杂度与上个世纪的巨无霸服务不可同日而语了;还有一些在实践上已经被用烂了,只是一直没有意识到它们的名字而已,比如FACADE、PROXY;此外设计模式提出来的时间也比较久了,而现代C++增加了许多新的特性,所以一些设计模式真的需要重新REVISE一下,比如最常见的OBSERVER有更完美的替代方案。

1. TEMPLATE METHOD

  根据DIP原则,我们希望通用的算法不要依赖于具体的实现,而TEMPLATE METHOD和STRATEGY都可以用来分离算法和具体上下文的耦合,使得通用算法和具体实现都依赖于抽象。不同的是TEMPLATE METHOD使用继承机制来解决该问题,而STRATEGY则是使用委托机制。
  在TEMPLATE METHOD中,可以将程序的通用结构分离出来,把他们放到一个抽象基类的普通实方法中,然后该实方法可以按应需调用抽象方法,所有的实现细节都由这些抽象方法在派生类来实现。通常上面的实方法是public的,而虚接口则是private的,成员方法的访问控制和虚特性是正交的,private virtual接口也可以在派生类中被override。

InnoDB存储引擎之数据库锁

  锁的目的就是为了支持对共享资源的并发访问,并提供数据的完整性和一致性,InnoDB具有两种标准的行级锁:共享锁(S Lock)和排他锁(X Lock)。
  不同的数据库,甚至MySQL不同的存储引擎,对锁的实现都是完全不同的。MyISAM是表级锁设计,在并发修改的时候性能较差;SQL Server的老版本使用页锁,新版本开始支持乐观并发和悲观并发,而且在乐观并发下开始支持行级锁了;InnoDB是通过在每个页中采用位图的形式进行锁管理的,所以InnoDB中锁是一种很轻量级的实现,即使同时锁住再多的记录其开销几乎也不会发生什么变化。

1. 一致性非锁定读

  一致性非锁定读是指InnoDB通过行多版本控制(MVCC)的方式来读取当前执行时间下数据库中的行数据,比如读取的行正进行DELETE或UPDATE操作,此时的读操作不会等待该行上X锁释放,而是会去读取行的某个快照数据,快照数据是通过undo段来完成的,undo数据是事务中用来回滚时候使用的,所以只要执行事务产生就肯定会产生undo数据,使用快照数据是没有额外开销的,同时快照是不会被事务修改的,所以访问这些数据也不用进行加锁操作。
  InnoDB对每一行记录可能会有多个版本的快照,因此称之为行多版本技术,这种技术下的并发控制成为多版本并发控制(MVCC)。在READ COMMITTED和REPEATABLE READ事务隔离级别下,InnoDB会使用一致性非锁定读,不过不同的是在READ COMMITTED事务隔离级别下,对快照数据一致性非锁定读总是读取被锁定数据的最新一份快照数据;而在REPEATABLE READ事务隔离级别下,对于快照数据非锁定一致性读总是读取事务开始时候行数据版本。