mysql连接器,分析器,优化器,执行器

mysqlServer分为:连接器,分析器,优化器,执行器。

1、连接器

管理用户的连接
show processlist;

2、分析器

词法分析,语法分析

calcite 开源数据库分析组件。

3、优化器

优化sql语句,规定执行流程

4、执行器

sql语句实际执行组件

mysql索引

MYISAM

MyISAM简介

每个MyISAM表都以三个文件存储在磁盘上。这些文件的名称以表名开头,并具有扩展名以指示文件类型。一个.frm 文件存储表格式。数据文件的 扩展名为.MYD(MYData)。索引文件的扩展名为.MYI (MYIndex)。

要明确指定要使用MyISAM 表,使用ENGINE表选项进行指示:

CREATE TABLE t (i INT) ENGINE = MYISAM;

MyISAM 表具有以下特征:

  • 所有数据值都先以低字节存储。这使数据机和操作系统独立。二进制可移植性的唯一要求是机器使用二进制补码带符号整数和IEEE浮点格式。这些要求已在主流机器中广泛使用。二进制兼容性可能不适用于有时具有特殊处理器的嵌入式系统。

    先存储低字节数据没有明显的速度损失;表行中的字节通常是未对齐的,按顺序读取未对齐的字节所需的处理要多于反向顺序。而且,与其他代码相比,服务器中获取列值的代码不是时间紧迫的。

  • 所有数字键值都先存储高字节,以实现更好的索引压缩。

  • 在支持大文件的文件系统和操作系统上,支持大文件(文件长度最大为63位)。

  • 表格中 最多只能 有(2^32)2(1.844E + 19)行MyISAM

  • 每个MyISAM 表的最大索引数为64。

    每个索引的最大列数为16。

  • 最大密钥长度为1000个字节。也可以通过更改源代码并重新编译来更改。对于密钥超过250字节的情况,将使用比默认值1024字节更大的密钥块大小。

  • 当按排序顺序插入行时(如使用 AUTO_INCREMENT列时),索引树将被拆分,以便高级节点仅包含一个键。这样可以提高索引树中的空间利用率。

  • AUTO_INCREMENT 支持每个表 对一列的内部处理。MyISAM 自动更新此列的 INSERTUPDATE操作。这样可使 AUTO_INCREMENT列更快(至少10%)。序列顶部的值在删除后不会重复使用。(当一AUTO_INCREMENT列定义为多列索引的最后一列时,确实会重复使用从序列顶部删除的值。)AUTO_INCREMENT可以使用ALTER TABLEmyisamchk重置该 值 。

  • 将删除与更新和插入混合在一起时,动态大小的行的碎片化要少得多。通过自动组合相邻的已删除块并通过扩展块(如果删除下一个块)来完成此操作。

  • MyISAM支持并发插入:如果表在数据文件的中间没有空闲块,则可以INSERT在其他线程从表读取数据 的同时向其中添加新行。由于删除行或使用比当前内容更多的数据更新动态长度行,可能会出现空闲块。当所有可用块用完(填充)时,以后的插入将再次并发。请参见 第8.11.3节“并发插入”

  • 您可以将数据文件和索引文件放在不同物理设备上的不同目录中,以使用DATA DIRECTORY和的INDEX DIRECTORY表选项来提高速度CREATE TABLE。请参见第13.1.18节“ CREATE TABLE语句”

  • BLOB并且 TEXT列可以建立索引。

  • NULL索引列中允许使用值。每个密钥占用0到1个字节。

  • 每个字符列可以具有不同的字符集。请参见 第10章,字符集,整理,Unicode

  • MyISAM索引文件中 有一个标志,指示表是否已正确关闭。如果 使用系统变量集启动 mysqldmyisam_recover_optionsMyISAM则在打开表时会自动对其进行检查,如果未正确关闭表,则会对其进行修复。

  • 如果使用该--update-state 选项运行 myisamchk,则将表标记为已选中。myisamchk –fast仅检查那些没有此标记的表。

  • myisamchk –analyze存储部分键以及整个键的统计信息。

  • myisampack可以包装BLOB和 包装 VARCHAR

    MyISAM 还支持以下功能:

  • 支持真实VARCHAR类型;一VARCHAR列开始与存储在一个或两个字节的长度。

  • VARCHAR列的表可能具有固定或动态的行长。

  • 表格中VARCHAR和 的长度之 和 CHAR可能不超过64KB。

  • 任意长度限制UNIQUE

    InnoDB

InnoDB简介
InnoDB是一种兼顾了高可靠性和高性能的通用存储引擎。在MySQL 5.7中,InnoDB是默认的MySQL存储引擎。除非配置了其他默认存储引擎,否则发出CREATE TABLE不带ENGINE= 子句的语句将创建一个InnoDB表。

InnoDB的主要优势

索引

How MySQL Uses Indexes

叶子节点放的数据不是实际数据,而是主键值。然后回表。
查询时是两颗B+树,一颗索引树,一个原来的B+树

全文索引

  • MySQL支持全文索引和搜索:

    • MySQL中的全文索引是type的索引 FULLTEXT
    • 全文索引只能使用InnoDB或MyISAM表格,并且只能用于创建CHAR,VARCHAR或 TEXT列。
    • MySQL提供了一个内置的全文ngram解析器,该解析器支持中文,日文和韩文(CJK),以及一个用于日语的可安装的MeCab全文分析器插件。第12.9.8节“ ngram全文解析器”第12.9.9节“ MeCab全文解析器插件”中概述了解析差异。
    • FULLTEXT索引定义可以在被给予CREATE TABLE的语句中创建表时,或者稍后使用添加ALTER TABLE或 CREATE INDEX。
    • 对于大型数据集,将数据加载到没有FULLTEXT索引的表中然后再创建索引比将数据加载到具有现有FULLTEXT索引的表中要快得多。

    全文搜索分为三种:

  • 自然语言搜索将搜索字符串解释为自然人类语言中的短语(自由文本中的短语)。除双引号(“)字符外,没有特殊的运算符。适用停用词列表。有关停用词列表的更多信息,请参见第12.9.4节“全文停用词 “

    如果指定了IN NATURAL LANGUAGE MODE修饰符或未指定修饰符,则全文搜索是自然语言搜索 。有关更多信息,请参见 第12.9.1节“自然语言全文本搜索”

  • 布尔搜索使用特殊查询语言的规则解释搜索字符串。该字符串包含要搜索的单词。它还可以包含指定要求的运算符,以使匹配行中的单词必须存在或不存在,或者其权重应高于或低于平常。某些常见单词(停用词)将从搜索索引中省略,并且如果出现在搜索字符串中则不匹配。该IN BOOLEAN MODE修饰符指定一个布尔搜索。有关更多信息,请参见 第12.9.2节“布尔全文本搜索”

  • 查询扩展搜索是对自然语言搜索的修改。搜索字符串用于执行自然语言搜索。然后,将搜索返回的最相关行中的单词添加到搜索字符串中,然后再次执行搜索。该查询返回第二个搜索中的行。该IN NATURAL LANGUAGE MODE WITH QUERY EXPANSIONWITH QUERY EXPANSION修改指定的查询扩展搜索。有关更多信息,请参见 第12.9.3节“具有查询扩展的全文本搜索”

哈希索引

只有memony引擎显示支持哈希索引

  • 仅用于使用=or <=> 运算符的相等比较 (但非常快),不用于比较运算符
  • 优化器无法使用哈希索引来加快ORDER BY操作速度
  • 仅整个键可用于搜索行

组合索引

mysql的联合索引的B+树

有number name age adds四个列时,组合索引 (number age adds)

explain select * from bigtables where number = 101 and age >18 and adds =18;走联合索引number的索引,Using index condition

mysql> explain select * from bigtables where number = 101 and age >18 and adds =18;
+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
| id | select_type | table     | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | bigtables | NULL       | range | idx           | idx  | 10      | NULL |  104 |    10.00 | Using index condition |
+----+-------------+-----------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

explain select * from bigtables where number = 101 and age like '1%' and adds =18;走联合索引number的索引

mysql> explain select * from bigtables where number = 101 and age like '1%' and adds =18;
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-----------------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra                 |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-----------------------+
|  1 | SIMPLE      | bigtables | NULL       | ref  | idx           | idx  | 5       | const |  106 |     1.11 | Using index condition |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

explain select * from bigtables where number = 101 and age like '%9' and adds =18;走联合索引number的索引

mysql> explain select * from bigtables where number = 101 and age like '%9' and adds =18;
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-----------------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra                 |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-----------------------+
|  1 | SIMPLE      | bigtables | NULL       | ref  | idx           | idx  | 5       | const |  106 |     1.11 | Using index condition |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

explain select * from bigtables where age like '%9' and adds =18; 不走索引

mysql> explain select * from bigtables where age like '%9' and adds =18;
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | bigtables | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1010 |     1.11 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

explain select * from bigtables where adds =18;不走索引

mysql> explain select * from bigtables where adds =18;
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | bigtables | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1010 |    10.00 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

B tree和B+ tree

单列索引

  • 聚集索引

  • 非聚集索引

外键

为什么不推荐使用外键约束

foreign-key-optimization

索引覆盖

当sql语句的所求查询字段(select列)和查询条件字段(where子句)全都包含在一个索引中,可以直接使用索引查询而不需要回表。这就是索引覆盖,通过使用覆盖索引,可以减少搜索树的次数,是常用的性能优化手段。

mysql> explain select number, age, adds from bigtables where  number = 101;
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------------+
|  1 | SIMPLE      | bigtables | NULL       | ref  | idx           | idx  | 5       | const |  106 |   100.00 | Using index |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

两个单列索引,查询也能触发索引覆盖

组合索引也可以触发索引覆盖

索引下推

对于bigtables表,我们现在有(name,number)联合索引
如果现在有一个需求,查出名称中以“w”开头且number小于等于101的信息,语句如下:

"select * from bigtables where name like 'w%' and number> 10;".

语句有两种执行可能:

  • 1、根据(name,number)联合索引查询所有满足名称以“w”开头的索引,然后回表查询出相应的全行数据,然后再筛选出满足number小于等于101的用户数据。

  • 2、根据(name,number)联合索引查询所有满足名称以“w”开头的索引,然后直接再筛选出number小于等于101的索引,之后再回表查询全行数据。

明显的,第二种方式需要回表查询的全行数据比较少,这就是mysql的索引下推。
mysql默认启用索引下推,我们也可以通过修改系统变量optimizer_switch的index_condition_pushdown标志来控制

1
SET optimizer_switch = 'index_condition_pushdown=off';

注意点:
1、innodb引擎的表,索引下推只能用于二级索引。

就像之前提到的,innodb的主键索引树叶子结点上保存的是全行数据,所以这个时候索引下推并不会起到减少查询全行数据的效果。

2、索引下推一般可用于所求查询字段(select列)不是/不全是联合索引的字段,查询条件为多条件查询且查询条件子句(where/order by)字段全是联合索引。

假设表t有联合索引(a,b),下面语句可以使用索引下推提高效率
select * from t where a > 2 and b > 10;

参考: mysql索引篇之覆盖索引、联合索引、索引下推

最左匹配

like会不会走索引

根据最左匹配原则:

where like '%ssss%' ;不走索引

where like 'ssss%'; 走索引

where like '%ssss'; 不走索引

优化小细节

数据库操作层面

1 不要使用表达式

虽然执行计划中有可能会判断走索引,但是 rows依然是全表扫描了,1010条

mysql> explain select * from bigtables where number+1  = 103;
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | bigtables | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1010 |   100.00 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from bigtables where number = 103;
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | bigtables | NULL       | ref  | idx           | idx  | 5       | const |   98 |   100.00 | NULL  |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

2 使用索引扫描进行排序时

为排序使用索引Order By优化

mysql默认的排序是asc。

多个排序时,一个逆序,其他asc的时候也不会走索引排序,而同时都desc时候,不会走索引排序
使用索引扫描进行排序
或者一个是desc,也不会走索引排序。Using filesort

mysql> explain select * from abc2 where c >1 order by c desc;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                                    |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------------+
|  1 | SIMPLE      | abc2  | NULL       | index | NULL          | idx_abc | 72      | NULL |    3 |    33.33 | Using where; Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------------------+
1 row in set, 1 warning (0.00 sec)

ERROR: 
No query specified

3 union all(执行计划分多步执行), in, or

or

number,age为联合索引:
mysql> explain select * from bigtables where number = 103 or age = 19;
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | bigtables | NULL       | ALL  | idx           | NULL | NULL    | NULL | 1010 |    19.00 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

a b c为单列索引:
mysql> explain select * from abc where b = 2 or c = 3;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | abc   | NULL       | ALL  | idx_b,idx_c   | NULL | NULL    | NULL |   10 |    23.50 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

union all执行计划分多步执行

mysql> explain select * from abc  union all  select * from abc2\G;
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: abc
   partitions: NULL
         type: index
possible_keys: NULL
          key: idx_abc
      key_len: 14
          ref: NULL
         rows: 3
     filtered: 100.00
        Extra: Using index
*************************** 2. row ***************************
           id: 2
  select_type: UNION
        table: abc2
   partitions: NULL
         type: index
possible_keys: NULL
          key: idx_abc
      key_len: 72
          ref: NULL
         rows: 3
     filtered: 100.00
        Extra: Using index
2 rows in set, 1 warning (0.00 sec)

ERROR: 
No query specified

in

mysql> explain select * from bigtables where number in (101);
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | bigtables | NULL       | ref  | idx           | idx  | 5       | const |  106 |   100.00 | NULL  |
+----+-------------+-----------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from bigtables where number in (101,102);
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | bigtables | NULL       | ALL  | idx           | NULL | NULL    | NULL | 1010 |    21.68 | Using where |
+----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

4 类型转换可能会造成索引失效

ex: name 为varchar 时,where name = 123 会造成索引失效

MySQL小结:锁-3.1.2 行锁变表锁

5 对于数据库中不常用数据可以进行备份或者压缩操作,减少数据库压力

6 使用explain进行检查

EXPLAIN Output Format

rows:

官网中有一句话:

rows (JSON name: rows)

The rows column indicates the number of rows MySQL believes it must examine to execute the query.

For InnoDB tables, this number is an estimate, and may not always be exact.
//对于InnoDB表,此数字是估计值,可能并不总是准确的。
type:
type JSON名称 含义
id select_id SELECT标识符
select_type None SELECT类型
table table_name 输出行表
partitions partitions 匹配的分区
type access_type 联接类型
possible_keys possible_keys 可能的索引选择
key key 实际选择的索引
key_len key_length 所选键的长度
ref ref 与索引比较的列
rows rows 估计要检查的行
filtered filtered 按表条件过滤的行百分比
Extra None 附加信息
Extra:

Using index condition: 通过访问索引并首先对其进行测试以确定是否读取完整的表行来读取表。除非有必要,否则索引信息将用 索引下推 读取整个表行

Using index:仅使用索引树中的信息从表中检索列信息,而不必进行其他查找以读取实际行。

Using filesort:MySQL必须额外进行一遍,以找出如何按排序顺序检索行。排序是通过根据联接类型遍历所有行并存储与该WHERE子句匹配的所有行的排序键和指向该行的指针来完成的。然后对键进行排序,并按排序顺序检索行。

Using join buffer (Block Nested Loop), Using join buffer (Batched Key Access):来自较早联接的表被部分读取到联接缓冲区中,然后从缓冲区中使用它们的行来执行与当前表的联接。

Using temporary:为了解决该查询,MySQL需要创建一个临时表来保存结果。如果查询包含GROUP BY和 ORDER BY子句以不同的方式列出列,通常会发生这种情况。

Using where:WHERE子句用于限制来匹配下一个表或发送到客户端的行。

7 查看查询语句每一个步骤的时间

show-profile

官网中有一句话:该SHOW PROFILE和 SHOW PROFILES语句被取消,并将在未来的MySQL版本中删除,改用性能模式;

The SHOW PROFILE and SHOW PROFILES statements are deprecated and will be removed in a future MySQL release. Use the Performance Schema instead; see Section 25.19.1, “Query Profiling Using Performance Schema”.

SET profiling = 1;

select * from abc;

SHOW PROFILE FOR QUERY 1; //  SHOW PROFILES;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000056 |
| checking permissions | 0.000010 |
| Opening tables       | 0.000029 |
| init                 | 0.000019 |
| System lock          | 0.000011 |
| optimizing           | 0.000006 |
| statistics           | 0.000012 |
| preparing            | 0.000009 |
| executing            | 0.000003 |
| Sending data         | 0.000053 |
| end                  | 0.000006 |
| query end            | 0.000009 |
| closing tables       | 0.000009 |
| freeing items        | 0.000014 |
| cleaning up          | 0.000013 |
+----------------------+----------+
15 rows in set, 1 warning (0.00 sec)

8 数据库性能监控 Performance Schema

使用性能模式进行查询分析

9 数据库参数设置:线程池等。。。

数据库设计层面

1 索引一定要加适量

创建索引会使查询操作变得更加快速,但是会降低增加、删除、更新操作的速度,因为执行这些操作的同时会对索引文件进行重新排序或更新;

2 考虑前缀索引

前缀索引是一种能使索引更小,更快的有效办法

注意:MySQL中无法使用前缀索引进行ORDER BY和GROUP BY,也无法用来进行覆盖扫描

MySQL前缀索引和索引选择性

3 更新十分频繁,数据区分度不高的字段不推荐建立索引

  • sex: 男,女
  • 更新会变动B+树,更新频繁的字段建立索引会大大降低数据库性能

4 创建索引的列,不允许为null

5 当需要表连接的时候,最好不要超过三张表,因为需要join的字段,数据类型必须一致

6 表设计时字段优化

  • 尽可能选择小的数据类型 ex: tinyint
  • 字段不要过多,取名见名思义,加注释,预留字段供扩展

MySQL数据库表结构设计优化技巧

全表扫描

table-scan-avoidance

使用EXPLAIN分析SQL时,当列出执行计划表中type字段值为ALL时,代表需要全表扫描 ,mysql会在一下情况使用全表扫描:

  • 所扫描的数据表非常小,因此全表扫描的速度要远快于使用索引, 对于少于10行且行长较短的表
  • 在ON或WHERE子句中没有可以使用的索引列
  • 在使用索引列与常量值比较,并且MySQL服务已经通过索引树计算出常量值覆盖了大部分表数据,此时使用全表扫描是比较快的。
  • 当前正在使用一个对于其他列来说基数较低的索引(每个索引值在另一列都有多行行对应),在这种情况下,使用索引可能会引起较多的索引查询,MySQL认为全表扫描比较快。
避免全表扫描

对于小型表,表扫描通常是合适的,并且对性能的影响可以忽略不计。对于大型表,使用以下操作可以帮助优化器对于是否进行全表扫描做出正确的判断:

  • 使用ANALYZE TABLE tbl_name语句来更新被扫描表中索引的分布。

  • 使用FORCE INDEX 语句来强制优化器对该表放弃全表扫描而使用索引,如下:

1
2
SELECT * FROM t1, t2 FORCE INDEX (index_for_column)
WHERE t1.col_name=t2.col_name;

force index()指令可以指定本次查询使用哪个索引。

mysql优化器会计算出一个合适的索引,但是这个索引不一定是最好的。force index()指令可以避免MySql优化器用到了一个低效的索引。

  • 设置启动参数–max-seeks-for-key=1000或使用参数SET max_seeks_for_key=1000来通知优化器如果没有索引扫描会导致过千的索引查找。

join

执行联接时从其他表中检索行。如果声明相同的类型和大小,MySQL可以更有效地在列上使用索引。在这种情况下, VARCHARCHAR被认为是相同的,如果它们被声明为相同的大小。例如, VARCHAR(10)CHAR(10)是相同的大小,但是 VARCHAR(10)CHAR(15)不是。

  • 如果ORDER BYand GROUP BY子句中的所有列 都来自同一表,则在连接时优先使用该表。
  • 如果存在一个ORDER BY子句和另一个GROUP BY子句,或者如果 ORDER BYGROUP BY 包含连接队列中第一个表以外的表中的列,则会创建一个临时表。

压缩如何用于InnoDB表

MySQL在著名的zlib库的帮助下实现了压缩,该 库实现了LZ77压缩算法。这种压缩算法在CPU利用率和数据大小减小方面都是成熟,可靠且有效的。该算法是 “ 无损的 ”,因此始终可以从压缩形式中重建原始的未压缩数据。LZ77压缩通过查找在要压缩的数据内重复的数据序列来工作。数据中的值模式决定了压缩的程度,但是典型的用户数据通常压缩50%或更多。

由于B树页面经常更新,因此需要特殊对待。重要的是,最小化B树节点的分割次数,以及最小化解压缩和重新压缩其内容的需求。

MySQL使用的一种技术是以未压缩的形式维护B树节点中的一些系统信息,从而促进某些就地更新。例如,这允许对行进行删除标记和删除,而无需任何压缩操作。

另外,MySQL试图避免在更改索引页时不必要的解压缩和重新压缩。在每个B树页面中,系统保留一个未压缩的 ‘ modification log ‘以记录对该页面所做的更改。小记录的更新和插入可以写入此修改日志,而无需完全重建整个页面。

当修改日志的空间用完时,InnoDB解压缩页面,应用更改并重新压缩页面。如果再压缩失败(称为一个的情况 压缩破坏),B-树节点被分割,并重复该过程,直到更新或插入成功。

参考资料:

MySQL索引背后的数据结构及算法原理

涉及到的数据库表结构为:

mysql> show index from bigtables;
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| bigtables |          0 | PRIMARY  |            1 | id          | A         |        1010 |     NULL | NULL   |      | BTREE      |         |               |
| bigtables |          1 | idx      |            1 | number      | A         |          10 |     NULL | NULL   | YES  | BTREE      |         |               |
| bigtables |          1 | idx      |            2 | age         | A         |          17 |     NULL | NULL   | YES  | BTREE      |         |               |
| bigtables |          1 | idx      |            3 | adds        | A         |          17 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (0.00 sec)

mysql> show index from abc;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| abc   |          0 | PRIMARY  |            1 | a           | A         |           3 |     NULL | NULL   |      | BTREE      |         |               |
| abc   |          1 | idx_a    |            1 | a           | A         |           3 |     NULL | NULL   |      | BTREE      |         |               |
| abc   |          1 | idx_b    |            1 | b           | A         |           3 |     NULL | NULL   | YES  | BTREE      |         |               |
| abc   |          1 | idx_c    |            1 | c           | A         |           2 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (0.00 sec)

mysql面试题

mysql为什么强制⾃增主键
mysql是怎么保证事务的
limit 20000 加载很慢怎么解决
字段B、C联合索引,如果where C=1 and B=2;
字符串索引变⻓;

事务是怎么做的?@Transactional注解,事务失效场景?⽐如:A⽅法包含查
询、更新操作,B⽅法调⽤了A⽅法?事务嵌套问题?事务的传播机制。
required、support、require_new、manodory、not_support、
sql查询经历了什么?
聚集索引和⾮聚集索引有何区别?
表:name、age、sex,索引index(name,age,sex)
mysql默认的事务隔离级别?是否有幻读?如何解决幻读?Mysql有哪些锁?
MVCC是什么?

mysql的数据库隔离级别?默认是什么隔离级别?

mysql 聚集索引叶⼦节点存储的是什么?
线程池中的核⼼线程数是怎么设置的?⼜怎么根据运⾏情况调整的?
Java中有哪些线程安全的机制?
mysql查询优化举例?

k8s小结

#1、基础概念

1 容器编排系统

- Service Discovery  [服务注册和发现]
- Load Balancing     [负载均衡]
- Secrets/configuration/storage management  [配置和存储管理]
- Health checks  [健康检查]
- Auto-[scaling/restart/healing] of containers and nodes [自动扩容、缩容、重启]
- Zero - downtime deploys  [零宕机]

2 容器编排系统种类

1 Kubernetes
2 Docker Swarm 
3 Apache Mesos and Marathon

2、集群部署及陈述式命令管理

3、资源类型及配置清单

4、Pod资源

5、Pod控制器

6、Service资源

7、存储卷

8、ConfigMap与Secret资源

9、StatefulSet控制器

10、认证、授权及准入控制

11、网络模型及网络策略

12、Pod资源调度

13、CRD、自定义资源、自定义控制器及自定义APR server

14、资源指标与HPA控制器

15、Helm管理器

16、高可用k8s

17、部署要点

  • 测试环境

    • 可以使用单master节点,单etcd实例;
    • Node主机数量按需而定
    • nfsglusterfs等存储系统
  • 生产环境

    • 高可用etcd集群,建立3、5或7个节点;
    • 高可用Master
      • kube-apiserver 无状态,可多实例;
        • 借助于keepalived进行vip流动实现多实例冗余;
        • 或在多实例前端通过HAProxyNgind反代,并借助于keepalived对代理服务器进行冗余
      • kube-schedulerkube-controller-manager各自只能有一个活动实例,但可以有多个备用;
        • 各自自带leader选举功能,并默认处于启用状态;
    • Node主机,数量越多,冗余能力越强;
    • cephglusterfsiSCSIFC SAN及各种云储存等;

18、常用命令

kubectl create namespace ***
kubectl get namespaces

#1、持久化

RDB 快照

恢复快,数据存储量大,数据丢失多

AOF 日志

恢复慢,数据存储量小,数据丢失少,

文件存储在 /var/lib/redis/6379

日志文件越来越大的时候,而key值不断被修改,可以通过手动 BGREWRITEAOF重置日志文件。
可以抵消重复的数据。

R&A

配置文件开启
vi/etc/redis/6379.conf

`aof-use-rdb-preamble yes`

2、主从复制集群

AFK微服务划分原则

CAP定理

3、redis、zookeeper分布式锁对比

如何正确使用redis分布式锁

Redis分布式锁正确的实现方法

假如Redis节点宕机了,那么所有客户端就都无法获得锁了,服务变得不可用。
为了提高可用性,我们可以给这个Redis节点挂一个Slave,当Master节点不可用的时候,
系统自动切到Slave上(failover)。但由于Redis的主从复制(replication)是异步的,
这可能导致在failover过程中丧失锁的安全性。
针对这个问题,可以参考一下Redlock的算法。

#1、偏向锁

2、自旋锁

3、重量级锁

自旋锁是要占用CPU的,线程数量过多的时候,用自旋锁不合适

当自旋超过10,或者当前线程超过CPU的二分之一,升级为重量级锁。

Adaptive CAS: 自适应自旋。自动判断是否升级为重量级锁

MySQL锁

参考资料:

innodb-locking-transaction-model

1、概述

不同存储引擎支持不同的锁机制。

  • MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);

  • BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁;

  • InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但是默认情况下采用行级锁。

表级锁、行级锁、页面锁

  • 表级锁:开销小,加锁快;不会出现死锁;锁粒度大。发生冲突几率最大,并发度最低。

  • 行级锁:开销大,加锁慢;会出现死锁,发生锁冲突几率最低,并发度最高。

  • 页面锁:介于表级锁和行级锁之间。

查看当前数据库支持的引擎

mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)

查看当前默认的引擎

mysql> show variables like 'default_storage_engine';
+------------------------+--------+
| Variable_name          | Value  |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+
1 row in set (0.00 sec)

修改数据库当前引擎

alter table table_name engine=MyISAM;

查看指定表当前的引擎

show table status where NAME ='table_name' 

修改mysql默认的数据库引擎

打开配置文件my.ini,将“default-storage-engine=MYISAM”改为你想设定的,然后重启即可

2、MyISAM表级锁

Mysql的表级锁有两种模式:表共享锁(Table Read Lock)和表独占锁(Table Write Lock).

2.1、共享读锁

lock table 表名 read
unlock table table_name

现在用两个窗口模拟多个client请求mysql,当开启共享读锁时,其他client在修改表数据时,进入等待状态。

解除共享读锁后,其他client才会进行提交操作。

2.2、表独占锁

lock table 表名 write 
unlock table table_name

现在用两个窗口模拟多个client请求mysql,当开启表独占锁时,其他client在查询表数据时,进入等待状态。

解除表独占锁后,其他client才会进行提交操作。

2.3、查询表级锁使用情况

show status like 'table%'
show variables like '%table%'

Table_locks_immediate:产生表级锁定的次数;
Table_locks_waited:出现表级锁定争用而等待的次数。

两个参数值都是系统启动后开始记录的,出现一次对应的事件,则数量加一。当Table_locks_waited状态值比较高时,那么说明系统中表级锁定争用现象比较明显。

2.4 别名

表名以别名的形式进行操作时,需要在锁操作时添加别名lock table 表名 as 别名 write

2.5 session和锁

一个session使用lock table命令给表加了锁,这个session可以查询锁定表中的记录,但是更新或访问其他表都会提示错误;
同时,另外一个session可以查询表中的记录,但更新就会出现锁等待,查询其他表数据不受影响。

2.6 并发插入

  • 当concurrent_insert=0时,此时读不能与insert写共存。
  • 当concurrent_insert=1时,如果表中没有空数据块时(即表中没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入数据。(默认设置)。
  • 当concurrent_insert=2时,不论有没有空数据块,都允许在表尾插入数据。

2.6.1 查看当前设置状态

mysql> show variables like 'concurrent_insert';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| concurrent_insert | AUTO  |
+-------------------+-------+
1 row in set (0.00 sec)

2.6.2 设置并发插入状态

mysql> set global concurrent_insert = 2;
Query OK, 0 rows affected (0.00 sec)

2.6.3 举例并发插入状态为2(ALWAYS)时

show variables like 'concurrent_insert';
+-------------------+--------+
| Variable_name     | Value  |
+-------------------+--------+
| concurrent_insert | ALWAYS |
+-------------------+--------+
1 row in set (0.00 sec)

现在用两个窗口模拟多个client请求mysql,当client_A开启并发插入时,

mysql> lock table student read local;
Query OK, 0 rows affected (0.00 sec)

client_B在操作表数据时,可以直接修改表中数据。
但是此时client_A对该表进行查询操作时,表中数据依然为未修改数据;而其他client为已修改数据。

2.7 一个进程请求某个MyISAM表的读锁,同时另一个进程也请求同一个表的写锁,mysql如何处理?

写进程先获得锁,即使读请求先到锁等待队列,写请求后到,写锁也会插到读锁队列。
Mysql认为写请求写请求比读请求更重要。
MyISAM不太适合有大量更新操作和查询操作的原因,因为大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。

解决方法:
执行`set low_priority_updates=1`,使该连接发出的更新请求优先级降低。同理insert,delete也可以通过此方法指定。

另外MySQL也提供了一种折中的方法调节读写冲突,即给系统参数max_write_lock_count设置一个合适的值,当一个表的读锁达到这个值后,MySQL就暂时将写请求的优先级降低,给读进程一定的获取锁的机会

3 Innodb锁

关闭自动提交 `set autocommit=0;`
  • 共享锁(S) :读锁
  • 排它锁(X) :写锁
  • 意向共享锁(IS)
  • 意向排他锁(IX)
排它锁(X) 意向排他锁(IX) 共享锁(S) 意向共享锁(IS)
排它锁(X) 冲突 冲突 冲突 冲突
意向排他锁(IX) 冲突 兼容 冲突 兼容
共享锁(S) 冲突 冲突 兼容 兼容
意向共享锁(IS) 冲突 兼容 兼容 兼容

3.1 意向锁

3.1.1 意向锁

意向锁

对于update、delete和insert语句,Innodb会自动给涉及数据集加排他锁(X);
对于普通的select语句,Innodb不会加任何锁。

事务可以通过以下语句显式的给记录集加锁:

//共享锁
select * from table_name where  ... lock in share mode;
//排它锁
select * from table_name where ... for update;

3.1.2 行锁变表锁

InnoDB行锁是通过给索引上的索引项加锁来实现的:只有通过索引检索数据,InnoDB才使用
行锁,否则,InnoDB使用表锁。

现在用两个窗口模拟多个client请求mysql,当client_A对表中某一行数据进行修改时,触发了索引失效。
client_A未进行commit时,则client_B对该表中其他行数据进行修改时,发生了表锁事件。

注释:实例中 `name`字段为`varchar`类型的索引,在更新操作时字段赋值为 666(而不是'666') ,此时mysql数据库会自动将其类型转化。
转化条件需要设置sql模式为非严格模式

mysql> show session variables like '%sql_mode%';
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value                                                                                                                                     |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| sql_mode      | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

mysql> set sql_mode='NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
Query OK, 0 rows affected (0.00 sec)

mysql> show session variables like '%sql_mode%';
+---------------+--------------------------------------------+
| Variable_name | Value                                      |
+---------------+--------------------------------------------+
| sql_mode      | NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+---------------+--------------------------------------------+
1 row in set (0.01 sec)

3.1.3 间隙锁(gap lock)

InnoDB使用间隙锁的目的:

  • 防止幻读,以满足相关隔离级别的要求;
  • 满足恢复和复制的需要;

间隙锁

如何开启和关闭MySQL 间隙锁(gap lock)

间隙锁定是对索引记录之间的间隙的锁定,或者是对第一个或最后一个索引记录之前的间隙的锁定。

例如,SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;

防止其他事务将value 15插入column中t.c1,无论该列 中是否已有这样的值,
因为该范围中所有现有值之间的间隙都是锁定的。

间隙可能跨越单个索引值,多个索引值,甚至为空。

对于使用唯一索引来锁定唯一行来锁定行的语句,不需要间隙锁定。
(这不包括搜索条件仅包含多列唯一索引的某些列的情况;在这种情况下,会发生间隙锁定。)
例如,如果该id列具有唯一索引,则以下语句仅使用一个具有id值100 的行的索引记录锁定,
其他会话是否在前面的间隙中插入行并不重要:
SELECT * FROM child WHERE id = 100;

间隙锁定InnoDB是“ 纯粹抑制性的 ”,这意味着它们的唯一目的是防止其他事务插入间隙。

3.1.4 InnoDB使用索引的条件

  • 在不通过索引条件查询的时候,InnoDB确实使用的是表锁,而不是行锁。
  • mysql的行锁是针对索引加的锁。不是针对记录加的锁,虽然是访问不同的行,但是若是相同的索引,会出现锁锁冲突的。
    当表中含有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行。
  • 即使在条件中使用了索引,但是是否使用索引来检索数据是由MySQL通过判断不同执行计划的代价决定的,如果MySQL认为全表扫描效率更高,比如很小的表,他也不会使用索引,此时InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突的时候,不要忘记检查SQL的执行计划,以确定是否真正使用了索引。
关于InnoDB到底是使用行锁还是表锁,我们需要依据索引来决定的,本质上行锁是针对索引加的锁,而非记录!!!
虽然是访问不同的行,但是若是含有相同的索引,还是会发生锁冲突的!!!
而且就算条件里面使用了索引,Mysql也不一定走索引,还是要看SQL的执行计划!!!

参考资料:

InnoDB使用索引的条件

从 v1.0以来,第一个 Hyperledger Fabric 主版本,Fabric v2.0为用户和运营商提供了重要的新功能和更改,包括对新应用程序和隐私模式的支持,围绕智能合约对管理增强,操作节点的新选择。

保持不变的是根据您自己的条件升级网络组件的能力,支持从 v1.4.x 开始滚动升级,以及只有在成员组织准备好时才启用新功能的能力。

下面我们就来看看 Fabric v2.0 发布的一些亮点……

##智能合约的去中心化治理
Fabric v2.0 引入了智能合约的去中心化治理,它提供了一个新的流程,用于在您的 Peer 节点上安装链码,并在通道上启动它。新的 Fabric 链码生命周期允许多个组织在它用于与账本交互之前认同链码的参数,例如链码背书策略。对于比以前的生命周期,新的模式有几个改进:

###多组织必须认同链码参数
在 Fabric 1.x 版本中,一个组织有能力为所有其他通道成员设置链码的参数(例如背书策略),这些通道成员只有拒绝安装链码的权力,因此不能参与调用它的事务。新的 Fabric 链码生命周期更加灵活,因为它既支持中心化的信任模式(如以前的生命周期模式),也支持去中心化的模式,去中心化的模式要求在链码于通道上变为活动状态之前,有足够数量的组织就背书策略和其他细节达成一致意见。

###更周密的链码升级过程
在以前的链码生命周期中,升级交易可能由单个组织发出,这会给尚未安装新链码的通道成员带来风险。新的模式允许只有在足够数量的组织批准升级后才能升级链码。

###更简单的背书政策和私有数据收集更新
Fabric生命周期允许您更改背书策略或私有数据收集配置,而无需重新打包或重新安装链码。用户还可以利用新的默认背书策略,该策略要求获得通道上大多数组织的背书。在通道中添加或删除组织时,会自动更新此策略。

###可被检查的链码包
Fabric生命周期将链码封装在易于阅读的 tar 文件中。这使得检查链码包和跨多个组织协调安装变得更加容易。

###使用一个包在通道上启动多个链码
以前的生命周期在安装链码包时使用指定的名称和版本定义通道上的每个链码。您现在可以使用单个链码包,并以不同的名称在同一通道或不同通道上多次部署它。例如,如果您想在链码自己的“副本”中跟踪不同类型的资产。

###链码包不需要在通道成员之间相同
组织可以用他们自己的用例扩展链码,例如为了他们组织的利益执行不同的验证。只要所需数量的组织为链码交易背书和结果相匹配,该交易将被验证并提交到帐本中。这还允许组织按照自己的时间表单独推出小的修补程序,而不需要整个网络同步进行。

##使用新的链码生命周期
对于现有的 Fabric 部署,您可以继续使用 Fabric v2.0 之前的链码生命周期。新的链码生命周期只有在通道应用程序功能更新到 v2.0 时才会生效。 关于新的链码生命周期完整细节教程请看 Chaincode for Operators

用于协作和共识的新链码应用程序模式

支持新的链码生命周期管理的相同的去中心化的达成协议的方法也可以用于您自己的链码应用程序中,以确保组织在数据交易被提交到帐本之前同意它们。

####自动检查
如上所述,组织可以在链码功能中添加自动检查,以便在背书事务提案之前验证附加信息。

####去中心化协议
链码可能要求来自不同组织的参与者在账本交易中指明他们的协议条款和条件。然后,最终的链码提案可以验证来自所有单个交易者的条件是否得到满足,并最终在所有通道成员之间“解决”业务交易。有关以非公开方式指示条款和条件的具体示例,请参见资产转移场景,于文档中 私有数据.

##私有数据增强
Fabric v2.0还支持使用和共享私有数据的新模式,而不需要为所有可能要进行交易的通道成员组合创建私有数据集合。具体地说,您不是在多个成员的集合中共享私有数据,而是可能想要跨集合共享私有数据,其中每个集合可能包括单个组织,或者带有一个监管者或审计师的单个组织。

Fabric v2.0 中的几个增强使得这些新的私有数据模式成为可能:

###共享和验证私有数据
当私有数据与不是集合成员的通道成员共享时,或者与包含一个或多个通道成员的另一个私有数据集合共享时(通过向该集合写入密钥),接收方可以利用 GetPrivateDataHash() 链码 API 验证私有数据是否与以前交易中被创建的来自私有数据的链上哈希匹配。

###集合水平的背书策略
现在可以选择使用背书策略来定义私有数据集合,该背书策略覆盖集合内密钥的链码级别背书策略。该特性可用于限制哪些组织可以将数据写入集合,并且正是它启用了前面提到的新的链码生命周期和链码应用程序模式。例如,您可能有一个链码背书策略,该策略要求大多数组织背书,但对于任何给定的交易,您可能需要两个交易处理组织在它们自己的私有数据集合中单独背书它们的协议。

###每个组织的隐式集合
如果您想利用每个组织的私有数据模式,那么在 Fabric v2.0 中部署链码时甚至不需要定义集合。不需要任何前期定义就可以使用隐式的特定组织集合。
了解更多关于新的私有数据模式请看 私有数据 (概念文档). 更多关于私有数据集合配置和隐式集合请看 Private Data (参考文档).

##外部的链码启动器
外部链码启动器功能使运营商能够使用他们选择的技术构建和启动链码。不需要使用外部构建器和启动器,因为默认行为构建和运行链码的方式与使用 Docker API 的先前版本相同。

###消除 Docker
守护进程依赖 Fabric 以前的版本要求 Peer 节点能够访问 Docker 守护进程,以便构建和启动链码——由于 Peer 节点进程所需的特权,这在生产环境中可能是不可取的。

###容器的替代品
不再要求链码在 Docker 容器中运行,可以在运营商选择的环境(包括容器)中执行。

###外部构建器可执行文件
操作员可以提供一组外部构建器可执行文件,以覆盖 Peer 节点构建和启动链码方式。

###作为外部服务的链码
传统上,链码由 Peer 节点启动,然后连接回 Peer 节点。现在可以将链码作为外部服务运行,例如在 Kubernetes pod 中, Peer 节点可以连接到该 pod,并利用该 pod 执行链码。了解更多信息请看 Chaincode as an external service
了解更多关于外部链码启动功能请看 External Builders and Launchers

##用于提高 CouchDB 性能的状态数据库缓存
在使用外部 CouchDB 状态数据库时,背书和验证阶段的读取延迟历来是性能瓶颈。
在 Fabric v2.0 中,一个新的 Peer 节点缓存用快速的本地缓存读取取代了许多昂贵的查找。可以使用 core.yaml 文件中的属性 cachesize 来配置缓存大小。

##基于 Alpine 的 docker 镜像
从 v2.0 开始,Hyperledger Fabric Docker 镜像将使用 Alpine Linux 作为基础镜像,这是一个面向安全的轻量级 Linux 发行版。这意味着 Docker 镜像现在要小得多,提供更快的下载和启动时间,以及占用主机系统上更少的磁盘空间。Alpine Linux 的设计从一开始就考虑到了安全性,Alpine 发行版的最小化特性大大降低了安全漏洞的风险。

##示例测试网络
Fabric-Samples 仓库现在包括一个新的 Fabric 测试网络。测试网络被构建为模块化的和用户友好的示例 Fabric 网络,这使测试您的应用程序和智能合约变得容易。除了 Cryptogen 之外,该网络还支持使用 Certificate Authorities 部署网络的能力。

了解更多关于这个网络的信息,请查看 Using the Fabric test network.

##升级到 Fabric v2.0
一个主要的新版本带来了一些额外的升级注意事项。不过请放心,我们支持从 v1.4.x 到 v2.0 的滚动升级,因此可以一次升级一个网络组件而不会停机。

升级文档得到了显著的扩展和修改,现在在文档中有了一个独立的主页 Upgrading to the latest release. 这里您将会发现文档
Upgrading your componentsUpdating the capability level of a channel, 以及对升级到 v2.0 的注意事项的具体了解, Considerations for getting to v2.0

#1、安装kafka

kafka-quickstart

#2 分区存储文件原理

#3 kafka选择分区模式

#4 生产者往kafka发送数据的模式

#5 为什么kafka快

#6 消费者组消费数据的原理

#7 生产者往kafka发送数据原理

kafka和rocketmq都能实现消息队列,为什么要引入rocket,不直接使用kafka

zk 分布式锁慢 除了IO慢之外还有其他原因吗?

排它锁的粒度大,没有区分读、写操作,如果读多写少,则十分影响性能
羊群效应:锁释放后会通知所有等待中的 ZooKeeper 客户端,然后同时发起加锁请求,瞬时压力很大

解决方案是:

1.缩小通知范围:等待锁的小伙伴们按先来后到的顺序排队吧,排好队了,接下来我只需要关心我前面一个节点的状态,当前一个节点被释放,我再去抢锁。

2.缩小锁的粒度:锁不关心业务,但是可以简单地通过操作的读、写性质来二分锁的粒度:
读锁:又称共享锁,如果前面没有写节点,可以直接上锁;当前面有写节点时,则等待距离自己最近的写节点释放( 删除 )。
写锁:如果前面没有节点,可以直接上锁;如果前面有节点,则等待前一个节点释放( 删除 )。

(转)联盟链,Fabric比较其他联盟链的优势

联盟链是目前区块链落地实践的热点,也是大家对“杀手级应用”期望最大的区块链部署形态。联盟链的诞生源于对区块链技术的“反思”,是对比特币、以太坊所体现的技术特点与企业客户实际需要的融合与折衷,蕴含了大量区块链工作者的智慧与辛劳。

由于对未来价值的“共识”,很多厂商推出了自己的联盟链框架或平台,本文选择了 Hyperledger Fabric、FISCO BCOS、微软的 Coco、企业以太坊联盟(EEA)及 R3 的 Corda 这五个具有一定影响力的联盟链,拟从设计理念、生态、效率、扩展性、节点管理与权限管理、智能合约、部署与运维友好性、隐私保护、公链结合或演化能力九个方面进行比对,以供各位开发者、爱好者参考。

其中,EEA 由于只出具规范而不涉及代码,所以比对中采用了其官方承认的技术基础——摩根大通的 Quorum 平台;Corda 并不是区块链,严格说与其他四者的比较属于分布式账本技术这个层级的比较,但是由于其承认设计上是受到区块链技术启发,且对其他联盟链也产生了一定的影响,因此,也列入了比较范围。本文的信息主要来源于公开的技术白皮书、Github 中的开源信息,就不在文中一一注明了。

#一、设计理念

设计理念其实决定了一个框架或者系统的最佳应用方式,是其设计的出发点,因此,研究每种区块链时,都应当认真关注其如何“看待自己”,以免在应用上出现“硬套”的问题。设计理念上本文分成核心思路与市场定位两部分进行比较。

##(一)核心思路

核心思路体现的是其设计初衷,这个“初心”对其后续技术走向有一定的影响。

Hyperledger Fabric 是希望改变公链的单一通用网络模式,通过建立多个可以互联的区块链网络覆盖各类不同的业务场景,实现设计的灵活性,满足多样化的要求,并实现网络间的交互,这种思路体现在了其独特的通道机制设计上。

FISCO BCOS 初衷是设计一个国内企业主导研发、自主可控、对外开源的满足金融行业需求企业级区块链底层平台,并逐渐扩展至其他领域、适用于广泛的分布式商业场景,所以进行了自底向上的完整设计,并考虑了较多国内的特殊需求。

Coco 基于保密联盟环境的假定,重新评估了公链的设计,通过将其他区块链协议集成为底层,快速高效地构建区块链应用。在这种思路下 Coco 大胆放松了一些关键的设计限制,并且最终实现了一个对现有区块链协议的加速机制,可集成的协议已经包括 Hyperledger Fabric、以太坊、Corda、Quorum 等。

EEA 是力求引导一种基于以太坊的标准区块链设计,可根据成员需要定制,但不提供代码(Quorum 提供部分开源代码)。官方承认其技术基础是摩根大通开发的 Quorum 平台,该平台的目标则是提供高速、高吞吐量交易的能力,以解决区块链技术在金融等领域遭遇的挑战。

Corda 希望提供一个具有唯一性、权威性、可以记录企业间所有协议的全局逻辑账本,核心是实现具有节点间最小信任机制的无中心数据库,因此,Corda 主张充分考虑与现有业务系统的结合,而非将现有业务系统拆掉重来。Corda 的设计思路对 Hyperledger Fabric 有一定影响,也参与了对后者的建设。

##(二)市场定位

市场定位反映了对自身应用方向的价值主张。五个联盟链都是面向企业级应用的,但是具体的定位略有差异:

Hyperledger Fabric 旨在打造不分行业的通用区块链开源框架;

FISCO BCOS 源自企业级区块链平台 BCOS,做为一个金融版本分支,保留通用性的同时,更关注于金融行业,并且较多考虑了监管机构的特殊性;

Coco 希望提供更高效易用的区块链技术,没有特殊的行业定位;

EEA 比较有趣,它以将所有企业导向一个统一的路线图(该路线图以以太坊技术发展为基础)为目标,但是由于目前的技术代表是摩根大通的 Quorum,所以,应用实例上对金融行业更有指导性;

Corda 则是针对金融行业的,并且明确提出至少一定时间内不会考虑其他行业。

从设计理念的角度来讲,选用 Hyperledger Fabric 时,应当善用其通道机制,通过通道机制降低业务或者环境的复杂度,但是要注意其跨通道能力的一些技术限制;FISCO BCOS 则应关注其对国内市场特殊需求的适应性设计,这些设计会带来很多部署上的优势;Coco 和 EEA(Quorum)设计理念上都属于基于现有协议的优化加速机制,只是前者“博爱”,兼容的协议更多,后者“专一”,只针对以太坊;选用 Corda 则要先明确,它不是区块链,不要带着区块链的价值假定去应用。

#二、生态

大家常说建联盟链就是建生态,所以本文就比较下要帮着别人建生态的联盟链,其自身的生态建的如何。生态考察主要包括管理方、社区和商业应用这三个方面。

##(一)管理方

从管理方看,各家都是“实力派”。

Hyperledger Fabric 的管理方是 Linux 基金会,基金会管理下的 Hyperledger 其实是一个项目系列,包括 Cello、Swatooth、Burrow、Iroha 等;

FISCO BCOS 管理方是金链盟,金链盟是由深圳市金融科技协会、深圳前海微众银行、深证通、腾讯、华为、中科院等金融机构、科技企业、学术机构等组成的非营利性组织;(参考 https://www.fisco.com.cn/views/member.html)

Coco 的管理方是微软;

EEA 是由芝加哥交易所、因特尔、ING、摩根大通和微软等三十几家创始成员组成的;

Corda 的管理方 R3 是以银行为主的组织,至少已经吸收了 42 家金融巨头,包括富国银行、美国银行、花旗银行、德意志银行、加拿大皇家银行等,我国的平安、招行等也是其成员,不过 R3 麻烦不断,也有些重量级成员已经退出。

##(二)社区

现今科技发展比较流行开源,五大联盟链也都是开源的,开源意味着要搞好社区建设,通过社区推广和改进设计,凝聚更多智慧。

Hyperledger Fabric 已经打造了国际化的社区,除了在 GitHub 上比较活跃外,大量的线下 Meetup、技术推广活动也比较多,加上 IBM 的有力推动,使其有了大量的活跃用户;

FISCO BCOS 社区建设初现规模,已有了千级成员、百级机构参与,除了 GitHub 外,还有官方微信群。FISCO BCOS 在不断迭代源码和文档的基础上,陆续推出了线上线下多种形式的系列运营活动,包括技术培训、高校开课、线上线下讲座沙龙、包括近期举办的金链盟中国区块链大赛,影响力逐渐扩散。作为国内开源项目,相信未来发展上会有一定的“天时地利人和”;

Coco 社区不是很活跃;

Quorum 在 GitHub 上已经有了 551 个话题,有一定活跃度;

Corda 也不是很活跃。

##(三)商业应用

商业应用是大家打造区块链平台的目的,也是一个联盟链最重要的人气所在。

Hyperledger Fabric 得益于 IBM 的大力推广,加上技术框架比较成熟、推出较早,目前已有较多商业应用,据 IBM 披露有 400 多个落地项目,其中不乏马士基、沃尔玛、联想、邮储银行这类大型客户,也有统计称,所有联盟链项目中 Hyperledger Fabric 已占据半壁江山;

FISCO BCOS 从金融出发,携本土优势,落地项目也有数十个,包括微众银行的机构间对账平台、网易的竞猜游戏,四方精创的供应链金融、城商行旅游金融联盟的旅游金融、仲裁链、安妮股份的版权存证平台、乐寻坊的人才活动平台、链动时代的不动产登记系统等;

Coco 目前在项目方面乏善可陈,除了其白皮书中提到的 Mojix 将其供应链 Dapp 转移到 Coco 平台上之外,没有更多公开的项目信息;

Quorum 上,比较有影响的应该算是 2017 年 10 月摩根大通开发的 IIN(Interbank Information Network)平台,实现跨行信息交互,摩根大通、加拿大皇家银行、澳大利亚 ANZ 银行、新西兰银行等相继加入该平台;

Corda 也是同样的境地,雷大雨小,耗费巨资,但是测试的多,落地的少。

从生态角度看,Hyperledger Fabric启动的比较早,目前领先一步,但是 FISCO BCOS 奋起直追,已经初见规模,Coco、Quorum、Corda 还需要做很大努力。

#三、效率

区块链目前最差强人意的指标莫过于效率,虽然现在也有些人开始反思也许不应当苛求区块链的效率,但是商业应用总是回避不了这个问题。效率方面,本文从共识协议、出块速度、TPS 和存储消耗这四点加以比对。

##(一)共识协议

联盟链为了提升交易速度,往往是先从共识协议“下手”。POW 和 POS 都无法满足商业应用的需要,“挖矿”对联盟链来讲也是没必要的,因此,各家都采用了替代的共识方案。

Hyperledger Fabric 在 0.6 版中应用了 PBFT,而在 1.0 版中放弃了 PBFT,转而采用效率更高的 Kafka,支持单点和集群两种方式,由 Kafka 直接给交易排序和出块。

FISCO BCOS 支持并行计算的 PBFT 和标准 RAFT 两种方式,前者是将通常的 PBFT 中议长节点和投票节点分步验证的方式优化为并发验证,从而进一步提高共识效率;

Coco 支持 Paxos 和 Caesar 两种协议。由于 Coco 节点是建立在基于硬件的 TEEs(可信执行环境)上,因此就假定了节点充分可信,所以在 Paxos 中,leader 节点处理过的事务,follwer 节点简单跟随即可,这体现了其对公链假定的改变;Caesar 支持灵活的容错模型,可以与 Paxos 共同使用以防范 leader 节点由于 TEEs 遭到破坏产生的安全威胁,该协议支持在 follwer 节点发现 leader 节点不可靠时将其驱逐,从而保证全网的安全;

Quorum 支持 Raft 和 Istanbul BFT 两种协议。后者是由来自台湾的 AMIS 帐联网公司在 2017 年研发的,可以大幅提升现有的以太坊架构的讯息交换效率;

Corda 比较特殊,它借鉴“矿工”角色设计了公证人模块来提供交易公证(也即签名)服务,整个网络不依赖于任何特定的共识算法。但公证人是一个集群概念,一般使用 BFT 或 Raft 在公证人间达成一致,因此,公证人是存在效率问题,可能成为效率瓶颈;

与传统分布式系统的共识设计相比,Hyperledger Fabric 并没有什么改进,其共识方式与中心化共识的分布式数据库一致;FISCO BCOS 支持 PBFT 共识算法,具备拜占庭容错功能,也提供 RAFT 共识算法,适用于在节点可信度比较乐观的场景;Coco 是通过 TEEs 提高节点可信性,以降低共识协议的复杂度;Quorum 也没做多少调整,尤其是在引入 Istanbul BFT 之前;Corda 应该说是在传统设计中引入了“矿工”理念。

##(二)出块速度

由于替换了共识机制,因此相比使用 POW 的比特币、以太坊,联盟链出块速度要提高很多。Hyperledger Fabric、FISCO BCOS、Coco 都是秒级出块;Quorum 则称是毫秒级,默认设定是 50 毫秒,可以调整;Corda 没有块,所以也没有出块速度可以考量。

##(三)TPS

TPS 相当于区块链世界中的“网红”,很多新出现的链都把 TPS 贴在“脑门”上。这五大联盟链虽然 TPS 远高于比特币、以太坊,但还是比现有的分布式系统逊色:

Hyperledger Fabric 通常实测的 TPS 在 300-500 之间;

FISCO BCOS 实测单链可以达到 1000 以上。并且支持多链架构下的并行计算,可灵活扩展,理论上无上限。

Coco 官方数据是 1600;

Quorum 在 Istanbul BFT 协议下可以达到 400-800,Raft 下缺少数据;

Corda 由于其网络结构的原因,没有全局吞吐量可以衡量。

其实 TPS 方面如果没有达到一个数量级以上的差异,是不用特殊关注的,因为在实际应用中,节点数量、网络环境、硬件配置、软件设计等都会对 TPS 产生影响,而现有的联盟链在吞吐量上已经可以满足相当一部分商业场景的要求,毕竟 Visa 在 2016 年每秒实际处理的交易也只有 1,667 笔,尽管 Visanet 据称有每秒处理 56,000 笔交易的能力。

##(四)存储消耗

区块链可以说是以“浪费”存储来换取信任的技术。虽然存储设备的价格越来越低廉,但这不代表“浪费”就没毛病,存储的快速膨胀一定会带来效率、成本、可用性等诸多问题,甚至会要求改变设计架构,尤其是在大家都想追求“杀手级应用”的时候。

Hyperledger Fabric 方面,蚂蚁金服倒是给出了一个详细的计算公式,Fabric 数据容量估算(GB) = 每种业务每天平均交易笔数 x (Fabric 每笔交易基本开销 + 每笔交易平均业务数据大小 KB x 2 ) x 业务 Channel 数量 x(365 x 年数 x(Peer 节点数量 x 2~1 之间 + Orderer 节点数量)+ Kafka RetenTIon 天数 x Kafka Replica 数量) / (1024 x 1024),其计算示例中,在业务笔数每天 10 万、4 节点、2 通道、单笔交易容量 1K 的情况(其他因素不详细列出了)下,年存储消耗 4619G;

FISCO BCOS 支持历史数据快速追踪,对接数据库,实现分布式存储,能够支持海量服务的存储需求,提高存储访问速率,节省存储消耗。

Coco 由于设计上需要集成区块链协议做底层,因此其消耗就取决于集成的区块链协议,比如集成了 Hyperledger Fabric,那加上 Coco 自身的消耗,其存储消耗量至少应该是比肩 Fabric 的;

Quorum 也没有针对存储的特殊优化,至少应当按照大于以太坊消耗来估算;

Corda 倒是不同于其他联盟链,因为它基本上就是传统的分布式数据库,而且没有任何节点保存全局数据,每个节点都只保存跟自己有关的数据,所以,其存储消耗应该与传统分布式系统设计类似,没有过多的冗余消耗。

综上,从效率方面看,在 Hyperledger Fabric 之后推出或开源的其他联盟链,效率高于它也属正常。FISCO BCOS、Quorum 本就是面向金融的设计,所以效率要求自然要高于一开始就希望做通用框架 Hyperledger Fabric;Coco 设计理念上就是希望做成“加速器”的,它的效率理应高于任何它可以集成的区块链;而 Corda 的设计模式决定了很难全面评价其效率,只能去单独观察每个实例。

#四、扩展性

联盟链的用户都希望自己能发展成生态圈,比如海尔的供应链、中化的原油进出口贸易平台、马士基的全球交易平台等,因此,扩展性是联盟链设计必须要考虑的问题。这方面本文关注了节点数量扩展、共识扩展、单多链模式、加密算法扩展、第三方认证证书支持这五点。

##(一)节点数量扩展

Hyperledger Fabric 在节点数量扩展方面是弱项,已落地项目多是个位数节点,但是可以支持较多的客户端,算是一种弥补,不过节点数少其实意味着参与方的独立性是会有所下降的;

FISCO BCOS 的分组模式支持根据节点数量进行水平扩容,因此理论上节点数量是不受限制的;

Coco 在这方面有些“投机取巧”,可支持的节点数量取决于其集成的区块链协议,如果集成的是公链协议,在理论上也不受限制;

Quorum 是基于以太坊的,因此理论上也没有限制;

Corda 同样也没有节点数限制。

虽然除了 Hyperledger Fabric,其他联盟链似乎都没有节点数量问题,但是节点数量其实还受共识协议的影响,BFT 类共识协议在节点数量超过一定水平时会出现吞吐量下降,设计时应当考虑这点。

##(二)共识协议扩展

共识协议的扩展能力对联盟链的稳定性有很大影响,能否根据节点数量、网络平衡情况、吞吐量进行调整决定了其网络的扩展能力。

Hyperledger Fabric 虽然很早在设计上就称其共识模块可插拔,但是目前实际应用上看是不具备插拔能力的,每个版本仅支持一种共识模式;

FISCO BCOS 支持共识协议的插件式实现,允许切换共识机制;

Coco、Quorum 目前也具备了这种能力;

Corda 实现的应该说不是共识协议的直接插拔,而是公证人模块的可插拔,可以通过切换公证人模块来选择公证人的共识模式。

##(三)单多链模式

多链模式目前被很多新出现的链用于性能扩展,不过多链模式有利有弊,提升性能的同时也增加了设计复杂度。

Hyperledger Fabric 的通道机制其实可以算是早期的多链设计,但是通道在 Hyperledger Fabric 中并不是出于提升效率的目的设计的,而是为了满足业务多样性要求,以降低业务复杂度,因此,通道机制目前在性能扩展方面没有显著贡献;

FISCO BCOS 是明确的并行计算多链设计,设计上要求开发者尽可能保持多链的同构特征以减少冲突,多链设计被直接应用在系统扩展方面;

Coco 的模式仍然取决于其集成的区块链协议;

Quorum 是单链模式的,底层的性能扩展要跟随以太坊的技术路线,可能要依赖以太坊的分片等技术进行扩展;

Corda 设计上是多网络模式,没有单多链的概念,但是可以建立两个网络节点的双向连接,配置双方信任的公正和认证机构进行网络融合,融合算是其扩展的一种方式。

##(四)加密算法扩展

对于国内的应用,加密算法的扩展也即国密替换是一个强烈需求,尤其是在金融领域。

Hyperledger Fabric 不支持国密替换,目前已有的应用凡实现国密的基本上是自行替换或者依赖第三方服务;

FISCO BCOS 是支持国密的;

Coco 未对加密算法的选择有明确说明,因为这对 Coco 而言属于底层,取决于其集成区块链协议,但目前它所集成的协议中还没有支持国密的;

Quorum、Corda 都没有对国密的支持方案。

##(五)第三方认证证书支持

这一点对国内的应用也很重要。

Hyperledger Fabric 目前不支持第三方 CA;

FISCO BCOS 支持第三方证书,支持证书的撤销,支持多CA;

Coco 由于私钥都保管在本地业务系统且允许自己生成,网络上只存公钥集,因此技术上看应该可以支持第三方 CA;

Quorum、Corda 都未见有此类支持。

综上,Hyperledger Fabric 在扩展性上有一定的限制; FISCO BCOS 的可扩展性是很有优势的,尤其是面向国内应用时;Coco 扩展性取决于其集成的协议;Quorum 的扩展性与以太坊关系密切;Corda 除了在加密算法和第三方认证证书方面外,扩展的自由度有可能是最高的。

#五、节点管理与权限管理

除了共识之外,联盟链与公链的显著区别当属在节点和权限上的设计了。本文从节点类型、作用、成员准入控制、角色和权限管理这几个方面比较下各联盟链之间的差异。

##(一)节点类型

Hyperledger Fabric 网络中的节点主要分为排序节点、背书节点和记账节点三类,实际应用中还可以加入只有同步账本能力的二级节点;

FISCO BCOS 中包含核心节点、全节点、轻节点;

Coco 是一个可信验证节点(VN)分布式网络,也即,它只有一类节点就是 VN;

Quorum 中的节点是基于的以太坊 Golang 版本实现的,因此节点之间是对等的,没有节点类型的区分,节点之间可以有白名单管理;

Corda 也不区分节点类型。

##(二)节点作用

Hyperledger Fabric 网络中背书节点负责提供签名服务,经背书节点签名且满足签名策略的交易提案会提交给排序节点进行交易排序和出块,再由记账节点完成账本更新;

FISCO BCOS 中核心节点负责共识和记账,共识节点参与记账共识, 观察节点同步账本;

Coco、Quorum、Corda 中节点都是对等的。

##(三)准入控制

Hyperledger Fabric 中有专门的 CA 模块提供用户信息注册、数字证书发行、延期和吊销等服务,成员管理采用 MSP 方式,同一个组织内的成员通过共用同一个 MSP 标识进行识别;

FISCO BCOS 中,成员加入网络采用管理员认证的方式,提供合法有效的成员信息与CA证书,由管理员审核通过后,加入网络;

Coco 网络中的角色分为成员和参与者两种,成员是网络的集体管理者,拥有投票权,投票决定其他机构的加入或删除;

Quorum 网络中节点通过授权才能加入网络,授权是集中式的,通过 Java 控制台操作;

Corda 中节点也是需要授权加入的,节点选择加入一个或多个网络地图,网络地图相当于网络成员及其地址列表,节点只能与所在地图中的成员进行交易。

##(四)角色

Hyperledger Fabric 中虽然成员没有明确的角色划分,但是基于其运维或对应的节点的差异会自然形成不同的角色;

FISCO BCOS 网络中的角色包含超级管理员、链或权限管理员、运维、交易、监管等;

Coco 网络中的角色分为成员和参与者两种,但不是必须同时具有两类参加者,也可以只有成员类型;

Quorum 网络中没有角色的区分;

Corda 网络中的角色分为公证人和参与者两种,公证人提供公证服务,参与者进行交易。

##(五)权限管理

Hyperledger Fabric 中权限主要通过策略进行管理,策略实际上是成员通过节点进行某种操作,比如提交交易提案等,所需要满足的签名数量要求。

FISCO BCOS 权限管理采用系统合约的方式,并可以通过自定义合约的方式进行权限管理功能的扩展,权限管理模型为 ARPI(账户——角色——权限——接口)模式,多个账户可以对应同一个角色,角色有明确的权限列表,每个权限对应一个接口,接口指向智能合约,权限列表按照系统合约方式维护。业务中的权限管理则采用交易权限链的方式,一个交易相当于一组权限链,包含多个 Filter,交易处理是逐个 Filter 进行权限判断,一个交易完成相当于一组 Filter 审核都通过。

Coco 网络有成员负责治理,参与者是没有投票权的,不能参加网络管理。成员和参与者都可以拥有 VN。成员对网络的管理通过共同维护一个可编程的网络章程来进行,章程内容至少包括成员列表、VN 列表、代码清单、TEE 清单和投票策略。

Quorum、Corda 没有明显的权限管理内容。

综合比较,FISCO BCOS 的设计比较周全,也有一定的复杂性,但这也意味着它能够支持更复杂的场景; Hyperledger Fabric 、Coco 带有一定中心化因素;相较之下,Quorum、Corda 更接近公链思路。带有中心化因素本就是联盟链对其应用的商业环境的体现,这也无可厚非。

#六、智能合约

为了提升效率,支持更加友好的设计,各联盟链在智能合约上也出现了不同的发展思路。

Hyperledger Fabric 中的智能合约称为“链码”。链码分为系统链码和普通链码,前者包括生命周期管理、配置管理等,属于系统控制层面的链码;普通链码则是用于实现业务逻辑的链码,智能合约开发通常指的就是这部分链码。链码的业务模型为“MCV-B”,即,在传统的 MVC(模型、控制器、视图)模式中嵌入 B(区块链),强调链码是业务逻辑的加强。链码的生命周期包括打包、安装、实例化、升级、停止和启动,运行在 Docker 中,由背书节点进行调用,目前主要支持的是 Go 语言。Hyperledger Fabric 虽然提供了跨通道机制,允许跨通道调用链码,但是跨通道调用只支持读而不支持写。

FISCO BCOS 中除了通常用于业务逻辑的智能合约外,将系统管理也智能合约化了,统称为系统合约,包含系统代理、节点管理、机构证书、权限管理、全网配置五类。上述合约原则上由区块链管理员在网络启动时部署,网络运行期间的变更则需要在去全网所有节点许可的情况下由管理员操作。FISCO BCOS 主要支持 EVM 引擎的智能合约。

Coco 由于其节点运行在可信执行环境中,因此,与其他联盟链不同的是智能合约只需单个节点运行,不必多次验证。更与众不同的是,因为可以单点只运行一次,所以 Coco 的智能合约支持不确定交易。此外,允许智能合约直接连接外部可信数据源。

Quorum 是基于以太坊智能合约的,智能合约本身没有特别之处,合约运行结果方面,节点只对公开交易和节点涉及的私有交易进行验证,而不必验证所有交易。

Corda 的智能合约设计思路也比较独特,首先,它主张智能合约的业务数据和业务逻辑要能关联到明确的法律依据上,这相当于要智能合约跟业务凭证之间具有强联系;其次,Corda 主张纯函数式设计,力推金融合约的标准化,提供小型类库,以减少对低层次逻辑的重新开发;再次,单纯看智能合约的话,Corda 的智能合约是“碎片化”的小段程序,而且只能做为起流转控制作用的“验证程序”,做不到一般智能合约那种价值转移功能,在 Corda 中,“交易”、“智能合约”和“流式架构”加起来才能与其他平台的智能合约相当。

总结一下,Hyperledger Fabric 的链码设计给了智能合约一个新的设计框架,这方面它是开创性的;FISCO BCOS 则将智能合约应用扩展到了系统管理方面;Coco 采取了改变公链设计假定的思路,不仅不对智能合约进行重复验证,还支持不确定交易;Quorum 的智能合约基本沿袭公链思路;Corda 的思路也比较另类,但是智能合约本身却更弱化了。

智能合约是随着以太坊火起来的,成了区块链的标志性技术,但其实目前的智能合约还远不够“智能”,这个名字容易引起误解。以太坊创始人 Vitalik 最近在推特上发文称对使用智能合约这个术语表示“十分遗憾”,应该使用更专业或更无聊的名字,比如,“持续的脚本”之类的东西,想来也有此意。

#七、部署与运维友好性

联盟链常被称为是个“坑”,这个“坑”主要是在部署和运维方面。

##(一)部署

Hyperledger Fabric 虽然已经是个成熟框架了,有良好的社区环境,市面上还有若干不错的教材,但是部署方面依然让很多新人不知就里,笔者所在的微信群里大部分时间都在交流部署问题而非设计问题;

FISCO BCOS提供一键安装/step-by-step/docker等搭链方式,同时还未企业生产部署提供物料包的打包工具,简化部署复杂度;

Coco 的部署特点是增加了一次对其他区块链协议的集成,要先有底层区块链协议,才能部署 Coco,这其实要设计人员对 Coco 和其集成的区块链协议都有一定了解才好,学习成本较大,此外,Coco 需要部署 TEE 硬件设备来支持可信执行环境构建,这是其他联盟链通常不需要的,TEE 因此也成为一个安全隐患;

Quorum 需要在以太坊之上部署,依赖以太坊,与 Coco 相同,设计人员最好也要了解以太坊;

Corda 的部署目前缺乏实例来做比较。

##(二)运维

Fabric 目前没有提供多少支持工具,多数需要设计者自己开发;

FISCO BCOS 提供了方便运维的合约命名服务,提供区块链浏览器和监控,并且有上帝模式用于处理节点崩溃问题,运维友好度有一定改善;

Coco 目前未见提供多少运维工具;

Quorum 有一些第三方支持工具;

Corda 与其他联盟链相比,运维方面最大的特色莫过于支持受限形式的数据库回滚。

联盟链的部署和运维都有一定的学习曲线,其复杂度远高于公链,一个新手部署一条以太坊要不了多少时间,但是运转起一个联盟链,还是需要打听不少“小伙伴”的。

#八、隐私保护

联盟链有一个让大家纠结的问题是,明明要上链一起共建生态、共享信息,却纷纷要求隐私保护,要上链又不能随意公开,不仅希望身份保密,还希望交易信息保密,这与公链信息公开、身份保密的设计理念有很大不同,但这是合理要求,尤其是在金融领域。本文从可见范围、加密措施两方面对各链加以比较。

##(一)可见范围

Hyperledger Fabric 的通道可以用来隔离数据,只有在同一通道内的节点才可以共享同一套账本信息,而通过组织设计,基于 MSP 标识可以在同一通道内进一步控制数据可见范围,1.2 版中加入了私有数据模式,允许指定的节点间共享信息,这比组织更加灵活;

FISCO BCOS 设计了 AMOP 协议,以提供机构间的点对点通信,通信信息属于链下信息,不在全网共享,链上部分在引入中央对手方提供信用背书的情况下,数据也仅在交易方和中央对手方之间共享,多链方式也可用于数据隔离,必要时通过跨连互通;

Coco 支持两个或多个交易者的机密交易,通过 TEE 控制可见性,但要求集成的区块链协议最好也提供一定支持;

Quorum 区分公开数据和私有数据,私有数据只允许限定的交易方可见;

Corda 数据仅在交易方之间可见,节点之间提供一个交易依赖关系图,数据根据需要发送,而不在全局广播,任何参与方都无法见到包含全部数据的全局账本。

##(二)加密措施

Hyperledger Fabric 1.1 开始支持账本数据加密,1.2 版引入私有数据后,设计上允许只给 Kafka 提供交易 Hash 用于排序而不向 Kafka 提供交易信息,以防排序节点泄露数据;

FISCO BCOS 允许采用高强度的加密数据信封进行保护,未参与交易的机构只能接收到密文,此外,建议对敏感数据采用脱敏上链、Hash 上链等方式进行保密处理;支持零知识证明,环签名,群签名,同态加密等隐私保护方法。

Coco 允许应用程序先进行数据加密再提交事务,公网数据采用加密传播的方式,以对不受信任的 host 保密;

Quorum 有独立的 ConstellaTIon 模块,对私有事务的交易数据进行加密保护,还提供了独立的零知识证明(ZSL)模块以防止验证用户身份时发生信息泄露;

Corda 也使用 enclave 进行数据保护,并考虑使用安全硬件。

在隐私保护上,各链都下了很大力气,这方面与其一较短长,不如考虑互相借鉴。

#九、选型建议

通过以上八个方面,本文粗略比较了五大联盟链的设计与差异,如果非要从技术角度给各家打个分、排个名,实在有些“霸王硬上弓”之嫌,各家原本思路和焦点就不同,都有自己的“小目标”,非要不管人家自己的想法去论个短长,有些不太“科学”,也不是应用的合理“姿势”。各联盟链毕竟都是为了解决实际问题、为了落地区块链项目而设计的,所以,本文最后从大家都会关心的技术选型角度做个总结。

整体而言,Hyperledger Fabric 的综合实力依然最强,推出时间早、框架完整且比较成熟,有国际化应用和国际化社区加持,案例和技术支持对于仍属早期发展阶段的区块链而言非常重要,Hyperledger Fabric 在这方面可以说优势极大。但是,它也有些不能回避的问题,比如基础研发进展缓慢,研发主体不明确,一些应用者关心的关键问题迟迟不见解决。随着百度、阿里、腾讯、京东等一众国内大厂的强势加入,Hyperledger Fabric 的优势地位也会受到越来越多的挑战,对此,它急需合适的应对措施。

FISCO BCOS 应该说是本土化设计的代表,其在底层研究上的投入、关键技术上的改进、对国内需要的适应性调整、对社区建设和运维的重视,都有可圈点之处,平台在各行业的通用性也在加强,随着开源工作的推进和案例的不断增加,其本土化优势会逐步显现。在国家政策的鼓励下,国内大厂如今纷纷高调杀入联盟链市场,如果这些大厂真的“倾情”加入,那与 Hyperledger Fabric 相较,其开发主体、资金投入的稳定性要更有优势,而且,大厂们基本自带生态和流量,案例的增长、生态的发展也是可以预期的,是很多项目可以借力之处。

Coco、Quorum、Corda 都存在支持能力不足、缺乏有效案例的问题,虽然微软目前在 Coco 以及其他基于 Azure 的区块链平台和应用上投入了一定力量,但是对国内应用者而言,仍显不足。

因此,从技术选型角度来讲,应用者,尤其是新入局的应用者,最好还是在 Hyperledger Fabric 这种影响广泛的成熟框架或者 FISCO BCOS 这种有实力且能提供较强本土支持的平台上做选择,而在开发过程中借鉴下 Coco、Quorum、Corda 中的优秀设计理念。