数据库索引总结

一,索引的种类

一,从数据结构角度

  1. B+树索引(O(log(n))):n是记录总树,底数是树的分叉数,结果就是树的层次数,关于B+树索引,可以参考MySQL索引背后的数据结构及算法原理

    • B+树是一颗平衡树,如果我们对这颗树增删改的话,那肯定会破坏它的原有结构
    • 要维持平衡树,就必须做额外的工作。正因为这些额外的工作开销,导致索引会降低增删改的速度
  2. hash索引:哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需一次哈希算法即可立刻定位到相应的位置,速度非常快

    hash索引的缺点:

    • 哈希索引也没办法利用索引完成排序

    • 不支持最左匹配原则

    • 在有大量重复键值情况下,哈希索引的效率也是极低的—->哈希碰撞问题。

    • 不支持范围查询,仅仅能满足”=”,”IN”和”<=>”查询,不能使用范围查询

    • 其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引

    • 只有Memory存储引擎显示支持hash索引

  3. FULLTEXT索引(现在MyISAM和InnoDB引擎都支持了)

  4. R-Tree索引(用于对GIS数据类型创建SPATIAL索引)

二,从物理存储角度

  1. 聚集索引(clustered index)就是以主键创建的索引
  2. 非聚集索引(non-clustered index)就是以非主键创建的索引
    • 区别:
      • 聚集索引在叶子节点存储的是表中的数据
      • 非聚集索引在叶子节点存储的是主键和索引列
      • 使用非聚集索引查询出数据时,拿到叶子上的主键再去查到想要查找的数据。(拿到主键再查找这个过程叫做回表)

三,从逻辑角度

  1. 主键索引:主键索引是一种特殊的唯一索引,不允许有空值

  2. 普通索引或者单列索引

  3. 多列索引(复合索引):复合索引指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用复合索引时遵循最左前缀集合;

    • 我们前面知道了,如果不是聚集索引,叶子节点存储的是主键+列值
    • 最终还是要“回表”,也就是要通过主键查找一次。这样就会比较慢
    • 覆盖索引就是把要查询出的列和索引是对应的,不做回表操作!
    • 比如说:
      • 现在我创建了索引(username,age),在查询数据的时候:select username , age from user where username = 'Java3y' and age = 20
      • 很明显地知道,我们上边的查询是走索引的,并且,要查询出的列在叶子节点都存在!所以,就不用回表了~
      • 所以,能使用覆盖索引就尽量使用吧~
  4. 唯一索引或者非唯一索引

  5. 空间索引:空间索引是对空间数据类型的字段建立的索引,MYSQL中的空间数据类型有4种,分别是GEOMETRY、POINT、LINESTRING、POLYGON。
    MYSQL使用SPATIAL关键字进行扩展,使得能够用于创建正规索引类型的语法创建空间索引。创建空间索引的列,必须将其声明为NOT NULL,空间索引只能在存储引擎为MYISAM的表中创建

索引最左匹配原则:

  • 索引可以简单如一个列(a),也可以复杂如多个列(a, b, c, d),即联合索引

  • 如果是联合索引,那么key也由多个列组成,同时,索引只能用于查找key是否存在(相等),遇到范围查询(>、<、between、like左匹配)等就不能进一步匹配了,后续退化为线性查找。

  • 因此,列的排列顺序决定了可命中索引的列数

    例子:

  • 如有索引(a, b, c, d),查询条件a = 1 and b = 2 and c > 3 and d = 4,则会在每个节点依次命中a、b、c,无法命中d。(很简单:索引命中只能是相等的情况,不能是范围匹配)

索引总结

索引在数据库中是一个非常重要的知识点!上面谈的其实就是索引最基本的东西,要创建出好的索引要顾及到很多的方面:

  • 1,最左前缀匹配原则。这是非常重要、非常重要、非常重要(重要的事情说三遍)的原则,MySQL会一直向右匹配直到遇到范围查询(>,<,BETWEEN,LIKE)就停止匹配。
  • 3,尽量选择区分度高的列作为索引,区分度的公式是 COUNT(DISTINCT col) / COUNT(*)。表示字段不重复的比率,比率越大我们扫描的记录数就越少。
  • 4,索引列不能参与计算,尽量保持列“干净”。比如,FROM_UNIXTIME(create_time) = '2016-06-06' 就不能使用索引,原因很简单,B+树中存储的都是数据表中的字段值,但是进行检索时,需要把所有元素都应用函数才能比较,显然这样的代价太大。所以语句要写成 : create_time = UNIX_TIMESTAMP('2016-06-06')
  • 5,尽可能的扩展索引,不要新建立索引。比如表中已经有了a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。
  • 6,单个多列组合索引和多个单列索引的检索查询效果不同,因为在执行SQL时,MySQL只能使用一个索引,会从多个单列索引中选择一个限制最为严格的索引。

参考文档:

数据库两大神器【索引和锁】

MySQL的索引

深入浅出的理解数据库索引

阿里巴巴Java开发手册

二,数据库引擎

一,Innodb

InnoDB是事务型数据库首选引擎,支持事务安全表(ACID),支持行锁定和外键,InnoDB是默认的MySQL引擎。InnoDB主要特性有:

  1. InnoDB给MySQL提供了具有提交、回滚和崩溃恢复能力的事物安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句中提供一个类似Oracle的非锁定读。这些功能增加了多用户部署和性能。在SQL查询中,可以自由地将InnoDB类型的表和其他MySQL的表类型混合起来,甚至在同一个查询中也可以混合
  2. InnoDB是为处理巨大数据量的最大性能设计。它的CPU效率可能是任何其他基于磁盘的关系型数据库引擎锁不能匹敌的
  3. InnoDB支持外键完整性约束,存储表中的数据时,每张表的存储都按主键顺序存放,如果没有显示在表定义时指定主键,InnoDB会为每一行生成一个6字节的ROWID,并以此作为主键
  4. InnoDB被用在众多需要高性能的大型数据库站点上

二,MyIASM

MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事物。MyISAM主要特性有:

  1. 大文件(达到63位文件长度)在支持大文件的文件系统和操作系统上被支持

  2. 当把删除和更新及插入操作混合使用的时候,动态尺寸的行产生更少碎片。这要通过合并相邻被删除的块,以及若下一个块被删除,就扩展到下一块自动完成

  3. 每个MyISAM表最大索引数是64,这可以通过重新编译来改变。每个索引最大的列数是16

  4. 最大的键长度是1000字节,这也可以通过编译来改变,对于键长度超过250字节的情况,一个超过1024字节的键将被用上

  5. BLOB和TEXT列可以被索引

  6. NULL被允许在索引的列中,这个值占每个键的0~1个字节

  7. 所有数字键值以高字节优先被存储以允许一个更高的索引压缩

  8. 每个MyISAM类型的表都有一个AUTO_INCREMENT的内部列,当INSERT和UPDATE操作的时候该列被更新,同时AUTO_INCREMENT列将被刷新。所以说,MyISAM类型表的AUTO_INCREMENT列更新比InnoDB类型的AUTO_INCREMENT更快

  9. 可以把数据文件和索引文件放在不同目录

  10. 每个字符列可以有不同的字符集

  11. 有VARCHAR的表可以固定或动态记录长度

  12. VARCHAR和CHAR列可以多达64KB

使用MyISAM引擎创建数据库,将产生3个文件。文件的名字以表名字开始,扩展名之处文件类型:frm文件存储表定义、数据文件的扩展名为.MYD(MYData)、索引文件的扩展名时.MYI(MYIndex)

三,MEMORY

  1. MEMORY表的每个表可以有多达32个索引,每个索引16列,以及500字节的最大键长度

  2. MEMORY存储引擎执行HASH和BTREE缩影

  3. 可以在一个MEMORY表中有非唯一键值

  4. MEMORY表使用一个固定的记录长度格式

  5. MEMORY不支持BLOB或TEXT列

  6. MEMORY支持AUTO_INCREMENT列和对可包含NULL值的列的索引

  7. MEMORY表在所由客户端之间共享(就像其他任何非TEMPORARY表)

  8. MEMORY表内存被存储在内存中,内存是MEMORY表和服务器在查询处理时的空闲中,创建的内部表共享

  9. 当不再需要MEMORY表的内容时,要释放被MEMORY表使用的内存,应该执行DELETE FROM或TRUNCATE TABLE,或者删除整个表(使用DROP TABLE)

四,Achive

功能 MYISAM Memory InnoDB Achive
存储限制 256TB RAM 64TB None
支持事务 no no yes no
支持全文索引 yes no no no
支持数索引 yes yes yes no
支持哈希索引 no yes no no
支持数据缓存 no N/A yes no
支持外键 no no yes no

三,数据库事务

四,数据库锁

SQL优化

SQL优化方案

一,SQL语句性能优化

  1. 对查询进行优化,应尽量避免全表扫描,首先应考虑在where及order by 涉及的列上建立索引

  2. 应尽量避免在 where 子句中对字段进行 null 值判断,创建表时NULL是默认值,但大多数时候应该使用NOT NULL,或者使用一个特殊的值,如0,-1作为默 认值。

    1
    select id from t where num is null;

    可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询:

    1
    select id from t where num=0;
  3. 应尽量避免在 where 子句中使用!=或<>操作符, MySQL只有对以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE。

  4. 应尽量避免在 where 子句中使用 or 来连接条件, 否则将导致引擎放弃使用索引而进行全表扫描, 可以 使用UNION合并查询:

    1
    select id from t where num=10 or num=20;

    可以这样查询:

    1
    select id from t where num=10 union all select id from t where num=20
  5. in 和 not in 也要慎用,否则会导致全表扫描,如:

    1
    select id from t where num in(1,2,3);

    对于连续的数值,能用 between 就不要用 in 了:

    1
    select id from t where num between 1 and 3;
  6. 下面的查询也将导致全表扫描:

    1
    select id from t where name like '%c%';

    若要提高效率,可以考虑全文检索。

  7. 如果在 where 子句中使用参数,也会导致全表扫描。因为 SQL 只有在运行时才会解析局部变量,但优 化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计 划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:

    1
    select id from t where num=@num;

    可以改为强制查询使用索引:

    1
    select id from t with(index(索引名)) where num=@num;
  8. 应尽量避免在 where 子句中对字段进行表达式操作, 这将导致引擎放弃使用索引而进行全表扫描。

    1
    select id from t where num/2=100;

    可以这样查询:

    1
    select id from t where num=100*2;
  9. 应尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:

    1
    select id from t where substring(name,1,3)='abc';#name 以 abc 开头的 id

    应改为:

    1
    select id from t where name like 'abc%';
  10. 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用 索引。

  11. 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件 时才能保证系统使用该索引, 否则该索引将不会 被使用, 并且应尽可能的让字段顺序与索引顺序相一致。

  12. 不要写一些没有意义的查询,如需要生成一个空表结构:

    1
    select col1,col2 into #t from t where 1=0;

    这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:

    1
    create table #t(…);
  13. 很多时候用 exists 代替 in 是一个好的选择:

    1
    select num from a where num in(select num from b);

    用下面的语句替换:

    1
    select num from a where exists(select 1 from b where num=a.num);
  14. 并不是所有索引对查询都有效,SQL 是根据表中数据来进行查询优化的,当索引列有大量数据重复时, SQL 查询可能不会去利用索引,如一表中有字段 sex,male、female 几乎各一半,那么即使在 sex 上建 了索引也对查询效率起不了作用。

  15. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过 6 个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

  16. 应尽可能的避免更新 clustered 索引数据列, 因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。

  17. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言 只需要比较一次就够了。

  18. 尽可能的使用 varchar/nvarchar 代替 char/nchar , 因为首先变长字段存储空间小, 可以节省存储空间, 其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

  19. 任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。

  20. 尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。

  21. 避免频繁创建和删除临时表,以减少系统表资源的消耗。

  22. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用 表中的某个数据集时。但是,对于一次性事件, 最好使用导出表。

  23. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先 create table,然后 insert。

  24. 如果使用到了临时表, 在存储过程的最后务必将所有的临时表显式删除, 先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。

  25. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过 1 万行,那么就应该考虑改写。

  26. 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更 有效。

  27. 与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

  28. 在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF .无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。

  29. 尽量避免大事务操作,提高系统并发能力。 sql 优化方法使用索引来更快地遍历表。 缺省情况下建立的索引是非群集索引,但有时它并不是最佳的。在非群集索引下,数据在物理上随机存放在数据页上。合理的索引设计要建立在对各种查询的分析和预测上。一般来说:

    • 有大量重复值、且经常有范围查询( > ,< ,> =,< =)和 order by、group by 发生的列,可考虑建立集群索引;
    • 经常同时存取多列,且每列都含有重复值可考虑建立组合索引;
    • 组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列。索引虽有助于提高性能但 不是索引越多越好,恰好相反过多的索引会导致系统低效。用户在表中每加进一个索引,维护索引集合就 要做相应的更新工作。
  30. 定期分析表和检查表

    1
    2
    分析表的语法:ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tb1_name[, tbl_name]...
    复制代码

    以上语句用于分析和存储表的关键字分布,分析的结果将可以使得系统得到准确的统计信息,使得SQL能够生成正确的执行计划。如果用户感觉实际执行计划并不是预期的执行计划,执行一次分析表可能会解决问题。在分析期间,使用一个读取锁定对表进行锁定。这对于MyISAM,DBD和InnoDB表有作用。

    1
    2
    3
    例如分析一个数据表:analyze table table_name

    检查表的语法:CHECK TABLE tb1_name[,tbl_name]...[option]...option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}

    检查表的作用是检查一个或多个表是否有错误,CHECK TABLE 对MyISAM 和 InnoDB表有作用,对于MyISAM表,关键字统计数据被更新

  31. 定期优化表。

    1
    优化表的语法:OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tb1_name [,tbl_name]...

    如果删除了表的一大部分,或者如果已经对含有可变长度行的表(含有 VARCHAR、BLOB或TEXT列的表)进行更多更改,则应使用OPTIMIZE TABLE命令来进行表优化。这个命令可以将表中的空间碎片进行合并,并且可以消除由于删除或者更新造成的空间浪费,但OPTIMIZE TABLE 命令只对MyISAM、 BDB 和InnoDB表起作用。

    1
    例如: optimize table table_name

    注意: analyze、check、optimize执行期间将对表进行锁定,因此一定注意要在MySQL数据库不繁忙的时候执行相关的操作。

二,其他优化

  1. 在海量查询时尽量少用格式转换。

  2. ORDER BY 和 GROPU BY:使用 ORDER BY 和 GROUP BY 短语,任何一种索引都有助于 SELECT 的性能提高。

  3. 任何对列的操作都将导致表扫描,它包括数据库教程函数、计算表达式等等,查询时要尽可能将操作移 至等号右边。

  4. IN、OR 子句常会使用工作表,使索引失效。如果不产生大量重复值,可以考虑把子句拆开。拆开的子 句中应该包含索引。

  5. 只要能满足你的需求,应尽可能使用更小的数据类型:例如使用 MEDIUMINT 代替 INT

  6. 尽量把所有的列设置为 NOT NULL,如果你要保存 NULL,手动去设置它,而不是把它设为默认值。

  7. 尽量少用TEXT、BLOB 类型

  8. 如果你的数据只有你所知的少量的几个。最好使用 ENUM 类型

  9. 正如 graymice 所讲的那样,建立索引。

  10. 合理用运分表与分区表提高数据存放和提取速度。

转自链接https://juejin.im/post/5aa7703c6fb9a028c8128739

转自来源:掘金

k8s二进制部署(HTTPS+RBAC)

k8s二进制部署(HTTPS+RBAC)

官方提供的几种Kubernetes部署方式

  • minikube

    ​ Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用。不能用于生产环境。

    官方地址:https://kubernetes.io/docs/setup/minikube/

  • kubeadm

    ​ Kubeadm也是一个工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。

    官方地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/

  • 二进制包

    ​ 从官方下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。
    小结:

    ​ 生产环境中部署Kubernetes集群,只有Kubeadm和二进制包可选,Kubeadm降低部署门槛,但屏蔽了很多细节,遇到问题很难排查。我们这里使用二进制包部署Kubernetes集群,我也是推荐大家使用这种方式,虽然手动部署麻烦点,但学习很多工作原理,更有利于后期维护。

参考地址:李振良博客

JAVA集合总结

JAVA集合总结

HashMap的实现原理

  • 概述

    HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

分布式事务探索

前言

不知道你是否遇到过这样的情况,去小卖铺买东西,付了钱,但是店主因为处理了一些其他事,居然忘记你付了钱,又叫你重新付。又或者在网上购物明明已经扣款,但是却告诉我没有发生交易。这一系列情况都是因为没有事务导致的。这说明了事务在生活中的一些重要性。有了事务,你去小卖铺买东西,那就是一手交钱一手交货。有了事务,你去网上购物,扣款即产生订单交易。

事务的具体定义

事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整个事务的回滚。简单地说,事务提供一种“要么什么都不做,要么做全套(All or Nothing)”机制。

数据库本地事务

ACID

说到数据库事务就不得不说,数据库事务中的四大特性,ACID:

  • A:原子性(Atomicity)
    一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
    就像你买东西要么交钱收货一起都执行,要么要是发不出货,就退钱。
  • C:一致性(Consistency)
    事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。
  • I:隔离性(Isolation)
    指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
    打个比方,你买东西这个事情,是不影响其他人的。
  • D:持久性(Durability)
    指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
    打个比方,你买东西的时候需要记录在账本上,即使老板忘记了那也有据可查。

    InnoDB实现原理

    InnoDB是mysql的一个存储引擎,大部分人对mysql都比较熟悉,这里简单介绍一下数据库事务实现的一些基本原理,在本地事务中,服务和资源在事务的包裹下可以看做是一体的:
    事务
    我们的本地事务由资源管理器进行管理:
    InnoDB
    而事务的ACID是通过InnoDB日志和锁来保证。事务的隔离性是通过数据库锁的机制实现的,持久性通过redo log(重做日志)来实现,原子性和一致性通过Undo log来实现。UndoLog的原理很简单,为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为UndoLog)。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。 和Undo Log相反,RedoLog记录的是新数据的备份。在事务提交前,只要将RedoLog持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是RedoLog已经持久化。系统可以根据RedoLog的内容,将所有数据恢复到最新的状态。 对具体实现过程有兴趣的同学可以去自行搜索扩展。

    分布式事务

    什么是分布式事务

    分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

    分布式事务产生的原因

    从上面本地事务来看,我们可以看为两块,一个是service产生多个节点,另一个是resource产生多个节点。
    service多个节点
    随着互联网快速发展,微服务,SOA等服务架构模式正在被大规模的使用,举个简单的例子,一个公司之内,用户的资产可能分为好多个部分,比如余额,积分,优惠券等等。在公司内部有可能积分功能由一个微服务团队维护,优惠券又是另外的团队维护
    service多个节点
    这样的话就无法保证积分扣减了之后,优惠券能否扣减成功。
    resource多个节点
    同样的,互联网发展得太快了,我们的Mysql一般来说装千万级的数据就得进行分库分表,对于一个支付宝的转账业务来说,你给的朋友转钱,有可能你的数据库是在北京,而你的朋友的钱是存在上海,所以我们依然无法保证他们能同时成功。
    resource多个节点

    分布式事务的基础

    从上面来看分布式事务是随着互联网高速发展应运而生的,这是一个必然的我们之前说过数据库的ACID四大特性,已经无法满足我们分布式事务,这个时候又有一些新的大佬提出一些新的理论:
    CAP
    从上面来看分布式事务是随着互联网高速发展应运而生的,这是一个必然的我们之前说过数据库的ACID四大特性,已经无法满足我们分布式事务,这个时候又有一些新的大佬提出一些新的理论:

    CAP

    CAP定理,又被叫作布鲁尔定理。对于设计分布式系统来说(不仅仅是分布式事务)的架构师来说,CAP就是你的入门理论。
  • C (一致性):对某个指定的客户端来说,读操作能返回最新的写操作。对于数据分布在不同节点上的数据上来说,如果在某个节点更新了数据,那么在其他节点如果都能读取到这个最新的数据,那么就称为强一致,如果有某个节点没有读取到,那就是分布式不一致。
  • A (可用性):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。可用性的两个关键一个是合理的时间,一个是合理的响应。合理的时间指的是请求不能无限被阻塞,应该在合理的时间给出返回。合理的响应指的是系统应该明确返回结果并且结果是正确的,这里的正确指的是比如应该返回50,而不是返回40。
  • P (分区容错性):当出现网络分区后,系统能够继续工作。打个比方,这里个集群有多台机器,有台机器网络出现了问题,但是这个集群仍然可以正常工作。
    熟悉CAP的人都知道,三者不能共有,如果感兴趣可以搜索CAP的证明,在分布式系统中,网络无法100%可靠,分区其实是一个必然现象,如果我们选择了CA而放弃了P,那么当发生分区现象时,为了保证一致性,这个时候必须拒绝请求,但是A又不允许,所以分布式系统理论上不可能选择CA架构,只能选择CP或者AP架构。
    对于CP来说,放弃可用性,追求一致性和分区容错性,我们的zookeeper其实就是追求的强一致。
    对于AP来说,放弃一致性(这里说的一致性是强一致性),追求分区容错性和可用性,这是很多分布式系统设计时的选择,后面的BASE也是根据AP来扩展。
    顺便一提,CAP理论中是忽略网络延迟,也就是当事务提交时,从节点A复制到节点B,但是在现实中这个是明显不可能的,所以总会有一定的时间是不一致。同时CAP中选择两个,比如你选择了CP,并不是叫你放弃A。因为P出现的概率实在是太小了,大部分的时间你仍然需要保证CA。就算分区出现了你也要为后来的A做准备,比如通过一些日志的手段,是其他机器回复至可用。
    BASE
    BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。是对CAP中AP的一个扩展
  1. 基本可用:分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。
  2. 软状态:允许系统中存在中间状态,这个状态不影响系统可用性,这里指的是CAP中的不一致。
  3. 最终一致:最终一致是指经过一段时间后,所有节点数据都将会达到一致。
    BASE解决了CAP中理论没有网络延迟,在BASE中用软状态和最终一致,保证了延迟后的一致性。BASE和 ACID 是相反的,它完全不同于ACID的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。

    分布式事务解决方案

    有了上面的理论基础后,这里介绍开始介绍几种常见的分布式事务的解决方案。
    是否真的要分布式事务
    在说方案之前,首先你一定要明确你是否真的需要分布式事务?
    上面说过出现分布式事务的两个原因,其中有个原因是因为微服务过多。我见过太多团队一个人维护几个微服务,太多团队过度设计,搞得所有人疲劳不堪,而微服务过多就会引出分布式事务,这个时候我不会建议你去采用下面任何一种方案,而是请把需要事务的微服务聚合成一个单机服务,使用数据库的本地事务。因为不论任何一种方案都会增加你系统的复杂度,这样的成本实在是太高了,千万不要因为追求某些设计,而引入不必要的成本和复杂度。
    如果你确定需要引入分布式事务可以看看下面几种常见的方案。
    2PC
    说到2PC就不得不聊数据库分布式事务中的 XA Transactions。
    2PC
    在XA协议中分为两阶段:
    第一阶段:事务管理器要求每个涉及到事务的数据库预提交(precommit)此操作,并反映是否可以提交.
    第二阶段:事务协调器要求每个数据库提交数据,或者回滚数据。
    优点: 尽量保证了数据的强一致,实现成本较低,在各大主流数据库都有自己实现,对于MySQL是从5.5开始支持。
    缺点:
  • 单点问题:事务管理器在整个流程中扮演的角色很关键,如果其宕机,比如在第一阶段已经完成,在第二阶段正准备提交的时候事务管理器宕机,资源管理器就会一直阻塞,导致数据库无法使用。
  • 同步阻塞:在准备就绪之后,资源管理器中的资源一直处于阻塞,直到提交完成,释放资源。
  • 数据不一致:两阶段提交协议虽然为分布式数据强一致性所设计,但仍然存在数据不一致性的可能,比如在第二阶段中,假设协调者发出了事务commit的通知,但是因为网络问题该通知仅被一部分参与者所收到并执行了commit操作,其余的参与者则因为没有收到通知一直处于阻塞状态,这时候就产生了数据的不一致性。
    总的来说,XA协议比较简单,成本较低,但是其单点问题,以及不能支持高并发(由于同步阻塞)依然是其最大的弱点。
    TCC
    关于TCC(Try-Confirm-Cancel)的概念,最早是由Pat Helland于2007年发表的一篇名为《Life beyond Distributed Transactions:an Apostate’s Opinion》的论文提出。 TCC事务机制相比于上面介绍的XA,解决了其几个缺点: 1.解决了协调者单点,由主业务方发起并完成这个业务活动。业务活动管理器也变成多点,引入集群。 2.同步阻塞:引入超时,超时后进行补偿,并且不会锁定整个资源,将资源转换为业务逻辑形式,粒度变小。 3.数据一致性,有了补偿机制之后,由业务活动管理器控制一致性。
    TCC
    对于TCC的解释:
  • Try阶段:尝试执行,完成所有业务检查(一致性),预留必须业务资源(准隔离性)
  • Confirm阶段:确认执行真正执行业务,不作任何业务检查,只使用Try阶段预留的业务资源,Confirm操作满足幂等性。要求具备幂等设计,Confirm失败后需要进行重试。
  • Cancel阶段:取消执行,释放Try阶段预留的业务资源 Cancel操作满足幂等性Cancel阶段的异常和Confirm阶段异常处理方案基本上一致。
    举个简单的例子如果你用100元买了一瓶水, Try阶段:你需要向你的钱包检查是否够100元并锁住这100元,水也是一样的。
    如果有一个失败,则进行cancel(释放这100元和这一瓶水),如果cancel失败不论什么失败都进行重试cancel,所以需要保持幂等。
    如果都成功,则进行confirm,确认这100元扣,和这一瓶水被卖,如果confirm失败无论什么失败则重试(会依靠活动日志进行重试)
    对于TCC来说适合一些:
  • 强隔离性,严格一致性要求的活动业务。
  • 执行时间较短的业务
    实现参考:ByteTCC:github.com/liuyangming…
    本地消息表
    本地消息表这个方案最初是ebay提出的 ebay的完整方案https://queue.acm.org/detail.cfm?id=1394128。
    此方案的核心是将需要分布式处理的任务通过消息日志的方式来异步执行。消息日志可以存储到本地文本、数据库或消息队列,再通过业务规则自动或人工发起重试。人工重试更多的是应用于支付场景,通过对账系统对事后问题的处理。
    本地消息表
    对于本地消息队列来说核心是把大事务转变为小事务。还是举上面用100元去买一瓶水的例子。

1.当你扣钱的时候,你需要在你扣钱的服务器上新增加一个本地消息表,你需要把你扣钱和写入减去水的库存到本地消息表放入同一个事务(依靠数据库本地事务保证一致性。
2.这个时候有个定时任务去轮询这个本地事务表,把没有发送的消息,扔给商品库存服务器,叫他减去水的库存,到达商品服务器之后这个时候得先写入这个服务器的事务表,然后进行扣减,扣减成功后,更新事务表中的状态。
3.商品服务器通过定时任务扫描消息表或者直接通知扣钱服务器,扣钱服务器本地消息表进行状态更新。
4.针对一些异常情况,定时扫描未成功处理的消息,进行重新发送,在商品服务器接到消息之后,首先判断是否是重复的,如果已经接收,在判断是否执行,如果执行在马上又进行通知事务,如果未执行,需要重新执行需要由业务保证幂等,也就是不会多扣一瓶水。
本地消息队列是BASE理论,是最终一致模型,适用于对一致性要求不高的。实现这个模型时需要注意重试的幂等。

MQ事务

在RocketMQ中实现了分布式事务,实际上其实是对本地消息表的一个封装,将本地消息表移动到了MQ内部,下面简单介绍一下MQ事务,如果想对其详细了解可以参考:www.jianshu.com/p/453c6e7ff…
MQ事务1
基本流程如下: 第一阶段Prepared消息,会拿到消息的地址。
第二阶段执行本地事务。
第三阶段通过第一阶段拿到的地址去访问消息,并修改状态。消息接受者就能使用这个消息。
如果确认消息失败,在RocketMq Broker中提供了定时扫描没有更新状态的消息,如果有消息没有得到确认,会向消息发送者发送消息,来判断是否提交,在rocketmq中是以listener的形式给发送者,用来处理。
MQ事务2
如果消费超时,则需要一直重试,消息接收端需要保证幂等。如果消息消费失败,这个就需要人工进行处理,因为这个概率较低,如果为了这种小概率时间而设计这个复杂的流程反而得不偿失

Saga事务

Saga是30年前一篇数据库伦理提到的一个概念。其核心思想是将长事务拆分为多个本地短事务,由Saga事务协调器协调,如果正常结束那就正常完成,如果某个步骤失败,则根据相反顺序一次调用补偿操作。 Saga的组成:
每个Saga由一系列sub-transaction Ti 组成 每个Ti 都有对应的补偿动作Ci,补偿动作用于撤销Ti造成的结果,这里的每个T,都是一个本地事务。 可以看到,和TCC相比,Saga没有“预留 try”动作,它的Ti就是直接提交到库。
Saga的执行顺序有两种:
T1, T2, T3, …, Tn
T1, T2, …, Tj, Cj,…, C2, C1,其中0 < j < n Saga定义了两种恢复策略:
向后恢复,即上面提到的第二种执行顺序,其中j是发生错误的sub-transaction,这种做法的效果是撤销掉之前所有成功的sub-transation,使得整个Saga的执行结果撤销。 向前恢复,适用于必须要成功的场景,执行顺序是类似于这样的:T1, T2, …, Tj(失败), Tj(重试),…, Tn,其中j是发生错误的sub-transaction。该情况下不需要Ci。
这里要注意的是,在saga模式中不能保证隔离性,因为没有锁住资源,其他事务依然可以覆盖或者影响当前事务。
还是拿100元买一瓶水的例子来说,这里定义
T1=扣100元 T2=给用户加一瓶水 T3=减库存一瓶水
C1=加100元 C2=给用户减一瓶水 C3=给库存加一瓶水
我们一次进行T1,T2,T3如果发生问题,就执行发生问题的C操作的反向。 上面说到的隔离性的问题会出现在,如果执行到T3这个时候需要执行回滚,但是这个用户已经把水喝了(另外一个事务),回滚的时候就会发现,无法给用户减一瓶水了。这就是事务之间没有隔离性的问题
可以看见saga模式没有隔离性的影响还是较大,可以参照华为的解决方案:从业务层面入手加入一 Session 以及锁的机制来保证能够串行化操作资源。也可以在业务层面通过预先冻结资金的方式隔离这部分资源, 最后在业务操作的过程中可以通过及时读取当前状态的方式获取到最新的更新。
具体实例:可以参考华为的servicecomb

最后

还是那句话,能不用分布式事务就不用,如果非得使用的话,结合自己的业务分析,看看自己的业务比较适合哪一种,是在乎强一致,还是最终一致即可。上面对解决方案只是一些简单介绍,如果真正的想要落地,其实每种方案需要思考的地方都非常多,复杂度都比较大,所以最后再次提醒一定要判断好是否使用分布式事务。最后在总结一些问题,大家可以下来自己从文章找寻答案:

  1. ACID和CAP的 CA是一样的吗?
  2. 分布式事务常用的解决方案的优缺点是什么?适用于什么场景?
  3. 分布式事务出现的原因?用来解决什么痛点?
    转自作者:咖啡拿铁
    转自链接:https://juejin.im/post/5b5a0bf9f265da0f6523913b
    转自来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

修改docker日志目录

默认安装完成docker后docker的所有images及相关信息存储位置为:/var/lib/docker

镜像默认路径: /var/lib/docker/containers/

而通常我们的系统盘挂载一般不会很大,所以需要将其移到其他分区,我们可以采用

一,软链接的方式

  1. 首先暂停docker服务

    1
    systemctl stop docker.service
  2. 将文件移到指定目录

    1
    2
    3
    4
    5
    6
    7
    cd /var/lib
    # 文件复制
    mv docker/* /home/docker-log
    # 删除原来/var/lib下的docker文件夹
    rm -rf docker
    # 进入/dome/docker-log创建软连接
    ln -s /home/docker-log /var/lib/docker
  3. 重启服务

    1
    2
    systemctl restart docker.service
    docker info # 查看是否成功

二,修改镜像和容器的存放路径

指定镜像和容器存放路径的参数是–graph=/var/lib/docker,我们只需要修改配置文件指定启动参数即可。

Docker 的配置文件可以设置大部分的后台进程参数,在各个操作系统中的存放位置不一致,在 Ubuntu 中的位置是:/etc/default/docker,在 CentOS 中的位置是:/etc/sysconfig/docker。

如果是 CentOS6 则添加下面这行:

OPTIONS=–graph=”/root/data/docker” –selinux-enabled -H fd://

如果是 Ubuntu 则添加下面这行(因为 Ubuntu 默认没开启 selinux):

OPTIONS=–graph=”/root/data/docker” -H fd://# 或者DOCKER_OPTS=”-g /root/data/docker”

最后重新启动,Docker 的路径就改成 /root/data/docker 了。

centos7下,也可以

修改docker.service文件,使用-g参数指定存储位置

vi /usr/lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd –graph /new-path/docker

// reload配置文件

systemctl daemon-reload

// 重启docker

systemctl restart docker.service

如果docker是1.12或以上的版本,可以修改(或新建)daemon.json文件。修改后会立即生效,不需重启docker服务。

vim /etc/docker/daemon.json

{“registry-mirrors”: [“http://7e61f7f9.m.daocloud.io"],"graph": “/new-path/docker”}

三,system下创建配置文件

在/etc/systemd/system/docker.service.d 目录下创建一个Drop-In文件“docker.conf”,默认 docker.service.d 文件夹不存在。所以你必须先创建它。

创建Drop-In 文件的原因,是我们希望Docker 服务,使用docker.conf文件中提到的特定参数,将默认服务所使用的位于/lib/systemd/system/docker.service文件中的参数进行覆盖。如果你想深入了解Drop-In,请阅读system.unit文档

定义新的存储位置现在打开docker.conf增加如下内容:

# sudo vi /etc/systemd/system/docker.service.d/docker.conf

[Service]

ExecStart=

ExecStart=/usr/bin/dockerd –graph=”/mnt/new_volume” –storage-driver=devicemapper

保存并退出VI编辑器,/mnt/new_volume 是新的存储位置,而devicemapper是当前docker所使用的存储驱动。如果你的存储驱动有所不同,请输入之前第一步查看并记下的值。Docker官方文档中提供了更多有关各种存储驱动器的信息。现在,你可以重新加载服务守护程序,并启动Docker服务了。这将改变新的镜像和容器的存储位置。

# sudo systemctl daemon-reload

# sudo systemctl start docker

为了确认一切顺利,运行 # docker info 命令检查Docker 的根目录.它将被更改为/mnt/new_volume

四,使用docker-storage-set(docker1.12)命令进行配置

配置文件位置:/usr/lib/docker-storage-setup/docker-storage-setup或者/etc/sysconfig/docker-storage-setup、/etc/sysconfig/docker-storage

vim /etc/sysconfig/docker-storage

# This file may be automatically generated by an installation program.

# Please DO NOT edit this file directly. Instead edit

# /etc/sysconfig/docker-storage-setup and/or refer to

# “man docker-storage-setup”.

# By default, Docker uses a loopback-mounted sparse file in

# /var/lib/docker. The loopback makes it slower, and there are some

# restrictive defaults, such as 100GB max storage.

DOCKER_STORAGE_OPTIONS=–graph=”要保存的路径”

或者

DEVS=/dev/vdb

DATA_SIZE=800GB(更改docker默认存储大小)

参考连接

jenkins安装(yum源安装)

一,前沿

  1. Jenkins是什么?
    Jenkins是一个开源的支持自动化构建,部署等任务的平台。基本上可以说是持续集成(CI),持续发布(CD)不可缺的工具。Jenkins的官方地址

  2. 本篇环境信息

    工具/环境 版本
    Linux Server CentOS 7
    Jenkins 2.121.2
    JDK 1.8.0_181
  3. 准备工作
    安装jdk,安装maven

    二,安装Jenkins

  4. yum源的安装

    • yum源导入

      1
      2
      3
      4
      #添加Yum源
      sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
      #导入密钥
      sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
    • 安装

      1
      sudo yum install -y jenkins
  5. 开放端口
    Jenkins站点的默认监听端口是8080

    1
    2
    sudo firewall-cmd --add-port=8080/tcp --permanent
    sudo firewall-cmd --reload
  6. 配置Java可选路径
    因为Jenkins默认的java可选路径不包含我们部署的jdk路径,所以这里要配置一下,不然Jenkins服务会启动失败

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #修改jenkins启动脚本
    sudo vi /etc/init.d/jenkins
    #修改candidates增加java可选路径:/usr/java/jdk1.8.0_181/bin/java
    candidates="
    /etc/alternatives/java
    /usr/lib/jvm/java-1.8.0/bin/java
    /usr/lib/jvm/jre-1.8.0/bin/java
    /usr/lib/jvm/java-1.7.0/bin/java
    /usr/lib/jvm/jre-1.7.0/bin/java
    /usr/bin/java
    /usr/java/jdk1.8.0_181/bin/java
  7. 启动Jenkins并设置Jenkins开机启动

    1
    2
    3
    4
    5
    6
    7
    #重载服务(由于前面修改了Jenkins启动脚本)
    sudo systemctl daemon-reload
    #启动Jenkins服务
    sudo systemctl start jenkins
    #将Jenkins服务设置为开机启动
    #由于Jenkins不是Native Service,所以需要用chkconfig命令而不是systemctl命令
    sudo /sbin/chkconfig jenkins on

    浏览器输入 http://:8080 访问Jenkins

    三,Jenkins初始化

  8. 解锁Jenkins
    查询root账号默认密码

    1
    cat /var/lib/jenkins/secrets/initialAdminPassword

    jenkins初始化

  9. 选择插件
    jenkins选择插件
    可以选择安装推荐的插件,也可以选择自定义的插件安装,其中这里我选择了第二种。
    jenkins初始化安装插件

  10. 添加管理员
    创建用户

  11. 配置Jenkins URL
    如果由域名的话可以填入域名,之后也可以修改;在系统管理=>系统设置 Jenkins Location中设置
    配置URL

  12. 开始使用Jenkins
    配置完Jenkins URL之后就完成了整个Jenkins配置引导
    开始Jenkins

  13. 点击“开始使用Jenkins”就会进入Jenkins主页
    Jenkins的主页

四,Jenkins与git SSH配置

  1. 首先在jenkins服务器上安装相对应的git工具

    1
    yum -y install git
  2. 安装好git服务器,可以用gogs,GitLab或者直接使用github,gitee等仓库

  3. 在Jenkins服务器配置相对应的.ssh目录下配置config

    1
    2
    3
    4
    5
    Host git.***.com(你设置的jenkins能访问到的git域名)
    HostName git.***.com
    Port 10022(开放的git服务ssh端口)
    IdentityFile ~/.ssh/id_rsa(设置的公钥与私钥对应)
    IdentitiesOnly yes

    在git服务上进行相对应的ssh配置将jenkins生成的id_rsa.pub文件

  4. 这样配置你的jenkins服务器上应该能够clone相关的代码。如果jenkins服务与git服务放在一台服务上jenkins的web服务应该能拉取相关的代码,如果2台分开部署如何配置呢?

  5. 在jenkins的安装目录下进行ssh配置在/var/lib/jenkins创建相关的.ssh文件,设置相关的config以及私钥

  6. 在jenkins的web页面进行相关的配置将相对应的配置创建相关的密钥对应

五,Jenkins中JAVA,MAVEN配置

  1. 在jenkins服务器中安装相对应的JAVA环境,然后再系统管理中全局环境变量设置相对应的JAVA_HOME的环境
  2. maven配置,安装相关的maven插件Pipeline Maven Integration,配置相关的.m2文件

六,在Jenkins中配置nodejs

  1. 在centos中安装nodejs

    • 新建目录/opt/mnt

    • 选择你相应的版本官网下载对应的版本

    • 下载nodejs

      1
      wget https://nodejs.org/download/release/v8.12.0/node-v8.12.0-linux-x64.tar.gz
  • 解压

    1
    tar -zxcf -C node-v8.12.0-linux-x64.tar.gz
  • 进入解压目录下的bin目录,执行ls命令

    1
    2
    mv node-v8.12.0-linux-x64 node
    cd node/bin && ls
有node和npm

测试

1
./node -v
显示版本号即代表成功
  • 现在 nodenpm 还不能全局使用,做个链接

    1
    2
    ln -s /opt/mnt/node/bin/node /usr/local/bin/node
    ln -s /opt/mnt/node/bin/npm /usr/local/bin/npm
至此node就安装成功了
  1. jenkins中配置nodejs

    1563848937513

  2. 全局安装相应的angular的框架

    1
    npm install -g @angular/cli@7.3.9
  1. 修改npm的淘宝镜像,在/var/lib/jenkins的目录下创建相关

    1
    2
    3
    4
    5
    sudo su -s /bin/bash jenkins #登录jenkins
    cd /var/lib/jenkins
    touch .npmrc
    vi .npmrc
    registry=https://registry.npm.taobao.org/

七,jenkins修改用户运行

  1. 解决登录jenkins的问题,由于jenkins在运行时可以选择用户进行运行;

    • 打开Jenkins配置文件

      1
      vim /etc/sysconfig/jenkins

      找到如下行:

      将原来的Jenkins用户修改为root用户:

      1
      $JENKINS_USER="root"
  • 修改Jenkins相关文件夹用户权限

    更改jenkins三个文件夹的用户所属用户组:

    1
    2
    3
    chown -R root:root /var/lib/jenkins   jenkins的home目录
    chown -R root:root /var/cache/jenkins jenkins的缓存目录
    chown -R root:root /var/log/jenkins jenkins的日志目录
  • 重启jenkins

    重启jenkins服务并检查运行Jenkins的用户是否已经切换为root

    1
    2
    systemctl restart jenkins
    ps -ef | grep jenkins

    若显示为root用户,则表示修改完成

八,报错解决

  1. jenkins登录不了Harbor问题

    错误内容:

    1
    Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.34/version: dial unix /var/run/docker.sock: connect: permission denied

    解决方案:

    • 优先参考官方Manage Docker as a non-root user

    • 关闭虚拟机的selinux(可能有用)。参考查看 SELinux状态及关闭SELinux

    • 在虚拟机中修改/var/run/docker.sock的权限。(很危险!!!)(不推荐)

      终极解决方案:

      错误原因是,在push之前,需要使用docker login命令完成登录

      但是Jenkins job的命令是以伪用户jenkins的名义执行的,因此无法直接在jenkins账户完成登录,那么如何解决呢?

    • 使用root账户完成登录

    • 将/root/目录下的.docker目录复制到/var/lib/jenkins jenkins的家目录

    • 修改文件夹权限chown -R jenkins:jenkins .docker

      原理是:登录成功后会在.docker中生成一个config.json文件,里面保存了认证的信息,以后每次执行docker pull/push时,都会通过检测该文件确定用户是否已完成认证。

      参考文档1

      参考文档2

  2. 切换jenkins用户登录

    1
    sudo su -s /bin/bash jenkins
  1. 解决jenkins拉取不了私服代码的问题
    1563847680915

  2. Jenkins远程连接linux

    由于配置原因造成一下错误

    错误:jenkins.plugins.publish_over.BapPublisherException: Failed to connect session for config [131]. Message [Auth fail]

    配置方法:

    • 生成密钥

      在我的jenkins服务器上/var/lib/jenkins用户目录下

      1
      2
      3
      4
      ssh-keygen # 密钥生成路径直接默认回车
      cd .ssh
      cat id_rsa.pub >> authorized_keys # 将公钥拷贝到authorized_keys文件
      scp authorized_keys user@ip:/root/.ssh #将生成的authorized_keys拷贝到要连接的linux机器上的对应用户下的.ssh文件夹下
    • 配置SSH server 系统管理->系统设置

      系统设置

      点击测试

      test ssh

    • 参考连接

九,总结

​ 至此yum源安装的jenkins就完毕了,之后会陆续推出相关的docker中安装jenkins,在k8s中使用jenkins的master/salves模式

Harbor安装与配置

企业级私有镜像仓库的使用

简介

​ Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源Docker Distribution。作为一个企业级私有Registry服务器,Harbor提供了更好的性能和安全。提升用户使用Registry构建和运行环境传输镜像的效率。Harbor支持安装在多个Registry节点的镜像资源复制,镜像全部保存在私有Registry中, 确保数据和知识产权在公司内部网络中管控。另外,Harbor也提供了高级的安全特性,诸如用户管理,访问控制和活动审计等。

  • 基于角色的访问控制- 用户与Docker镜像仓库通过“项目”进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限。
  • 镜像复制 - 镜像可以在多个Registry实例中复制(同步)。尤其适合于负载均衡,高可用,混合云和多云的场景。
  • 图形化用户界面 - 用户可以通过浏览器来浏览,检索当前Docker镜像仓库,管理项目和命名空间。
  • AD/LDAP 支持 - Harbor可以集成企业内部已有的AD/LDAP,用于鉴权认证管理。
  • 审计管理 - 所有针对镜像仓库的操作都可以被记录追溯,用于审计管理。
    国际化 - 已拥有英文、中文、德文、日文和俄文的本地化版本。更多的语言将会添加进来。
  • RESTful API - RESTful API 提供给管理员对于Harbor更多的操控, 使得与其它管理软件集成变得更容易。
  • 部署简单 - 提供在线和离线两种安装工具, 也可以安装到vSphere平台(OVA方式)虚拟设备。

准备条件

Harbor被部署为多个Docker容器,因此可以部署在任何支持Docker的Linux发行版上,目标主机需要Docker,并且要安装Docker Compose

  • 硬件

    Resource Capacity Description
    CPU minimal 2 CPU 4 CPU is preferred
    Mem minimal 4GB 8GB is preferred
    Disk minimal 40GB 160GB is preferred
  • 软件

    Software Version Description
    Docker engine version 17.06.0-ce+ or higher For installation instructions, please refer to: docker engine doc
    Docker Compose version 1.18.0 or higher For installation instructions, please refer to: docker compose doc
    Openssl latest is preferred Generate certificate and keys for Harbor
  • 网络端口

    Port Protocol Description
    443 HTTPS Harbor portal and core API will accept requests on this port for https protocol, this port can change in config file
    4443 HTTPS Connections to the Docker Content Trust service for Harbor, only needed when Notary is enabled, This port can change in config file
    80 HTTP Harbor portal and core API will accept requests on this port for http protocol

Harbor安装

Harbor在github上的地址,从readme.md中可以知道安装的方式分为

  • Online installer(这是harbor的一种安装方式,与本文标题线上搭建无关联)
  • Offline installer(本文主讲)
  • OVA installer

至于Online installer和OVA installer这两种搭建方式,本文不会提及,有兴趣的同学可以自己尝试,相信在看完本文之后你也可以完成自己的Harbor仓库的搭建。

Offline installer

在官方的发布版本中,找到一个最新的发布版本(本文写与2019.07.18,官方version为1.8.1)

下载之后会得到一个类似于harbor-offline-installer-v1.8.1.tgz的文件,用命令

1
tar -zxvf harbor-offline-installer-v1.8.1.tgz
Harbor目录简介
  • harbor.v1.8.1.tar.gz
  • harbor.yml 启动harbor时使用的配置文件
  • install.sh 是一个shell脚本启动脚本
  • LICENSE 该版本许可信息
  • prepare python写的初始化脚本
http安装方式

安装步骤

  • 配置好harbor.yml

    1563438641

  • 运行install.sh 或者(./prepare 再使用docker-compose up -d启动)

  • 使用浏览器http://ip可以访问harbor的web页面

  • 其他docker客户端如何推送到该私有镜像仓库呢?

    • Harbor的默认安装使用HTTP - 因此,您需要将该选项添加--insecure-registry到客户端的Docker守护程序并重新启动Docker服务。

    • 在客户端的docker服务器中的/etc/docker/daemon.josn中配置

      1
      2
      3
      {
      "insecure-registry":"harbor服务器的ip"
      }
  • 登录

    1
    docker login ip -u admin -p Harbor12345
https安装方式
  • 首先也是配置harbor.yml文件(放开https配置,配置相应的域名)

  • 根据官方的文档生成对应的ssl密钥文件

  • 1563439550

  • 在对应的dockers客户端的/etc/hosts添加相应的域名解析

  • 运行install.sh 或者(./prepare 再使用docker-compose up -d启动)

  • 在电脑上配置 C:\Windows\System32\drivers\etc\hosts增加相应的域名解析,使用浏览器在https://ip可以访问harbor的web页面

  • 登录

    1
    docker login 域名 -u admin -p Harbor12345