Hegel2011的博客

读书 - 工作 - 生活 - 笔记

微服务笔记

微服务是Martin Fowler定义的一个术语,出自 https://martinfowler.com/articles/microservices.html

是伴随着敏捷开发和云服务部署流行而兴起的一种架构。微服务架构风格[1]是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并且可通过全自动部署机制独立部署。这些服务共用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术。

具备的特征包括:

  • 水平扩展服务能力时,可以扩展只需要扩展的模块而不是全部
  • 组件多以服务的形式提供
  • 团队多按业务能力/功能组建
  • 团队始终围着产品,而不是做完了就丢给运维
  • smart endpoints and dumb pipes,其实就是管道扁平化,针对SOA中部分总线太过只能而言
  • 去中心化的管理,微服务意味着可以自治化,而不是谈标准化
  • 可以多个编程语言同时使用,只要保持彼此间通信简单(http+lightweight messaging)
  • 数据存储也是去中心化的,Polyglot Persistence,存储/数据库也是每个服务自己定
  • 基础设施自动化程度高,实现持续提交和持续集成
  • 开发者和用户间会更容易建立更多的联系,要持续关注软件如何帮助用户提升业务能力,而不是把软件看成是将要完成的一组功能
  • 针对失效的设计,使用服务作为组件的一个结果是,应用程序需要被设计成能够容忍服务失效,如断路器模式

Spring Cloud 服务治理

服务治理是近年来架构中的热点部分,尽管比照ICE这些内容其实十几年前就已经有了, 只是五六年前伴随着系统越做越庞大,才变得必要起来。

简单理解一下,其主要内容基本是:

  • 要有一个服务中心,服务中心最好是集群的
  • 要能向中心注册服务,服务的地址用名称而不是ip硬绑
  • 要能发现一个服务,其实就是用名称通过服务中心找到服务的ip和端口
  • 要一个可以轮流访问服务集群的客户端
  • 此外再配合上消息总线等内容

有了这些,基本一个服务治理的框架就基本形成了。

《Spring Cloud 微服务实战》是一本很不错的书,有动手的介绍,有源码的分析,写的也算精炼。

Eureka 服务治理中心

启动服务中心后,配置客户端主要包含两部分:

  • 服务注册相关信息: 包括服务中心地址、服务获取间隔时间、可用区域,以eureka.client为前缀
  • 服务实例相关的配置信息: 包括实例的名称、IP地址、端口号、健康检查路径等,以eureka.instance为前缀

Ribbon

Spring Cloud的负载均衡是在客户端实现的。 WeightedResponseTimeRule是个比较复杂的实现。

Hystrix

这是一个容错断路器,当出现超时等状况时直接调用指定的回掉函数。使用了RxJava库的异步操作模式, 实现了发送+观察的效果,所以可以中断请求。

Feign

在RestTemplate上进一步抽象,实现和Spring MVC对等的method封装。因为要组client,所以@RequestParam 中的value不能少。

1
2
3
4
5
6
7
8
@FeignClient("Hello-Service")
public interface HelloService {
  @RequestMapping(value="/hello1", method=RequestMethod.GET) //指明要访问的路径和方法
  User hello(@RequestParam("name") String name, @RequestHeader("age") Integer age); //指明构造请求是的参数名称
}

//调用方式
helloService.hello("DiDi", 30);

Zuul Api 网关

网关的事情就两条:
1. 路由 2. 过滤

Zuul的路由结合了治理服务,下面就把一个路径全部转发去了一个服务

1
2
zuul.routes.service-a.path=/aaa/**
zuul.routes.service-a.serviceId=Hello-Service

过滤器则可以通过继承一个抽象类ZuulFilter并实现4个方法来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AccessFilter extends ZuulFilter {
  ....
}

@EnableZuulProxy
@SpringCloudApplication
public class Application {
  public static void main(String[] args) {
    new SpringApplicationBuilder(Application.class).web(true).run(args);
  }

  @Bean
  public AccessFilter accessFilter() {
    return new AccessFilter();
  }
}

Spring Cloud Config

基于git(也可以是svn或本地目录)的配置中心,其实就是一个可以保存各种配置信息,然后由其他微服务读取后拉起应用。

Bus 和 Stream 消息总线和消息流

目前只支持RabbitMQ和kafka两种队列,kafka更多的好像和实时日志处理流相关

新的挑战

去新公司已经快半年了,大约一个半月前副总找谈话,打算提拔我当部门经理,负责起部门的管理工作。 并且,跟我讲了他的经历。他原本也一直不想做管理,主要顾忌有两点:
1. 怕自己干不好; 2. 怕自己荒废。直到老板请他出山帮忙,也就不得不开始从事管理工作。
副总这番话还是挺让我有共鸣的,因为对我而言,所顾忌的也是类似的情况。但既然副总和其他领导举荐我,那也不好推辞,只能赶鸭子上架尽量干了。

但一方面接了下来,另一方面却又很忐忑。因为这个部门从原先的项目组升级而来,而之前我作为架构师是配合项目组经理工作的,我当部门主管之后,和原先的经理之间存在一个换位的过程。而我们合作的四个月其实配合的还不错,尽管我感觉加班多了些,其他方面大家还都能顺畅沟通。
难点之二,本司的产品很强势,往往会有莫名其妙的需求和时间安排,而研发的地位则属于较低并且相当被动,这都不太像如今的技术性公司了,但确实是我司的现状。做架构师的时候,还可以不直接面对强势的产品和大姐头,而做部门主管则必须为兄弟姐妹们争取合理的工作安排。
难点之三,下属以农村娃娃居多,吃苦耐劳者多之,聪明干活的则很稀少,这样的团队带起来管理难度还好,但干活水平不容易高。
难点之四,真的对我能不能买账也只有天晓得,尤其是在产品如此强势的情况下,并不是每个下属都觉得应该跟着我干的。

但是,当大姐头明确地告诉我部门连我在内已经有18个人的时候,我还是挺震惊的,打那一刻起我突然对这个工作有了兴趣。

然而,毕竟没管过那么大的团队,所以要学习的地方还有很多。就我个人的特点而言,至少具备了分析问题和解决问题的基本能力, 所以满足当好一个管理者的基本条件,但必须承认在一些管理者的日常方面做的并不好。解法也只有看书、看别人的经验加自己的实践了。

看书

  1. 《轻流程:IT团队的积分式绩效管理》,蔡为东,开始学习的第一本,虽然基本的道理很对,但这套积分制度实施起来还是有点难。
  2. 《行之有效:IT技术团队管理之道》,蔡为东,此书较前一本稍早出版,相当管用,可以直接使用的办法很多,最典型的如明确了研发部门的管理讲到底就是管人和项目,团队的日常管理就是谈话、考勤、请假、报销,比较好的一本书。
  3. 《从技术走向管理—李元芳履职记》,王树文,小说形式的IT管理书籍,基本上就是把前面一本管理理论书籍用小说形式 举例了一遍。
  4. 《技术管理之巅》,一号店的经历,写的比较泛。
  5. 《软件开发本质论》,Ron Jeffries,王凌云,基于敏捷模式的软件开发论,很薄但观点很犀利,对于 尽早测试的原因讲解的很清楚,这本书对我而言最大的触动是下了要大量编写自动化测试案例的决心。只有快速地 验证软件是不是正确,才不至于把问题留到最后。

java新的兼容性挑战者Kotlin

520期间被刷屏的除了show 恩爱,就是Kotlin了。 原本只是在一个做安卓的小朋友发的pdf里看见了Kotlin,想想应该又是一个和scala groovy或者closure类似的东西— 可以跑在jvm上,能利用jdk的库,语言表达力又强于java。

Java尽管有点啰嗦,语言表达力确实一般,但企业级的支持很强,jvm的性能更是出色,所以在类库、ide、甚至大型开发框架方面是无与伦比的。在jvm上跑的语言很多,甚至想部分替代的如scala closure groovy等等都火过一阵子,但是java继续维持着自己的优势地位。

然而这次真正被刷屏的,是因为Google认了Kotlin为干儿子,甚至以后可能是亲儿子,将kotlin变成了 头等安卓开发语言。查了一下,此前获得此定位的仅有java,这就可能有很大的不同了。kotlin有了google的支持,而其他所谓挑战者可没这个干爹。并且,Kotlin的创建者又是目前最流行的java ide的公司贡献的,可以保证在开发工具上的体验和支持,这么看来它的优势就比scala等强多了。

希望还是能帮助java改进吧,当然这个有点难,即使java8好几年下来了,也不知道有没有普及率超过java程序员的50%

Thymeleaf感想

刚使用spring boot时得知thymeleaf取代了jsp的默认地位,我是有所抵触的,做法就是重新配置回了jsp。 然而随着java web开发前后端业已分离的现实,逐步明白view层是thymeleaf还是jsp已经不再重要。因为java已变成 服务成守候在服务器侧,而原先页面的工作已经完全交给了(不需要会java)的前端人员,且他们是完全可以胜任的。

实际上截至目前,最新版的thymeleaf已经到了3.0以上的版本,而spring boot最新版集成的还是2.x的thymeleaf的版本, 可以认为这块已经处于冷淡的状态。

不过,凡是总有例外。这次又碰见了需要产生静态页面的业务场景,其中有不少的业务逻辑,所以还是需要一个view层,考虑到 新团队的习惯,决定采用thymeleaf吧,这样以后维护可以交给前端来做。于是简易学习了一下leaf,感觉还是不错的。

leaf最大的特色就是前端人员可以直接打开leaf所在的html页面,并做到完全的无异物感。脚本、链接完全动态静态可以分开。 这样解决了jsp长期以来美工介入很困难的问题,同时做的又比freemaker等更加到位。内置标签支持的语言语法也很现代化和好用,一般有jsp经验的程序员, 花个半天看一下一百来页的手册并动手实践一下,就完全可上手了。至于jsp,是可以退出历史舞台了。

Truffle and Solidity

区块链应用的开发,主要指用Solidity编写合约(Contract),然后部署到区块链上去。 注意,此处的区块链特指以太坊,而比特币的区块链是没有Solidity这种东西的。

因为是把sol编写的合约部署到区块链上去,所以可以进一步分解为3个问题:

  1. 区块链的安装(testrpc ethereum)
  2. sol合约编写(Solidity)
  3. 对sol合约进行编译以及发布(truffle)

目前来看,整个以太坊很喜欢借用node即javascript来构建他们的环境,尽管区块链和sol本身其实和javascript关系不大。 关于ethereum可查相关的安装手册,这里主要记录一下Solidity和truffle。

Sol的编辑器可以用atom vscode等等,submiline也没问题。 这门语言其实还是比较原始的,合约间的调用甚至不能传递结构(struct),更可悲的是返回string也不行。基本上任何不定长的返回 在sol的ethvm(以太坊虚拟机)中都不太好调用。 功能上来讲,solidity可以理解成数据存放在一个类似levelDB的内存数据库,这是ethvm会做的事情。

1
2
  mapping(uint=>LibDisSecPledgeApply.DisSecPledgeApply)  disSecPledgeApplyMap;
  uint[] disSecPledgeApplyIds;

上述代码定义了一个用于存放对象数据的mapping,因为mapping无循环遍历的功能,所以又增加了一个ids的数组保留所有对象的编号。

整个合约的编写,其实对写惯后台程序的人来讲还是不难上手的(类似用java操作redis写业务逻辑),只是限制确实比较多。 但solidity可以支持的变化太少,所以写起来是复杂不到哪里去。相当于成熟的脚本或编译型语言,solidity麻烦的地方在于其调试, 可简单罗列的就有两点:

  1. 编译速度慢。十几个文件的情况下,用 truffle编译就要3分钟以上
  2. 发布调试困难。必须发布到某个链的环境才能测试,而这个就真的很不友好了,断点还不支持,日志也很麻烦。

truffle是现在以太坊主要推荐的编写solidity的编译、测试运行和部署工具,能处理较复杂的sol文件关联引用,就是耗时很长,且 程序版本很不稳定,变化发展都依然极快。truffle是基于node和npm的,所以要先装好node。

1
2
3
4
5
npm uninstall truffle
npm install -g truffle@2.1.2
truffle compile  //编译合约
truffle migrate --reset //部署合约
truffle exec xxxx.js //执行某个js文件

和区块链一样,solidity,truffle都是刚刚涌现的东西,所以问题很多,用起来也不一定顺手。但,这个行业就是这样的。

CA证书略记

CA是Certificate Authority的缩写,就是一个证书颁发机构的意思。 它的作用是给某些公钥证书进行背书,以让调用者相信所获得的公钥证书确实的某个组织给予的。

具体做法可抽象为:
1. 某个组织自己生成一个公钥/私钥对
2. 该组织向某CA申请证书,需要把自己的身份信息、公钥交给ca,同时用自己的私钥给以上信息签名形成一个CSR,格式可以说pkcs10等
3. CA生成证书,比如P7b格式的证书。

此后,该申请的组织就可以把获得的证书交给客户,客户会去CA处验证证书的有效性等。

在现实中,浏览器、手机等默认内建很多知名CA,可能有几百个,对于这些CA颁发的证书均认为是安全的。

上述只是颁发完毕,之后进入使用阶段。

公钥与私钥的理解:  (1)私钥用来进行解密和签名,是给自己用的。
 (2)公钥由本人公开,用于加密和验证签名,是给别人用的。
(3)当该用户发送文件时,用私钥签名,别人用他给的公钥验证签名,可以保证该信息是由他发送的。当该用户接受文件时,别人用他的公钥加密,他用私钥解密,可以保证该信息只能由他接收到。

数字签名的基本用法

由于私钥加密东西长度是有限制的,所以一般私钥只用于对内容散列后的签名。 比如SHA1withRSA,顾名思义就是SHA1散列后用rsa加密散列值。

公钥端收到后,可对散列值进行解密,解密后再和收到的数据进行散列操作后的结果进行比对,如果散列值一致,那么该签名就是有效的。

区块链功课

https://www.igvita.com/2014/05/05/minimum-viable-block-chain/

Google的工程师讲解的P2P去中心化现金交易的底层技术—区块链(Block Chain),然后发现区块链的一大基石 是公钥私钥的加密技术,所以作者拿出了经典的Alice Bob来作为举例。

中心化的支付技术

目前的支付系统流行的是triple-entry 记账方式。三联为Alice Bob 和Chuck(中心节点,比如银行)都记录着交易记录, 以保证交易的可靠性和非重复性。 这套系统运作的前提是大家都信任Chuck。

去中心化的难点

1. 一致性问题

去中心化后,系统变成了分布式的,而分布式在一致性方面先天弱于中心化的。处理Double-spending的问题是一个难点。 因为一个交易发生后,系统中的其他参与者往往并不知道已经发生,可能还认为Bob拥有大量的钱财。在一个小的系统里, 可以通过全部完成通知后才认可交易成功,而这对一个大规模系统基本不可行。CAP理论表明P2P系统很难支持强一致性,但是,区块链技术 的亮点在于实现了weak(er) consistency。

2. Sybil attacks (西比尔攻击)

该攻击的特色在于虚拟出许多虚假的交易者,让真实的交易者误以为消费已经坐实。解决办法是增加造假的成本,同时保持验证的 成本够低,通过经济杠杆来从结构上阻止有人愿意造假,因为得不偿失就是傻事了。

但这带来的一个问题就是单个交易成本会很高,如果交易的手续费高于交易本身,那么这套系统也是没法运行的。

Block的概念

Block就是一组交易的集合,不单如此每个Block还记录了前一个Block,从而构成了Block Chain区块链。 每个交易者都可以将有效的交易集合生成一个block,生成block需要耗费大量的计算资源。 而将验证成本集中成Block的好处就是降低了每笔交易的成本,或者说交易集合共同承担了手续成本。而对交易有效性的、一致性、Sybil attacks的 防范都基于Block来进行。

Block Chain的冲突

因为所有的参与者都可以生成Block,所以一笔交易可能会加入在多个Block里。此时就构成了冲突,出现了chain fork。Block Chain对此的解决方式很简单粗暴, 永远选择最长的那个chain fork作为“真实的”交易链,并丢弃之前的交易分支。

使用的技术都是现成的:

  • accounting
  • cryptography
  • networking
  • proof-of-work

然而集合起来就又构成了一个新的精巧的方案。

Zookeeper

用于协作的服务,提供目录树的结构。基本可以认为是Yahoo出品。

data registers - called znodes, file parlance - directory

数据全部保存在内存中。

优势: 1. 性能好,可在大规模的分布式系统里使用 2. 可靠性高,可防止单点故障 3. 严格的顺序性,可满足复杂的、高精的客户端同步实现要求

znode的读写有acl控制以及版本号

leader nodes负责接受写的请求,follower nodes负责被同步和读取

配置示例

1
2
3
4
5
6
7
8
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888

tickTime是一个即使单元,单位是毫秒,2000表示2秒。
dataDir是存放数据文件的物理位置。
initLimit表示n个tickTime,上面这个就是10秒的意思,表示连接上leader nodes需要的时间单元数量。
syncLimit表示山离皇帝能有多远过期
server.1中的1的服务器内部的myid,zoo1是服务器地址,第二个port即2888用于follewer连接leader, 第三更port 3888用于选举leader。

基本上,zookeeper可以理解成一个分布式系统里,用于进程间通信的中间件,所以剩下的就是客户端调用了。 项目本身提供了C和Java的binding,具体实现时每个客户端会分为IO线程和watch线程两个。而Netflix在此基础上, 构造了wrapper: curator,以方便开发。

首先,引入maven依赖:

1
2
3
4
5
<dependency>  
    <groupId>org.apache.curator</groupId>  
    <artifactId>curator-recipes</artifactId>  
    <version>3.2.1</version>  
</dependency>

然后,在代码中可如下调用:

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
package zookeepertest;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;

public class CuratorTest {

  public void set() {
      String zookeeperConnectionString="127.0.0.1:2181";
      RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
              CuratorFramework client = CuratorFrameworkFactory.newClient(zookeeperConnectionString, retryPolicy);


              client.start();

              try {
                  client.create().forPath("/my", "555".getBytes());

                  client.getData().forPath("/my");
                  Thread.sleep(1000);

                  client.setData().forPath("/my", "666".getBytes());

              } catch (Exception e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
  }

  public static void main(String[] args) {
      CuratorTest test = new CuratorTest();
      test.set();
  }
}

这种调用方式是比较原始的进程间通信,以此为基础,recipes已经实现了一系列通信的高级语意, 如lock、semaphore、确认leader等,可以直接使用。

Included file 'twitter_sharing.html' not found in _includes directory