InfluxDB环境搭建01

一、设计原则
InfluxDB是一个时间序列数据库,其性能优化方向为大规模、高效的时间序列数据的插入及查询操作。经权衡,部分场景下需要以牺牲功能为代价来提高性能,以下列出了部分设计理念:
1、数据按时间戳顺序存储,不允许重复数据存在。
2、数据删除是低频操作,批量数据删除除外;
3、数据更新是低频操作,实际场景很少发生;对某一数据的持续更新,不应该发生;绝大多数的数据都是新产生的数据,而且不会发生变化;
4、数据写入的时间戳接近当前时间,数据写入顺序与数据时间戳顺序一致;
5、数据规模至关重要,数据库性能优化,主要针对大规模的写入和读取操作,而不是更新和删除操作;
6、数据库可用性高于强一致性;
7、很多时间序列都是短暂,而不是永恒的产生数据;
8、不需要特别关注某个时刻的数据,从整体分析数据趋势才更重要;

二、基本概念
时间序列数据库,有一些特有的概念。其实只需要正确理解measurement、tag、series和存储文件之间的关系就可以比较容易的理解整个系统了。

概念 解释 对应于SQL
时间戳timestamp 在InfluxDB里的所有时间都是UTC的,时间戳timestamp就是一个UTC时刻下,某一序列series在该时刻的全部数据的唯一标识。知道了时间戳timestamp就可以获取序列series下指定时间的数据点point,这也意味着同一series下时间戳不允许重复。
同一个序列series中,两个相同时间戳数据的写入,会触发数据更新及数据合并;
类似于SQL中的自增主键,但是时间戳类型的
数据点point 一个序列series中,具有相同timestamp的的field数据集合。也就是说在同一个series中同一个timestamp的数据点point只会出现一次(可以视为在series中数据点以时间戳timestamp为主键存储)。
数据点可以保存一个measurement的field的一个或多个,也可以随时增加新的field。但对于已存储的数据,不允许修改数据类型。
类似于SQL中的一行记录
数据库database 一个包含schema、时序数据、数据保留策略、持续查询、用户、权限的逻辑集合。 类似于SQL中的数据库
模式schema schema包含database,retention policy,series,measurement,tag key,tag value以及field keys,其确定了在InfluxDB里面如何组织数据。 对应于SQL的数据库模式+表模式
度量measurement 用于描述数据如何保存的数据结构,包含了tag,field和时间序列数据。measurement是字符串。
一个度量measurement可以有不同的存续策略retention policy。
对用于SQL的表
序列series measurement中的逻辑的数据分组,也是实际的数据存储分组。由shared measurement,tag set和feild key组成,不包含field value。
换句话就是,在InfluxDB中,数据不是按measurement存的,而是按series存的。
类似于SQL中按某一列的值,进行分表操作
序列候选series cardinality 在InfluxDB实例中,由database、measurement、tag set、field key确定的不重复的组合数量。
举例说明一下:比如记录一个人员信息的measurement,只有两个tag(性别和是否已就业),其中性别为2个可选值(M、F),是否已就业为2个可选值(Y、N),那么这个measurement下会存在2×2共4个series cardinality。而实际存储时,数据也会按每个series进行处理。
类似于SQL中按某一列的值,可以分表的数量
field InfluxDB数据中记录metadata和数据的键值对。field数量必须大于0,不支持无索引。 对应于SQL的无索引列
field set 数据点上field key和field value的集合。 对应于SQL的无索引列名称和数值的集合
field key 组成field的键值对里面的键的部分。field key是字符串且保存在metadata中。 对应于SQL的无索引列的名称
field value 组成field的键值对里面的值的部分。field value才是真正的数据,可以是字符串,浮点数,整数,布尔型数据。
一个field value总是和一个timestamp相关联。
field value不会被索引,如果要对field value做过滤话,那就必须遍历所选时间范围里面的所有数据点,这种方式对比与tag效率会差很多。
对应于SQL的无索引列的值
tag InfluxDB数据中记录metadata的键值对。tags用于存储常用的metadata,在InfluxDB的数据中是可选的。tags会被索引,因此tag上的查询是很高效的。 对应于SQL的索引列
tag set 数据点上tag key和tag value的集合。 对应于SQL的无索引列名称和数值的集合
tag key 组成tag的键值对中的键部分,tag key是字符串,存在metadata中。 对应于SQL的无索引列名称
tag value 组成tag的键值对中的值部分,tag value是字符串,存在metadata中。 对应于SQL的无索引列数值
分片shard 在分布式部署的情况下,shard决定了数据要存几份以及存在哪里。shard中包含实际的编码和压缩数据,并由磁盘上的TSM文件表示。每个shard都属于唯一的一个shard group。一个shard group中可以有1到多个shard。每个shard包含一组特定的序列series。同一shard group中的同一series上的所有点将存储在磁盘上的相同shard(TSM文件)中。 和SQL不太一样,有些类似于kafka分布式存储partition的机制
分片存续期间shard duration shard duration决定了每个shard group跨越多少时间。具体间隔由retention policy中的SHARD DURATION决定。
例如,如果retention policy的SHARD DURATION设置为1w,则每个shard group将跨越一周,并包含时间戳在该周内的所有点。之前的数据将被删除。
和SQL不太一样,有些类似于kafka中日志保留时间log.retention.hours
分片组shard group shard group是shard的逻辑组合。shard group由时间和retention policy组织。
包含数据的retention policy至少包含一个关联的shard group。
一个shard group包含shard group覆盖的间隔的数据的所有shard。
每个shard group跨越的间隔是shard的持续时间。
这个和kafka分组就差别很大了
存续策略retention policy 描述了InfluxDB保存数据的长短(duration),数据存在集群里面的副本数(replication factor),以及shard group的时间范围(shard group duration)。
当新建database的时候,InfluxDB会自动创建一个叫做autogen的retention policy,其duration为永远,replication factor为1,shard group的duration设为的7天。
retention policy在每个database里面是唯一的,是series的重要组成部分。
TSM(Time Structured Merge tree) 一种InfluxDB的专用数据存储格式,比现有的B+或LSM树实现更大的压缩和更高的写入和读取吞吐量。 存储结果,类似于SQL中的B+树,或KV数据库中的LSM树。
每秒写入量values per second InfluxDB数据持久化速度的度量,等于将每秒写入的数据点数 乘以 每个数据点存储的值的数量。
例如,如果数据共有四个field,并且每秒处理10个batch,每个batch是5000个数据点。那么每秒10个batch x 每batch5000个数据点 x values per second是每数据点4个field =每秒200,000个值。
数据点缓存WAL(Write Ahead Log) 为了TSM数据文件访问频率,InfluxDB将最新的数据点缓存在WAL中,直到其总大小或时间达到系统阈值,会触发将数据以batch的方式写入到TSM文件中。
WAL中的数据点是可以被查询的。
而且WAL中的树节点已经完成了持久化,系统重启后仍然会被保留。InfluxDB进程启动时,会确保WAL中的所有点都写入到TSM中,然后才会接受新的数据写入,。
WAL与TSM的关系,和SQL日志以及B+树关系有些相似。
持续查询Continuous Query(CQ) Continuous Query(CQ)是在数据库内部,自动的周期性运行的一个InfluxQL的查询。
Continuous Query(CQ)需要在SELECT语句中使用一个函数,并且一定包括一个GROUP BY time()语句。
有些类似于SQL中的存储过程+JOB
桶bucket 在InfluxDB 2.0中,桶是一个有命名的,时间序列数据存储位置。
在InfluxDB 1.8+版本中, 一个database和一个retention policy的组合就代表了一个桶bucket。
2.0新增概念

三、数据存储对比
我们以官方文档中的foodships表为例子:
包含了3个带索引里的列park_id,planet,and time;和一个不带索引的列#_foodships。
在SQL里,foodships表看起来是这个样子的:

+---------+---------+---------------------+--------------+
| park_id | planet  | time                | #_foodships  |
+---------+---------+---------------------+--------------+
|       1 | Earth   | 1429185600000000000 |            0 |
|       1 | Earth   | 1429185601000000000 |            3 |
|       1 | Earth   | 1429185602000000000 |           15 |
|       1 | Earth   | 1429185603000000000 |           15 |
|       2 | Saturn  | 1429185600000000000 |            5 |
|       2 | Saturn  | 1429185601000000000 |            9 |
|       2 | Saturn  | 1429185602000000000 |           10 |
|       2 | Saturn  | 1429185603000000000 |           14 |
|       3 | Jupiter | 1429185600000000000 |           20 |
|       3 | Jupiter | 1429185601000000000 |           21 |
|       3 | Jupiter | 1429185602000000000 |           21 |
|       3 | Jupiter | 1429185603000000000 |           20 |
|       4 | Saturn  | 1429185600000000000 |            5 |
|       4 | Saturn  | 1429185601000000000 |            5 |
|       4 | Saturn  | 1429185602000000000 |            6 |
|       4 | Saturn  | 1429185603000000000 |            5 |
+---------+---------+---------------------+--------------+

但在InfluxDB中,要按索引列也就是tag划分series,每个series要按时间存储,看起来是这样的:

name: foodships
tags: park_id=1, planet=Earth
time			 #_foodships
----			 ------------
2015-04-16T12:00:00Z	 0
2015-04-16T12:00:01Z	 3
2015-04-16T12:00:02Z	 15
2015-04-16T12:00:03Z	 15

name: foodships
tags: park_id=2, planet=Saturn
time			 #_foodships
----			 ------------
2015-04-16T12:00:00Z	 5
2015-04-16T12:00:01Z	 9
2015-04-16T12:00:02Z	 10
2015-04-16T12:00:03Z	 14

name: foodships
tags: park_id=3, planet=Jupiter
time			 #_foodships
----			 ------------
2015-04-16T12:00:00Z	 20
2015-04-16T12:00:01Z	 21
2015-04-16T12:00:02Z	 21
2015-04-16T12:00:03Z	 20

name: foodships
tags: park_id=4, planet=Saturn
time			 #_foodships
----			 ------------
2015-04-16T12:00:00Z	 5
2015-04-16T12:00:01Z	 5
2015-04-16T12:00:02Z	 6
2015-04-16T12:00:03Z	 5

四、schema设计原则
1、建议将meta data做成tag
2、建议不要用数据关键字作为tag或field的名称
3、不建议使用过多的series
4、不建议tag和field采用相同名称
5、不建议用measurement的名称作为区分数据的依据
6、不建议在一个tag中塞入多个分类的信息

五、小结
基于以上原则和概念,我们对时间序列数据库有了一个初步的认识:
1、InfluxDB是一个无模式(schemaless)的数据库,你可以在任意时间添加measurement,tags和fields,但对于已存储的数据,是不允许修改数据类型的
2、对比与SQL数据库,InfluxDB其实更接近与KV数据库,而且InfluxDB对列扩展的支持是十分好的
3、和SQL不同,不支持跨measurement的JOIN
4、measurement和series的关系,是通过tag来划分的,这是和SQL十分不一样的地方
5、InfluxDB中数据分两大类tag和field,其中:tag是用来划分series用的,只能是数量可控的字符串,而且支持索引;field是真正用于数据存储的
6、由于优先考虑数据插入及数据查询的性能,而不是数据更新和数据删除,InfluxDB不能算一个完整的CRUD数据库,更像是一个CR-ud数据库:
更新某个数据点时,只需要在同一个时间戳下重复insert一次数据;
删除某个数据点时,是无法根据field的值进行删除操作的,遇到这种情况就需要先进行一次查询,然后通过时间戳进行删除;
不允许更新或重命名tag,遇到这种情况需要新建一个tag,迁移数据后,drop原tag的series;
不允许通过tag key删除tag,但可以直接drop整个series;
7、单条数据的更新和删除操作,尽量少做,效率比较低
8、时间戳及其重要,数据的组织是按时间戳进行的
9、支持数据分片、数据保存时间、数据保存份数的设置
10、十分适合按时间为维度进行采样、生产和更新的系统

容器相关

几个问题
1,不同发行版的docker容器,尤其是glibc这些底层库版本不一致的情况下,可以在同一个宿主下运行,是因为glibc这些库与系统内核提供的ABI一直都保持不变吗?万一内核升级,有ABI变动了,docker是如何处理的呢?
处理办法是镜像自己带着基础库,事实上大多数发行版docker镜像都带着glibc,alpine用的则是更轻量的musl。镜像封装的应用,就只需保证兼容自带的glibc/musl即可。

2,现在虚拟机,都支持将某个虚拟机的窗体,直接投射到宿主机上,让宿主机像操作本地应用来操作虚拟机的应用,这个算那一层的虚拟化呢?也是通过ABI模拟来实现的吗?
说的是vmware unity mode这类功能么?具体如何实现的我没有研究过,无责任猜测只是vmware tool这样的工具提供的屏幕映射。但可以肯定的是,并不影响虚拟化层次,即还是硬件抽象层虚拟化。

3,在windows的vmware或virtualbox运行macos的虚拟机超级慢,但运行ubuntu就还蛮快的,是因为mac到win的ABI很难模拟吗?
“超级缓慢”主要是GUI慢,这个与显示方式和驱动都有关。如果你在SSH到虚拟的ubuntu和macos上,跑个console下的跑分软件的话,得到的分数相差并不大。

Windows 系统中是否有文件、访问、资源的隔离手段?是否存在 Windows 版本的容器运行时呢?
Windows的容器还是太重了,镜像超级大,而且优先支持微软自己的技术栈。这么重,加之不成熟,现在对上服务器虚拟化的各类成熟方案,实在没啥优势可言。

WindowsServer从设计上来讲,模块化做的比linux要差一些,内核做的事情也太多,早期类库变化也过于剧烈,类库前后兼容性也不算好。加之之前主推的技术,生命周期都太短,自家技术代与技术代之间没有传承,闭源得不到社区支持,开源服务端软件,在linux上性能,往往吊打windows。

而且即使是windows的虚拟化软件,微软自家做的也不是最好的。vmware和virtualbox多香。

微软唯一让我感到惊艳了一次的,还是wsl,但总归功能差了些,性能差了些。我倒是觉得,把wsl做好,可以同时支持win和linux容器,windows可能更有机会一些。

再后面,就是微软家生态的事情咯。其实微软做的很多理念,都挺超前的,而且也开始与社区合作。但微软,啥都要自己造轮子,技术延续性差又不断要大家换轮子,又没有强援,做生态挺难的。

看下linux和java,一个轮子能用多少年。看一下苹果,也是闭源,也是自己造轮子,还要交保护费,但苹果也不要你三五年就把轮子换了啊,而且保护费不是白交啊。远了远了。。。

docker
我觉得docker和其他虚拟化技术比,仍是最成功的,从docker到containerd,是一种技术上的成功,但是商业上的失败。

k8s应当与swarm对比。k8s成功,源自于google需要这样的一套工具,用来管理自己的容器,开发来先自己用,积累了很多经验。swarm则没有这个过程。云厂商们,自然选择对自己更好用,更有利的工具咯。

google至此,已占有web流量制高点,浏览器制高点,移动操作系统制高点,云原生制高点。厉害

网络虚拟化
N年前,在大学用虚拟机的时候,就遇到了HostOnly,Bridge,NAT等联网模式,当时对Bridge和NAT的区别也是搞了挺久才弄清楚的。

系统对既有旧方案和旧功能的兼容
这种例子蛮多的,比如:
1、系统升级时,如果API版本升级到了2.0,1.0版本也要长期保留。
2、界面风格变化了,还能允许用户切换回之前的风格
3、做系统替换时,一些用户用惯了的工具、报表什么的,经常会被要求在新系统上增加对应功能
4、系统升级时,尽量去兼容原有数据库设计,而不是推翻重来
5、对于部分政企用户,被迫去兼容IE,全是泪啊

存储
存储小文件:用过本地存储、SSD、SAN、NAS、SFTP、Ceph【对象存储】,云存储【云盘、对象存储】
存储大文件:用过SAN、NAS、Ceph【块存储】、HDFS
存储XML用过existdb、Oracle XML DB
存储JSON用过mongodb、es
备份数据,用过磁带和蓝光盘
试过IPFS,但并没有实际投入使用

从底层介质来看:可以分为SSD、磁盘、磁盘阵列、磁带、光盘等
块存储,相当于划分了一块存储空间或一块逻辑盘,给了操作系统
文件存储,相当于操作系统在磁盘上创建了文件系统,可以作为本地磁盘使用,加上网络访问功能,可以封装成为NAS、SFTP等
HDFS,可以看作分布式的文件存储
对象存储,可以看作分布式的NAS
IPFS,可以看作把一个BT网络,封装成了一个NAS

在我们行业里,使用云存储最大的障碍是两个:
1、使用公有云,担心数据安全、用户隐私的问题;少量上云的数据,也因种种限制,只能用移动联通电信的云;
2、使用私有云,很多机构不愿花大价钱购买服务,又没有能力自己运维,最终很难推进;
但总的来讲,这几年,云存储的使用面还是越来越广的,需要有个渐进的过程。

网络透明
服务网格可以实现透明,很大程度上是服务网格的整个网络环境是相对可控的。
远程通讯,如果在网络可控的环境下,其实完全可以和服务网格采用同样的方式。
但在互联网环境下,无法实现网络的可控,运维工程师、网络工程师是无法把程序员的大部分工作都做掉的,也就是程序员不能只关心数据,不关心网络。

何时能实现这种透明呢?个人认为,需要网络设备更新换代才行,要华为、思科支持这种透明,并能将透明能力,一定程度上开放给开发应用的厂商,才有可能实现一定程度上的透明。

SDN
个人感觉,SDN与服务网格感觉从思想上很相似,实现途径却不一样。

SDN本身十分依赖于网络提供商,其实按我理解,需要一次网络设备更新换代才行,而且网络提供商也需要进行一次大升级,用户也要跟着改造,这一方面需要技术沉淀,另一方面需要很多资金投入,一方面需要等用户升级。SDN概念也比较早,在网络提供商向用户推销SDN概念时,多数网络用户第一反映很可能是一脸懵逼。很多用户根本听不明白,有啥用,现在感觉挺好的啊。

而服务网格,是在可控网络下进行的,不需要网络设备的更替,也不需要以来网络供应商,更不存在跨越网络供应商的问题。大厂支持,再加上K8S和Istio的加持,所以生态就起来了,有滋有味的。服务网格用户是技术人员,服务网格出来推广的时候,微服务已大行其道了。技术人员们被服务治理烦的不要不要的,一听有方法直接把自己解放出来,学习应用热情高涨。加上并不需要夸张的资金投入,方案也就更容易落地了。

故障恢复

故障恢复
之前做个一个折中的处理方案,类似于快速接收,批处理,反馈处理状态。之所以这样处理,是因为合作机构IT水平参差不齐,而且配合程度不高,如果把数据接收+处理+反馈放到一起的话,一旦有错误,就要麻烦对方重新推送最新数据,或者自己脚本重新处理数据,而且一天峰值十分明显,峰值时根本来不及处理数据。
1、数据接收阶段,采用了快速失败策略。一旦数据落库文件落盘,就返回成功,反之失败。
2、数据处理阶段,会进行重试,三次后进入失败队列
3、进入失败队列后,会通知运维和开发,去看下数据什么问题。有时会把文件手工处理一下,再重试。如果实在无法处理,就线下通知合作方相关人员如何修改数据。
4、数据处理成功后或彻底失败后,发送处理结果给合作方。

这种方式,在对合作方约束很小、合作方缺乏技术支持、项目前期阶段、以快速开展业务为优先考量时,可以尝试一下。后面自己做起来后,就可以要求对方,做一些统一要求了。

限流和降级
之前在一个大量读写小文件服务的入口处,用过令牌桶限制访问量,防止IO过高。问题是每秒要发放发放多少令牌,最后是慢慢试出来的。

后面微服务时代就是中规中矩的限流,降级和熔断了。但降级和熔断,是通过HTTP状态码进行判断的,有些后知后觉了。

零信任网络
一个团队去完成一个任务,如果彼此信任,相互配合就会很流畅,沟通成本会很低,任务推进也会很顺畅。比如几个知根知底的伙伴去创业,一个眼神可能就懂了。
一群互不信任的人去完成一个任务,哪怕每个人都很努力,但经常感觉别人掣肘,吵来吵去,任务止步不前。一个流动率高,甩锅成风的组织,便是如此。

代码也是如此,如果我们假设代码是可信的,直接拉取镜像就行了。
如果假设代码是不可信的,开发提交代码后,要各种引擎扫描,扫描通过后,流水线打包镜像。同时还要提交各类材料如测试报告,越权测试报告,渗透测试报告,压力测试报告,代码审核报告等等相互佐证代码没有问题,然后发布。
这样先不说要多少资源支持,单说发布,就从十几秒变成了十几分钟,甚至几十分钟。

服务也是如此,如果假设服务是可信的,不要加任何控制,就可以相互访问。
如果假设服务不可信,就要各种验证,网络端口是否允许访问,token是否正确,双向证书过了没,是否有服务访问权限,是否有数据权限,是否符合流量控制要求等等。
先不说做需要多少资源支持,单说服务性能,从几十毫秒一下到了几百毫秒。

那做这些值吗?值!
但要符合自己的情况,不能太过,绑了自己的手脚!

零信任网络安全
我认为边界安全模型和零信任模型会长期共存,边界安全模型毕竟更成熟,而且在资源隔离程度上,远高于零信任模型。istio们并没有提供边界模型的一些组件,比如杀毒,比如入侵检测,比如蜜罐,比如上帝视角的规则控制等。而且istio们本身也有被入侵的可能,所以不能只依赖这一个层面的安全管控,而是立体的安全管控。

可观测性
单体程序时代,类似于一个办公大楼,有了问题,告诉管理员门牌号和具体事情就行了,管理员就可以乘电梯过来解决问题。
只要在日志里输出一下,哪个方法,做了哪个任务或出了什么问题,用日志工具就可以统计到处理速度或快速定位到问题了。

微服务时代,类似于管理城市物流。要提出问题,我们必须说明,那条街,哪个门牌号,几单元,有什么需求。工作人员上门时,要看下地图,什么路线过去最快,遇到堵车怎么办,小区不让进怎么办,然后才能到顾客这边提供服务。数据链路就像城市地图,监控就像地图上的流量,而日志必须还原到这张地图上,才知道哪个交叉口或哪个大楼哪里出了问题。
所以,我们要花必要的精力,去做全链路,绘制这个地图。所以我们要收集度量信息,去监控哪里流量红了,哪里彻底堵车了。只凭日志,是无法快速定位问题的,这个交叉口堵车,问题可能出在三公里之外,一个交叉口一个交叉口查过去,太慢了。

流量大了,堵车是必然的。只有做好可观测性,才能快速疏导交通,做到事半功倍。

日志
个人觉得,如何正确的记录日志,用何规则做日志分级,要记录哪些东西,比用什么技术栈分析日志重要的多。老师能否分享一下,日志规范如何在团队中落地呢?

有两种情况,多记录一些日志有好处的。一类是部署于第三方的系统,宕机时要多记录日志,最好有dump文件,利于排查问题。第二类是跨公司做集成对接,输入输出一般都会记得很清楚,为了防止扯皮。

聚合度量
主要监控了服务请求,JVM,服务器的一些指标。但服务请求方面,做的还很基础,有较大提升空间。

分布式相关

共识机制
Basic Paxos在全部节点可信任的时候,主要还是效率问题。所以zk、etcd都要用改进的算法。
Basic Paxos在部分节点不可信任的时候,是不适用的。所以公共区块链项目需要用其他的共识机制。

公共区块链中,常用的共识方法有PoW、PoS、DPoS等,这些方法,一方面是要达成共识进行记账,另一方面是要防止网络被恶意攻击;
联盟链中,一般采用PBFT、PoET等方法,由于不需要面向整个互联网,所以共识机制效率比公共链高不少;同理RAFT、ZAB,默认所有节点是可信任的,效率也是比较高的。
其实大家在日常生活中,默认会通过中心化的方式来达成共识,比如转账成功与否,大家一般会通过银行或支付宝的记录来判断,而不是线下协商。而这种方式,反而是交易效率最高的。
还是那句话,根据业务场景,选择足够用的架构和算法就好了。适合团队,能高效低成本解决问题的方案,就是最好的方案,哪怕这个技术方十分十分的朴素。

为何有了 DNS,还会出现 Eureka、Consul 这些专有的服务发现框架?
感觉其实要解决的问题并不一样:
1、基于DNS,其实要解决的问题是流量的流向,可以做到流量监控,但无法管理到具体业务,功能简单,效率更高;正好符合K8S的需要;
2、服务发现框架,其实是深入到业务层面,在应用框架集成、业务监听支持、健康检查、服务保护等功能。而且基于业务需求,进一步提供配置管理、环境管理等、多数据中心管理、业务紧密结合的功能;
有点像前面说的四层负载和七层负载的意思。
一个功能简单,效率高花头少;一个功能复杂,效率低可发挥空间更大;

那么除了 BFF 之外,你还用网关来做什么?
在API网关之前,会把移动APP的后端服务单独独立出来,APP访问APP后端服务,APP后端服务访问Web后端服务,相当于做了一个完全定制化的API网关。
当时也尝试过直接用Nginx来完成,但当时也不知道OpenResty这类扩展,复杂些的功能没能实现,没能实际应用。
后面从Zuul开始就不造轮子了。

客户端的负载均衡
客户端的负载均衡,在传统的CS解决方案中也有涉及,比如:
1、直连数据库时,统计类SQL直连只读库就好了
2、而且有些其实也变相做了优化,比如大家都熟悉的游戏开新服,登陆时就把流量分了

客户端负载均衡方案,其实和nginx的均衡策略基本一致的。但还遇到过一种中间情况,就是多了一个调度器,客户端定期获取服务IP列表,也可以从调度器获知每个IP的繁忙程度,然后决定要访问那个IP。

此外,云厂商对于移动、联通、电信的网络,有时也会用不同的链路,并会交一定的“保护费”啦。

负载均衡的设计,最佳人选,应该是懂业务的架构师(默认架构懂开发、懂运维)。
但同时,开发、运维团队要参与及评审:
1、比如开发要与架构沟通,团队熟悉哪些技术栈,哪些服务有状态哪些服务无状态等,中间件如何取舍
2、比如运维要与架构沟通,跨机房数据同步要如何做,容灾备份要如何处理,动态扩展是靠脚本还是靠云平台机制等

认证的各类方式

补充一下认证方式,一般是由三大类方式及其组合实现:

What you are:
比如人的生理特征(指纹、面部识别、虹膜、声纹、DNA等)

What you know:
古代机关开启方式、密码、动态指令、预设安全问题、最近和谁聊天、最近几次变动的密码、最近几次登录地址等

What you have:
身份证,医保卡,银行U盾牌,手机短信/电话语音发送验证码

但有一些就不太会好判断归属:
1、公安局开的身份证明或CA颁发给机构的证书,应该是“你有啥”,但很多时候直接被用于“你是谁”
2、图形动态验证码,用于判断“你是人不是机器”,这个算是“你是谁”的简单版本?

令牌内容
令牌不需要带太多的信息,但要满足一些基本要求:
1、令牌颁发机构标识
2、令牌被授予机构、APP、服务或网站标识
3、令牌类型(资源访问令牌、刷新令牌等)
4、令牌可访问的资源类型(头像、昵称、二维码等)
5、令牌有效时间范围
6、令牌颁布机构签名和时间戳
7、数据组织方式其实用Json 或 编码过的字符串都可以
这样,三方就都可以快速验证令牌有效性。

数据权限
数据权限确实很多时候只能系统自己处理,很难跨行业通用,甚至同一行业不同机构也不尽相同。比如两个看似比较通用的场景:
1、当机构架构分为多级时,上级机构能看到下级哪些数据,平级之间能看到那些数据,下级机构能看到什么数据,各行业各类组织互不相同。如果只用功能权限的思路去解决这个问题,容易将功能权限弄得十分复杂。
2、此外就是用户情况比较复杂,比如除了组织架构、岗位、职级外,还有职业证书相关权限控制、客户业务办理关系、项目组组成、项目组轮班,加上审核、稽核、多级质控等功能,仅是功能权限也是力有不逮。
而且,近些年来,各公司对数据权限和数据安全的要求都越来越高、越来越严格了。

凭证
感觉中文的“凭证”指的内容,比Credentials范围广很多。比如:
有时候,网页提示“请输入登录凭证”,说的就是用户名密码
有时候,请下载云主机“临时凭证”,说的就是登录证书
有时候,请出示入场凭证,说的就是一张狗牌

尤其是证书是否算凭证,感觉有些想不清楚。比如:下面的算凭证吗?
1、域控认证,Windows凭证管理器
2、Linux服务器可以通过ssh证书直接访问
3、一些云厂商可以申请临时ssh证书,允许远程访问
4、IOS程序发布时,需要开发者申请APP证书,并签名才能上传发表
5、接入云SDK时,需要申请AppId 和 SecretKey
6、TCP通讯时,采用TLS双证书双向加密

客户端敏感数据加密
对于客户端敏感数据加密的问题:
1、客户端对敏感信息加密,在通用浏览器、开放网络环境下,其实意义不大。如果一位黑客有能力干掉HTTPS通讯加密或者伪装为服务网站的话,替换掉网站前端代码也不是一件难的事情,这样无论如何加密信息都没有任何用途。同时,在客户端、服务的,这些敏感信息其实都有原文的,如果贡献了这两个地方,黑客可以同时获取明文和密文,所以加密也没啥用。
2、对于安全要求特别高,采用特殊通信协议,特殊信道,特殊设备、特殊浏览器的情况下,对于特别敏感的信息,进行二次加密是有必要的。因为设备和软件都难以得到,即使信道被监听,通信加密被破解,也要尽量拖延敏感信息被破解。

字证书有什么具体应用
1、机构、网站、身份认证
2、APP开发者认证
3、可执行程序开发者认证
4、控件开发者认证
5、API认证
6、文档的电子签章证书
7、大家自己搭建开发环境时有时需要自签名证书
其实还有很多咯。

除了顶级CA之外,其实CA也分等级的,这就涉及到了证书链。
此外,CA还要维护黑名单,吊销一些还在有效期之内的证书。

数据验证
之前只是零零散散有了一些想法,也落地了。但看完今天老师的讲解,感觉落地的很难看。

数据校验这部分,回顾了一下,我们真的做了很多,但十分十分的零散。根据各种要求,包括架构、运维、数据安全、数据合规要求、数据脱敏、敏感数据加密,每年都要折腾个几轮。此类代码横跨了文章中提到的全部层,实现方式从单纯的编码规范,到各层编码,到切面,到流水线扫描,到Jar包,到中间件、到持久化层验证,都有零散涉及。如果能尽量统一到 Bean Validation处理,就不至于每次加个要求,都要一通大改了。

缓存的弊端

1、增加了整个系统的复杂度,增加了系统的故障点,系统的整体可靠性可能会下降。比如Redis遇到bigkey,处理不好会让系统性能明显下降;如果Redis所在服务器CPU或内存资源不足,也会引起严重的性能问题
2、增加缓存后,缓存的预加载、过期失效、击穿、穿透、雪崩等问题,需要付出额外代价去解决
3、增加缓存后,缓存与数据库数据的一致性是个难题,需要付出额外代价去解决
4、分布式环境下,各缓存之间的数据同步及一致性,也是个难题,需要付出额外代价去解决
5、分布式环境下,缓存的高可用及冷启动后快速恢复,需要付出额外代价去解决

各类HTTP性能优化方式

网络性能优化

资源预下载,资源异步加载,资源压缩,dns加速,静态资源内容分发,多机房服务器就近访问,购买多条网络链路,防火墙过滤非法请求,F5负载,反向代理,API网关,多实例部署,缓存加速,一致性Hash分流,DB分库,异步任务队列等等。

其实还有P2P加速,网盘文件特征码上传加速,多网卡带宽绑定等特殊手段。

HTTP3
HTTP3的广泛推广,需要电信运营商的大力支持,同时还需要华为、思科等网络设备厂商的大力支持。以往各大电信运营商对UPD限制较多,各种网络设备对TCP的优化也更多。如果HTTP3广泛使用起来,对设备厂商也是个设备升级换代的好机会。

负载均衡
负载均衡和去医院看医生有些相似的:
1、刚到医院,要去分诊挂号,护士和挂号台的人不会问你一堆信息,只询问最基本信息并确定要看哪个科,就可以了。(四层负载,所需信息简单,工作效率高,重在吞吐量,不要有阻塞)
2、到了科室,尤其是看很繁忙的科室,会有护士和年轻医生,各种询问患者的情况,甚至把一些基础检查都做了,才会让专家去进一步提供服务;(七层负载,所需信息复杂一些,效率低一些,但好在量小了,也就避免了阻塞)
3、然后是资深医生看诊(实际网络服务)

但如果反过来,分诊挂号的时候,就咨询一大堆的问题,并作一些检查,每个患者耗时都长,会造成拥堵,患者排队n小时,而且到了科室就没有二次分诊的必要了。所以,七层代理放到前面,吞吐量就差了,四层代理也就没有存在的必要了。

负载均衡

各种事务实现方式

本地事务
Logging是无奈之举,因为操作系统和硬件的有效性不是100%,所以需要处理系统挂掉的情况。在系统挂掉后重启,数据库要知道需要Redo哪些操作,Rollback哪些操作,一定要有一个地方提前记录下来才行;相当于日志做了提前记录,数据库再做操作,根据日志的事务节点,就知道发生异常时数据要如何处理了。

Shadow Paging处理并发时,应该很难实现MVCC这种花式操作吧,多个客户端多个事务难以并发处理。

全局事务和共享事务
之前尝试过分布式事务,但实现效果实在太差,一个DB的事务卡住了,有可能卡住其他DB上的事务,性能直线下降。后面将强一致的场景进行了识别,尽量改造将其移动到一个库,其他直接通过异步等待方式解决,性能提高了不少。不需要强一致的,直接kafka同步搞了。

可靠消息队列
XA使用少,主要是其实现复杂,吞吐量低,会导致其他业务的阻塞,对于高并发访问,得不偿失。
可靠性队列,要轮询,会导致访问量增加,服务器负担上升,而且设计不良容易雪崩。同时,数据存在一段时间的不一致状态,但在可接受的情况下,性能远远优于XA。其实很多业务在重新调整事务顺序后,短期不一致状态的危害会很小。

本地事务

服务调用发展趋势

几类方法对比
CORBA看起来比较烦,用好了比较难,写起来比较烦,但好在起步早啊,而且贵在不断缓慢进步;
DCOM一心要兼容COM,有些反人类,看起来就烦,用好了很难,写起来很烦;
Java RMI、JAVA EJB,都是犯了相同的错,标准太烦了,对开发人员太不友好了。

WebService是看起来容易,用好了很难,写起来很烦;但同时代其他协议都是看起来就很难,所以胜出了,在一段时间内大行其道;

后来REST出现了,看起来容易,学起来容易,用起来也很容易。轻松将WebService挑落马下。

再看现在的Dubbo、Thrift、gRPC等,使用都相对简单,容易上手,开发者友好。
WCF有些小奇葩,很多想法很好,就是重了些,管得有些多,配置有些烦,如果要更多的占领市场,就应该让其变得更容易使用才对,而且应该跨平台才行。反而倒是WebAPI感觉更有前途,至少使用复杂程度和Flask、SpringBoot在一个水平线。

说到底吧,RPC协议和框架,其最终用户就是开发。
一开始能解决用户需求就行,没有其他替代方案,能解决问题,开发前辈们就很开心。
但用着用着,开发感觉体验太差了,就会有新一代产品出来,替代掉之前的产品。
而且越是新的协议,就不能有大的学习成本,容易上手,功能强大。
不信的话,你看下新的手机,比30年前功能多了不知道多少,但哪里还要一本厚厚的说明书才能上手呢?

REST的成功
REST的成功很大程度上源于HTTP及JSON使用的广泛性,其资源的思维确实很巧妙。

但其实不少REST落地成了HTTP协议收发JSON,直接把“HTTP方法”变成了JSON中的一个KV,进行了扩展;而且进一步封装了HTTP的返回值,将HTTP400/500,封装成了JSON,从而可以反馈更多的信息。换句话说,REST的一些问题,可以通过适当的灵活来解决。但唯独“传输效率”这个问题无法突破HTTP+JSON的极限。

个人认为,微服务之间内部通讯使用RPC提升传输效率,Web及外部通讯使用REST或HTTP+JSON可能是一个比较好的折中性选择。

其他通讯手段
很多啊,天天用。通过操作系统机制(共享内存、发送消息通知、粘贴板、各类内核对象等)、数据库(关系型、非关系型、列数据库),通过中间件(队列,Kafka,ESB),通过缓存,通过文件存储(NAS、NFS、对象存储)、通过UDP/RAW协议、通过网络广播、通过短信、通过邮件、通过自动拨电话、通过平台消息推送。

当然还有很多其他的方式,通过电信号编码,光信号编码、通过声波编码、通过量子通讯、甚至通过存储运输等等等等。

各类系统架构演化

一、整体趋势
天下大势,分久必合合久必分。复杂有复杂的代价,简单有简单的代价。

看这些年的发展,也能看出一定的端倪:
单体应用【一统天下】-》业务复杂后,应用拆分【应用拆分】-》SOA、ESB【接口拆分聚合】-》微服务【服务拆分】-》中台【业务聚合】-》去中台【业务不要瞎聚合,再拆回去】

微服务的简单,其实是将服务功能单一化,确实降低了编码及编码维护难度,也是有很高的代价的。我们不仅要享受简单,也要知道其代价。最直观的几个代价有:
1、需要很高的代价去打造适合自己的微服务治理体系
2、由于需要解决单点问题,每个服务要部署多个实例即使用量达不到也要备着
3、运维复杂度上升,需要工具支持,对人员要求也更高;
4、微服务的调用链,比单体应用的调用链,复杂,效率低,排错难;
使用微服务,对运维能力是有一定要求的,而且非所有软件都应该走微服务的路子。盲目的微服务化,服务拆分过细的结果,往往是又合了回来。

究其原因,人对复杂事务的掌握是很有局限性的,所以我们倾向于将复杂问题分解为简单问题,将问题标准化,然后解决问题。整个人类社会都是这样,才会有社会专业分工。但分工又不能太细,这样才能恰到好处的发挥人的创造力。最终都是多种因素折中的结果。

无论是软件开发,还是CPU制造,还是工厂制造商品,还是粮食的生产,原理是相似的。

二、单体程序还是微服务
个人认为,以后的发展趋势是单体系统、微服务架构,会相互学习相互补足。

很多典型的单体系统如操作系统、数据库、中间件如MQ等,在内部设计时也会根据功能进行拆分模块,并不会全部放到一起实现,会尽力降低某一部分出错后导致的后果;同时在分布式环境下,也会给出自己不错的答案。

而微服务正相反,其本身确实是降低了开放的难度,提升了开放效率,隔离做的很好。但同时要看到,微服务将不少工作扔给了运维,没有强力的运维,微服务拆的越细,最后死的也是越难看。所以在微服务化的过程中,很多项目都是拆细了又合并回来,接受了单体组建的风险,避免了运维工作的指数型增长。

单体程序的问题在于,单体应用如果太复杂了,人是很难考虑到各个环节的,需要用更复杂的手段,来进行保证,如火箭、飞机、航母,这些复杂的软硬件一体的开放工作,需要额外的系统及理论及代价去确保系统的可靠性。而且单体系统最长见的一个问题就是,单体系统的稳定性,小于单体系统中最差部分的稳定性,在很多没有良好管控的软件项目上,单体系统的稳定性,其实就是最差的那段代码决定的。人员水平不足,项目经验不足,人力不足,时间不足,是不是和你的项目很像?这种情况下,复杂的单体系统难以高效稳定的发展。

微服务,通过各种拆分隔离解决的这个问题,但同时在运维的维度引入了新的复杂度。每个项目都应该在单体服务稳定性与运维复杂度、资源耗费之间,取得一个平衡。孰优孰劣,应该按项目来确定,而不是一棍子打死。

此外,单片机给人的感觉是单体吧,但加个设备网关,搞个IoT不香么?

同样,各种复杂的操作,云平台给你封装好了,应用只需要找平台要这要那,对于应用来说,平台把内部实现封成了黑盒子,一定意义上说不是单体么?

三、SOA为何衰败

SOA的想做的事情,方向是对的,到今天,很多思想都在落地。

但那种“干这种改变世界的事情,老子要发明一套让所有人看起来都高大上的技术才行”的想法,让SOA过于复杂。

反而不如务实,用尽了少的代价让想法落地。

不应该为了解决简单的问题,一开始就弄一巨复杂的规范,SOA如此,EJB也是如此。

重点没有去解决问题,而是为了规范而去制定规范。甚至为了制定规范,还要发明一堆名词,发明一种语言。

比如说,SOA什么都要管理,就需要发明WSDL来框定业务。WSDL根本就不是人类容易看懂的,而且十分严格。如果通讯双方namespace有个字母大小写不一致,通讯就失败,报错根本看不懂。查几个小时,发现就一个字母大小写问题。问题是你只想发个字符串过去啊。

成功的规范,往往是先落地用起来,然后一点一点长大的;先出一套巨复杂的规范,然后回去套业务,得到的不是惊喜,往往是惊吓。

四、微服务和DevOPS
一个微服务团队,从头到尾完全管理好自己的服务,其实是很难的一件事情。实际中,不少团队,微服务的技术用了不少,但DevOPS其实都没算做起来,仍然十分的依赖运维团队来完成很多工作,自建的微服务平台也不够好用,有了问题人仰马翻的。

感觉这个阶段,不如直接花钱买云厂商的服务,规避部分技术风险,重点发展业务,会更好一些。等有些技术积累了,再做适合自己的技术解决方案。

五、今天的云原生还有哪些主要矛盾,下一次软件架构的进化将会主要解决什么问题?

个人认为,当前的架构,还远远没有达到最优状态。真正最优的时候,绝大多数开发人员,是不需要知道K8S、ISTIO、Spring、数据库、缓存及各类中间件的存在的。

之前的状态是,硬件按硬件的思路发展,系统及虚拟化按其思路发展,应用架构也是按自己的思路发展。之所以当前需要发明很多新技术,是硬件、系统及虚拟化、应用架构彼此之间都有一条鸿沟,那大家就都需要自己造轮子搭梯子解决问题,统一问题必然有N中解法。后面相互磨合久了,鸿沟会进一步变窄,直至平滑过渡。

应用层开发人员,会在很大的技术视野内专注于业务层,其他层的需求只需要简单调用服务即可。

但不久的将来,一定会面临新的巨坑,需要填。

六、FAAS趋势

个人对FAAS有种直觉上的偏见,感觉有些走向了另一个极端:
1、如果保持F很简单,那平台确实可以直接将功能封装为通用服务,但就算加上DSL,F可以施展的空间感觉也不大
2、如果让F变复杂,支持复杂业务,那FAAS其实就退化成为了功能十分单一的微服务,还不如直接微服务来的爽快
整体感觉就是有些鸡肋,一边有纯图形化工具或标准服务,一边是正常程度的编码,夹在中间。

这个真的很像当年ESB的思维方式,给了一堆的标准组件,给人一看感觉封装的真好,不用编程也能做好多事情啊。但用过就知道,稍微复杂的业务就要自己去扩展组件了,不会编程什么都做不了。最后就是换了一个技术平台写代码而已。