# Phoenix **Repository Path**: Junice/phoenix ## Basic Information - **Project Name**: Phoenix - **Description**: 关于什么是“凤凰架构”的一些理解以及代码 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-09-01 - **Last Updated**: 2022-11-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 凤凰架构偷师 ## 介绍 学校“凤凰架构”的一些认知与代码 ## 凤凰架构 访问:http://icyfenix.cn/ ### 一些认知 #### 单体的弊端是什么 ``` 1.进程内隔离与自治能力上的欠缺导致造成的影响也是全局性的、难以隔离的。 一个tomcat发2个包也是用一个进程。所有线程共享进程资源。 库必须隔离自治能力才有意义。 2.程序升级、修改缺陷困难。 3.难以技术异构的困难。 ``` #### 为什么大家都往微服务迁移 ``` 1.外部 (1)当意识到没有什么技术能够包打天下。 (2)当个人能力因素成为系统发展的明显制约。 (3)当遇到来自外部商业层面对内部技术层面提出的要求。 2.内部 (1)变化发展特别快的创新业务系统往往会自主地向微服务架构靠近。 (2)大规模的、业务复杂的、历史包袱沉重的系统也可能主动向微服务架构靠近。 3.最主要的目的是对系统进行有效的拆分,实现物理层面的隔离,微服务的核心价值就是拆分之后的系统能够让局部的单个服务有可能实现敏捷地卸载、部署、开发、升级,局部的持续更迭,是系统整体具备 Phoenix 特性的必要条件 ``` #### 什么时候用单体 ``` 1.微服务化的第一个前提条件是决策者与执行者都能意识到康威定律在软件设计中的关键作用。 2.微服务化的第二个前提条件是组织中具备一些对微服务有充分理解、有一定实践经验的技术专家。 3.微服务化的第三个前提条件是系统应具有以自治为目标的自动化与监控度量能力。 4.微服务化的第四个前提条件是复杂性已经成为制约生产力的主要矛盾。 ``` #### 怎么理解接口 ``` 不在乎内部实现,只在乎输入与输出是否满足规则。 规范和标准、功能的抽象。 ``` #### 接口的表现形式有哪些 ``` 1.http接口:基于HTTP协议的开发接口。 2.api接口:API(Application Programming Interface)应用程序编程接口,应用也包括网络应用程序。 3.RPC接口:不在同一个进程中即为此。Remote Procedure Calls 远程过程调用 (RPC) 是一种协议,程序可使用这种协议向网络中的另一台计算机上的程序请求服务 4.RMI:RMI(Remote Method Invocation,远程方法调用)RMI是针对于java语言的, RMI 允许您使用Java编写分布式对象 5.Webservice接口:Webservice是系统对外的接口。 6.RESTful : 简称 REST,是描述了一个架构样式的网络系统,其核心是面向资源,REST专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性。 ``` #### 如何构建可靠地系统 ``` 编写可靠地代码,使用虚拟化技术和容器化技术保证其运行的可靠性。 面向失败、面向错误编程。 ``` #### 什么是可靠地系统 ``` 可以自动快速检测问题,并针对问题自动的应对,不太需要人为参与,排查问题并不引起用户感知的系统。 ``` #### 响应式宣言包含哪些内容 该如何理解 ``` 使用消息驱动的方法来构建系统,在形式上能够达到弹性和韧性,最后能够产生响应性的价值。 具有以下几个特性: 即时响应性: :只要有可能, 系统就会及时地做出响应。 回弹性:系统在出现失败时依然保持即时响应性。 弹性: 系统在不断变化的工作负载之下依然保持即时响应性。 消息驱动:反应式系统依赖异步的消息传递,从而确保了松耦合、隔离、位置透明的组件之间有着明确边界。 ``` #### 弹性 和 韧性的认知 ``` 韧性主要是系统对错误的容忍。 弹性主要是扩展。若是没有状态的话,就进行水平扩展,若是存在状态,就使用分片技术,将数据分至不一样的机器上 ``` # 数据库隔离级别以及日志 ## 介绍 实际情况演示、MySQL日志(redo log和undo log) ### 数据库隔离级别【凤凰架构】 访问:https://jingyecn.top:18080/architect-perspective/general-architecture/transaction/ #### 脏读(读未提交) ``` #脏读(读未提交) 1.开头的在一个窗口,2.在另一个窗口 -- 1.1 设置事务隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT @@transaction_isolation; -- 1.2 开启事务 START TRANSACTION; -- 1.3 查看数据 SELECT tel FROM user_tel WHERE id = 1; -- 2.4 第二个事务开启 ,默认【REPEATABLE READ】事务级别即可 START TRANSACTION; -- 2.5 第二个事务修改数据,但是未提交 UPDATE user_tel SET tel = 148 WHERE id = 1; -- 1.6 读取到第二个事务未提交的数据 SELECT tel FROM user_tel WHERE id = 1; 2.7 第二个事务回滚 ROLLBACK; -- 1.8 确认第二个事务进行了回滚,读取到的148是个脏数据 SELECT tel FROM user_tel WHERE id = 1; ``` ![](.IsolationLevel_images/594816eb.png) #### 避免脏读(读已提交) ``` #避免脏读(读已提交) 1.开头的在一个窗口,2.在另一个窗口 -- 1.1 设置事务隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT @@transaction_isolation; -- 1.2 开启事务 START TRANSACTION; -- 1.3 查看数据 SELECT tel FROM user_tel WHERE id = 1; -- 2.4 第二个事务开启 ,默认【REPEATABLE READ】事务级别即可 START TRANSACTION; -- 2.5 第二个事务修改数据,但是未提交 UPDATE user_tel SET tel = 148 WHERE id = 1; -- 1.6 读取不到第二个事务未提交的数据 SELECT tel FROM user_tel WHERE id = 1; -- 2.7 第二个事务提交 COMMIT; -- 1.8 读取到的数据是已提交的数据 SELECT tel FROM user_tel WHERE id = 1; ``` ![](.IsolationLevel_images/7794bbab.png) #### 不可重复读 ``` 如上图所示,一个事务还没有结束,就发生了不可重复读问题。 ``` #### 可重复读 ``` #可重复读 1.开头的在一个窗口,2.在另一个窗口 -- 1.1 设置事务隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT @@transaction_isolation; -- 1.2 开启事务 START TRANSACTION; -- 1.3 查看数据 SELECT tel FROM user_tel WHERE id = 1; -- 2.4 第二个事务开启 ,默认【REPEATABLE READ】事务级别即可 START TRANSACTION; -- 2.5 第二个事务修改数据,但是未提交 UPDATE user_tel SET tel = 148 WHERE id = 1; -- 1.6 读取不到第二个事务未提交的数据 SELECT tel FROM user_tel WHERE id = 1; -- 2.7 第二个事务提交 COMMIT; -- 1.8 第三次读取,结果仍然不变 SELECT tel FROM user_tel WHERE id = 1; -- 1.9 提交事务 COMMIT; -- 1.10 可以查看到修改数据 SELECT tel FROM user_tel WHERE id = 1; ``` ![](.IsolationLevel_images/37c6d3c9.png) ### MySQL日志(redo log和undo log) ``` redo log(重做日志)和undo log(回滚日志) ``` ![](.IsolationLevel_images/79f8201a.png) #### redo log ##### 定义 ``` redo log(重做日志)是InnoDB存储引擎独有的,它让MySQL拥有了崩溃恢复能力。 比如 MySQL 实例挂了或宕机了,重启时,InnoDB存储引擎会使用redo log恢复数据,保证数据的持久性与完整性。 ``` ![](.IsolationLevel_images/5b8a5b5e.png) ``` redo log(重做日志)是InnoDB存储引擎独有的,它让MySQL拥有了崩溃恢复能力。 比如 MySQL 实例挂了或宕机了,重启时,InnoDB存储引擎会使用redo log恢复数据,保证数据的持久性与完整性。 ``` ![](.IsolationLevel_images/a544bf92.png) ##### 刷盘策略 ``` InnoDB 存储引擎为 redo log 的刷盘策略提供了 innodb_flush_log_at_trx_commit 参数,它支持三种策略: 0 :设置为 0 的时候, 表示每次事务提交时不进行刷盘操作, 如果MySQL挂了或宕机可能会有1秒数据的丢失。 1 :设置为 1 的时候, 表示每次事务提交时都将进行刷盘操作(默认值), 只要事务提交成功,redo log记录就一定在硬盘里,不会有任何数据丢失。 2 :设置为 2 的时候, 表示每次事务提交时都只把 redo log buffer 内容写入 page cache, 如果仅仅只是MySQL挂了不会有任何数据丢失,但是宕机可能会有1秒数据的丢失。 另外,InnoDB 存储引擎有一个后台线程,每隔1 秒,就会把 redo log buffer 中的内容写到文件系统缓存(page cache),然后调用 fsync 刷盘。 除了后台线程每秒1次的轮询操作,还有一种情况,当 redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动刷盘。 ``` ##### 使用redo log好处 ``` 实际上,数据页大小是16KB,刷盘比较耗时,可能就修改了数据页里的几 Byte 数据,有必要把完整的数据页刷盘吗? 而且数据页刷盘是随机写,因为一个数据页对应的位置可能在硬盘文件的随机位置,所以性能是很差。 如果是写 redo log,一行记录可能就占几十 Byte,只包含表空间号、数据页号、磁盘文件偏移 量、更新值,再加上是顺序写,所以刷盘速度很快。 所以用 redo log 形式记录修改内容,性能会远远超过刷数据页的方式,这也让数据库的并发能力更强。 ``` #### undo log ##### 定义 ``` 1. 当事务回滚时用于将数据恢复到修改前的样子: 我们知道如果想要保证事务的原子性,就需要在异常发生时,对已经执行的操作进行回滚,在 MySQL 中, 恢复机制是通过 回滚日志(undo log) 实现的,所有事务进行的修改都会先记录到这个回滚日志中,然后再执行相关的操作。 如果执行过程中遇到异常的话,我们直接利用 回滚日志 中的信息将数据回滚到修改之前的样子即可! 并且,回滚日志会先于数据持久化到磁盘上。这样就保证了即使遇到数据库突然宕机等情况,当用户再次启动数据库的时候, 数据库还能够通过查询回滚日志来回滚将之前未完成的事务。 2.另一个作用是 MVCC ,当读取记录时,若该记录被其他事务占用或当前版本对该事务不可见,则可以通过 undo log 读取之前的版本数据,以此实现非锁定读: MVCC 的实现依赖于:隐藏字段、Read View、undo log。 在内部实现中,InnoDB 通过数据行的 DB_TRX_ID 和 Read View 来判断数据的可见性, 如不可见,则通过数据行的 DB_ROLL_PTR 找到 undo log 中的历史版本。 每个事务读到的数据版本可能是不一样的,在同一个事务中,用户只能看到该事务创建 Read View 之前已经提交的修改和该事务本身做的修改 ``` ##### 两阶段提交 ``` 将redo log的写入拆成了两个步骤prepare和commit,这就是两阶段提交。 ``` ![](.IsolationLevel_images/95cb5baa.png) ### 事务隔离级别总结 #### 四个隔离级别: ``` READ-UNCOMMITTED(读取未提交) : 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。 READ-COMMITTED(读取已提交) : 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。 REPEATABLE-READ(可重复读) : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改, 可以阻止脏读和不可重复读,但幻读仍有可能发生。 SERIALIZABLE(可串行化) : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行, 这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。 ``` ![](.IsolationLevel_images/baf9cc70.png) ``` 因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是 READ-COMMITTED , 但是你要知道的是 InnoDB 存储引擎默认使用 REPEATABLE-READ 并不会有任何性能损失。 InnoDB 存储引擎在分布式事务的情况下一般会用到 SERIALIZABLE 隔离级别。 ``` # REST设计风格 不足和争议 ## 介绍 REST设计风格 不足和争议 ### 凤凰架构 访问:https://icyfenix.cn/architect-perspective/general-architecture/api-style/rest.html ### 一些认知 #### REST的几个理解 ``` 1. 看Url就知道要什么 URL中只使用名词来指定资源,原则上不使用动词 2. 看http method就知道干什么 HTTP动词来实现资源的状态扭转: GET 用来获取资源, POST 用来新建资源(也可以用于更新资源), PUT/PATCH 用来更新资源, DELETE 用来删除资源 3. 看http status code就知道结果如何 200 OK 所有事情都按预期正确执行完毕 - 成功 400 Bad Request APP 发生了一些错误 – 客户端错误 500 Internal Server Error API 发生了一些错误 – 服务器端错误 ``` #### REST的几个限制以及优点 ``` 1.客户-服务器(Client-Server)客户端服务器分离 优点: 提高用户界面的便携性(操作简单) 通过简化服务器提高可伸缩性(高性能,低成本) 允许组件分别优化(可以让服务端和客户端分别进行改进和优化) 2.无状态(Stateless) 从客户端的每个请求要包含服务器所需要的所有信息 优点: 提高可见性(可以单独考虑每个请求) 提高了可靠性(更容易从局部故障中修复) 提高可扩展性(降低了服务器资源使用) 3.缓存(Cachable) 服务器返回信息必须被标记是否可以缓存,如果缓存,客户端可能会重用之前的信息发送请求。 优点: 减少交互次数 减少交互的平均延迟 4.分层系统(Layered System) 系统组件不需要知道与他交流组件之外的事情。封装服务,引入中间层。 优点: 限制了系统的复杂性 提高可扩展性 5.统一接口(Uniform Interface) 优点: 提高交互的可见性 鼓励单独改善组件 6.支持按需代码(Code-On-Demand 可选) 优点: 提高可扩展性 ``` #### REST的使用限制 ``` 对于开放的API,豆瓣、新浪微博、GitHub,好用,非常合适; 基于资源型的RESTFul API 接口粒度和返回结果过于的“粗”, 它通常返回的都是完整的数据模型,这对于客户端非常不友好。 但开放API之所以开放,就是因为它不知道你到底需要什么返回结果, 既然不知道,那么我干脆都返回给你。这样的好处是通用,但客户端 不好处理。你只需要一个字段,服务器啪的丢给你十几个,作为客户 端开发者你怎么想? 对于内部开发,不好用。 内部开发由于需求非常明确,通常来说服务器是不应该简单粗暴的直 接甩资源实体给客户端的。那RESTFul API就不能接入到内部开发 吗?当然不是,我们需要灵活一些借鉴RESTFul中的优点,来设计我 们的内部API。 ``` # 数据库多版本MVCC与Git ## 介绍 Git也是一个多版本控制机制的实现, 对比数据库多版本mvcc思考有哪些相同和不同之处, 这些和数据库的隔离级别有什么关系? #### Git ``` Git采用的是直接记录快照的方式,而非差异比较。 Git 更像是把数据看作是对小型文件系统的一组快照。 每次你提交更新,或在 Git 中保存项目状态时, 它主要对当时的全部文件制作一个快照并保存这个快照的索引。 为了高效,如果文件没有修改,Git 不再重新存储该文件, 而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个 快照流。 ``` #### MVCC ``` MVCC 的实现依赖于:隐藏字段、Read View、undo log。 在内部实现中,InnoDB 通过数据行的 DB_TRX_ID 和 Read View 来判断数据的可见性, 如不可见,则通过数据行的 DB_ROLL_PTR 找到 undo log 中的历史版本。 每个事务读到的数据版本可能是不一样的,在同一个事务中, 用户只能看到该事务创建 Read View 之前已经提交的修改和该事务本身做的修改 ``` RC 和 RR 隔离级别下 MVCC 的差异 ``` 在事务隔离级别 RC 和 RR (InnoDB 存储引擎的默认事务隔离级别)下, InnoDB 存储引擎使用 MVCC(非锁定一致性读),但它们生成 Read View 的时机却不同: 在 RC【READ-COMMITTED(读取已提交)】隔离级别下的 每次select 查询前都生成一个Read View (m_ids 列表) 在 RR【REPEATABLE-READ(可重复读) 】隔离级别下只在事务开始后 第一次select 数据前生成一个Read View(m_ids 列表) ```