<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <channel>
    <title>梦行</title>
    <link>https://yeung.xin</link>
    <description>梦行-博客</description>
    <language>zh-CN</language>
    <item>
      <title>小马哥1期训练营总结</title>
      <link>https://yeung.xin/article/37</link>
      <content:encoded>&lt;ul&gt; &lt;li&gt; &lt;h2&gt;熟悉了 JAX-RS 规范&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;熟悉了 Java JMX 监控体系以及配套工具的使用，了解了 Java 自带的配置管理系统&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;了解了 Servlet 规范以及常用的安全防范，熟悉了 Spring Security 的使用&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;熟悉了常用的 ORM 工具以及 JDBC 的封装思想，熟悉了 Spring MVC 的架构&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;了解了 Spring 的抽象能力以及对 JMX 的扩展，熟悉了 Spring 的配置系统&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;数据 Spring Cache&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;熟悉 Dubbo 注册中心的实现&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;了解 Alibaba Dubbo 的底层原理与 LoadBlance 的实现&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;熟悉了熔断、限流的设计思想以及实现方式&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;了解了 Dubbo 与 Spring 整合的思想以及 Spring Cloud Stream 对异步消息系统的抽象整合&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;熟悉了分布式配置以及分布日志&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;熟悉 Spring Security 访问控制，熟悉 Spring Webflux，熟悉 Spring Cloud 体系，了解了分布式追踪系统&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;熟悉容器化开发&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;掌握常用的容器开发技巧&lt;/h2&gt; &lt;/li&gt; &lt;li&gt; &lt;h2&gt;了解 Java Native、熟悉 k8s 系统以及 istio&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt;</content:encoded>
      <pubDate>Tue, 26 Oct 2021 07:29:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营毕业设计以及总结</title>
      <link>https://yeung.xin/article/36</link>
      <content:encoded>&lt;h1&gt;毕业设计&lt;/h1&gt; &lt;p&gt;&lt;a href="https://yeung.xin/upload/2021/08/4aspqfnmu4i80rmkhb9elasseq.pdf" target="_blank"&gt;电商秒杀系统.pdf&lt;/a&gt;&lt;/p&gt; &lt;h1&gt;课程总结&lt;/h1&gt; &lt;h2&gt;学习历程&lt;/h2&gt; &lt;p&gt;  2019 年 8 月，在极客时间买的第一门课就是华仔的《从0开始学架构》，也是因为这门课接触到了极客时间。但是也只是买了一直没有学习，后面因为对 netty 产生了兴趣买了第二门 netty 课程，学习了大半。后面因为 2020 年初疫情闲置在家，感觉时间很充裕，另外也感觉到自己有很多东西是不会的，就将极客时间架构师学习路径上的课程全面购买了，后面陆陆续续也学习了不少课程，到现在已经有 30 多门拿到毕业证书的课程了。&lt;/p&gt; &lt;p&gt;  同时，在 2020 年 3 月，看到极客训练营(那时叫极客大学)联系李智慧老师开了一门《架构师训练营》的课程，第一时间就报名了，成为了在极客时间上的第一个训练营，经过了 4 个月的学习，也掌握了一些基本的架构设计方法，但是总感觉缺了点什么。&lt;/p&gt; &lt;p&gt;  后面看到极客时间又开了一门《架构实战营》，看到里面的内容以偏向业务为主，想到自己陆陆续续学了很多关于后端的技术，但是对于业务这一块缺少实际的理解，就第一时间报名了。课程上到结束，发现收获很大，不仅学了业务上的一些知识，也知道了之前总感觉缺少的部分是啥了，那就是你的架构没有能让人相信的东西，没有设计的初衷和基准点，架构设计是为了解决问题的，不是给了一张架构图就完事了，而是要结合实际场景进行跟踪对于，选出合适简单可演进的架构。&lt;/p&gt; &lt;h2&gt;关于自己&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;我在读书时学的客户端和嵌入式方面的，也自学了 iOS 开发，基本接触了 Java 的 Servlet 开发。&lt;/li&gt; &lt;li&gt;大学时的实习工作就是C# WinFrom 开发游戏盒子(PS: 当时老板骗我说做 C 开发)。&lt;/li&gt; &lt;li&gt;第一份正式工作是C++ Qt 的客户端开发，后面陆陆续续接触到了 iOS、Android、Electron、Creator 游戏开发等开发，也尝试帮兄弟部门开发过一个 Python Falsk 的运维系统。&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;  在工作后，由于产品的特性，所有相关的内容全是插件化的开发工作，包括插件开发以及设计插件机制。在李智慧老师的训练营中也输出过一份分享，&lt;a href="https://shimo.im/docs/jGpVRJWYdhP8cYtk" target="_blank"&gt;深入理解 Cocos Creator 的插件设计架构&lt;/a&gt;。&lt;/p&gt; &lt;h2&gt;学习总结&lt;/h2&gt; &lt;p&gt;对于华仔老师的课程，个人的理解就是&lt;/p&gt; &lt;ul&gt; &lt;li&gt;面向复杂度进行架构设计，通过拆分、叠加和冗余法则明确架构设计，以合适、简单和演进为基准，筛选出合适的架构设计方案。 &lt;img src="https://yeung.xin/upload/2021/08/r8avd2hmvmhdtq9riiiiadhb85.png" alt="" title="" /&gt;&lt;/li&gt; &lt;/ul&gt;</content:encoded>
      <pubDate>Sun, 08 Aug 2021 15:11:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营模块八作业</title>
      <link>https://yeung.xin/article/35</link>
      <content:encoded>&lt;p&gt;【作业内容】设计消息队列存储消息数据的 MySQL 表格 【作业要求】&lt;/p&gt; &lt;ol&gt; &lt;li&gt;包括表名、字段、索引；&lt;/li&gt; &lt;li&gt;用文字描述设计思路和理由，例如：为什么设计某个索引？&lt;/li&gt; &lt;li&gt;一页 PPT 即可。&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;【设计】&lt;/p&gt; &lt;p&gt;一、消息记录表&lt;/p&gt; &lt;pre&gt;&lt;code class="language-sql"&gt;DROP TABLE IF EXISTS `mq_record_xx`; CREATE TABLE `mq_record_xx` (   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增 id',   `msg_id` varchar(36) DEFAULT NULL COMMENT '消息 id，唯一键',   `producer_id` varchar(36) DEFAULT NULL COMMENT '生产者 id',   `content` varchar(4096) DEFAULT NULL COMMENT '消息内容',   `create_time` datetime DEFAULT NULL COMMENT '消息创建时间',   PRIMARY KEY (`id`),   UNIQUE KEY `msg_id`,   INDEX [index1] (username(36), content(4096))   ) ENGINE=InnoDB AUTO_INCREMENT=0; &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;常用 sql：&lt;/p&gt; &lt;pre&gt;&lt;code class="language-sql"&gt;select content from mq_record_xx where msgId = ? &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;二、消息队列表&lt;/p&gt; &lt;pre&gt;&lt;code class="language-sql"&gt;DROP TABLE IF EXISTS `mq_topic_xx`; CREATE TABLE `mq_topic_xx` (   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增 id',   `msg_id` varchar(36) DEFAULT NULL COMMENT '消息 id，唯一键',   `producer_id` varchar(36) DEFAULT NULL COMMENT '生产者 id',   `consumer_id` varchar(36) DEFAULT NULL COMMENT '消费者 id',   `create_time` datetime DEFAULT NULL COMMENT '消息创建时间',   `status` tinyint(1) NOT NULL DEAULT 0 COMMENT '状态，0 是未消费，1 是消费',   `consume_time` datetime DEFAULT NULL COMMENT '消费时间',   PRIMARY KEY (`id`),   UNIQUE KEY `msg_id`,   CONSTRAINT fk_msg_id FOREIGN KEY(msg_id) REFERENCES mq_record_xx(msg_id),   INDEX [index1] (consumer_id(36), status(1))   ) ENGINE=InnoDB AUTO_INCREMENT=0; &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;常用 sql：消费者获取下一条未被读取的消息&lt;/p&gt; &lt;pre&gt;&lt;code class="language-sql"&gt;select * from mq_topic_xxx where consumer_id = A and status  = 0 order by id asc limit 1 &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Wed, 14 Jul 2021 15:36:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营模块一作业</title>
      <link>https://yeung.xin/article/34</link>
      <content:encoded>&lt;ol&gt; &lt;li&gt;画出微信的业务架构图&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/07/u5fvcvncs4ic2pp0q70o1c3hjp.webp" alt="" title="" /&gt;&lt;/p&gt; &lt;ol start="2"&gt; &lt;li&gt;“学生管理系统”毕设架构设计&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;需求分析：&lt;/p&gt; &lt;pre&gt;&lt;code&gt;提供学生/课程/考试/权限功能 要求可以通过公网域名访问 能够支撑管理 1000 个学生 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;面向复杂度分析：&lt;/p&gt; &lt;pre&gt;&lt;code&gt;高性能：除了很少的时间段可能会有高访问量，大部分时段访问量不高，因此不需要重点考虑高性能。 高可用：重点考虑，数据不允许丢失，服务允许短时间停用，不允许长时间停。 扩展性：不太需要考虑架构扩展性，因为学生人数不会短时间内暴涨。新增功能也不会很复杂。 成本/安全：公网访问需考虑网络安全，项目团队经济一般因此需考虑成本。 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;备选方案一：&lt;/p&gt; &lt;pre&gt;&lt;code&gt;公网访问由学校现有 DNS 服务提供转发。 业务服务器实现学生管理系统的主要业务功能（学生/课程/考试/权限管理），由于大家都会 Java，采用 Java 技术栈开发实现功能，团队成员分模块开发。 业务服务器配置两台虚拟机实现应用的高可用。 为保证存储的高可用、数据不丢失，数据库采用虚拟机部署 MySQL 主备节点的方式存储数据。 为避免在高峰时段，数据库压力过大，采用 Redis 作为缓存减轻数据库压力，提升系统处理能力。同时为了避免 Redis 单点故障，以三台虚拟机配置 Redis 集群。 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/07/67ag52gnhcgm6pckjgk1mh3a6h.webp" alt="" title="" /&gt;&lt;/p&gt; &lt;p&gt;备选方案二：&lt;/p&gt; &lt;pre&gt;&lt;code&gt;公网访问由学校现有 DNS 服务提供转发。 业务服务器实现学生管理系统的主要业务功能（学生/课程/考试/权限管理），由于大家都会 Java，采用 Java 技术栈开发实现功能，团队成员分模块开发。 在业务服务器的功能模块中增加“网关功能”，提供网络安全和限流的功能。系统面向公网提供服务，所以需要考虑网络安全策略。请求会有瞬时高峰，因此可以采用限流策略，一定程度上可以去掉缓存。所有提交到业务服务器的请求都需要先经过网关模块。网关模块不独立部署服务器而集成在业务服务模块，主要是出于部署简单和降低成本的角度考虑。 业务服务器配置两台虚拟机双活实现应用的高可用。 为保证存储的高可用、数据不丢失，数据库采用虚拟机部署 MySQL 主备节点的方式存储数据。 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/07/vlr2ef333oimhpjps4lrqn0ube.webp" alt="" title="" /&gt;&lt;/p&gt; &lt;p&gt;备选方案三：&lt;/p&gt; &lt;pre&gt;&lt;code&gt;公网访问由学校现有 DNS 服务提供转发。 用前置的独立服务器实现“网关功能”，提供网络安全和限流的功能。系统面向公网提供服务，所以需要考虑网络安全策略。针对瞬时的请求高峰，可以灵活地配置限流策略。所有提交到内部应用区的的请求都需要先经过网关服务器。 网关功能由 PHP 高手实现，服务器配置两台虚拟机实现高可用。 被网关允许的请求向后转发给业务服务器处理之前，部署 Ngnix 服务器实现负载均衡，采用 Keepalived 技术部署两台虚拟机实现双活。 业务服务器实现学生管理系统的主要业务功能（学生/课程/考试/权限管理），由团队的另外两位成员以 Java 技术栈分模块开发。 业务服务器配置两台虚拟机双活实现应用的高可用。 为保证存储的高可用、数据不丢失，数据库采用虚拟机部署 MySQL 主备节点的方式存储数据。 为避免在高峰时段，数据库压力过大，采用 Redis 作为缓存减轻数据库压力，提升系统处理能力。同时为了避免 Redis 单点故障，以三台虚拟机配置 Redis 集群。 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/07/787o2h2dnqhc6ol4hi64u79pg2.webp" alt="" title="" /&gt;&lt;/p&gt; &lt;p&gt;最终方案：&lt;/p&gt; &lt;p&gt;方案二。&lt;/p&gt; &lt;p&gt;分别考虑架构设计三原则：合适、简单、演化。 合适：团队人员都有 Java 背景，所以虽然有 PHP 高手，还是优先考虑统一使用 Java 技术栈。团队经济条件一般，所以尽量避免采用方案三这种高成本的方案。 简单：方案三功能最齐全，但是最复杂；方案一和方案二功能差别不大，但方案二的架构更简单，运维压力更小。 演化：方案二虽然简单，但基本的功能需求都已经满足，且未来如果增加新的组件例如扩充到方案三的复杂程度也很容易，不需要对现有架构进行大改；如果未来没有增加组件的需求，只需要提高系统处理能力也很容易，复制业务服务器虚拟机节点即可。&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 07 Jul 2021 09:39:00 GMT</pubDate>
    </item>
    <item>
      <title>小马哥0期训练营总结</title>
      <link>https://yeung.xin/article/33</link>
      <content:encoded>&lt;p&gt;项目模块:“用户注册”、“用户登录”以及“用户管理”等模块构建 规范运用:使用Java SE和Java EE技术栈实现业务需求 页面渲染:基于JSP、EL以及JSTL技术实现Java Web服务端视图渲染 服务通讯:基于JAX-RS实现同步服务通讯;基于JMS提供异步服务通讯能力&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;熟悉了 JAX-RS 规范&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;质量保证: codebase 平台工具实现代码变更通知、代码分析等 监控管理: Java JMX (Java 管理扩展)对关键服务进行监管，以及与不同类型的MBean使用场景 日志管理:使用Java Logging作为系统日志框架，理解其整体设计和架构 配置管理:使用Java EE配置管理，整合Apache Commons Configuration实现配置抽象&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;熟悉了 Java JMX 监控体系以及配套工具的使用，了解了 Java 自带的配置管理系统&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;负载均衡:使用多Java EE容器对等部署均衡服务器压力 API网关:基于Servlet异步技术实现高性能API网关 单点登录:通过JavaEE容器Session复制等手段提供单点登录 性能压测:通过JDK动态代理和Servlet Filter方式，对项目关键服务进行性能埋点，评估API性能指标 性能提升:结合压力测试结果，运用Java Caching整合Redis 以及异步技术，提升系统性能 访问控制:使用Java EE容器认证和授权架构实现访问控制 Web安全: SQL注入、CSRF、XSS、HSTS等攻击手段，结合Java Security提升安全性能&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;了解了 Servlet 规范以及常用的安全防范，熟悉了 Spring Security 的使用&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;数据存储:使用MyBatis和Spring Data JPA重构项目JDBC封装实现 视图渲染:基于Spring Web MVC重构业务实现，并复用JSP、EL以及JSTL页面 服务通讯:基于Spring Web MVC适配JAX- _RS注解，使用Spring JMS重构项目遗留JMS实现&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;熟悉了常用的 ORM 工具以及 JDBC 的封装思想，熟悉了 Spring MVC 的架构&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;测试用例:基于Spring Testing重构项目单元测试和集成测试 服务监控:基于Spring JMX重构项目中MBean的管理，简化JMX开发的实现细节。 日志管理:使用Spring Logging API替换现有的Java Logging实现 配置管理:基于Spring外部化配置重构当前项目的配置抽象实现。&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;了解了 Spring 的抽象能力以及对 JMX 的扩展，熟悉了 Spring 的配置系统&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;负载均衡:利用Nginx作为反向代理服务器，更替Java- Based Web Server实现 单点登录:使用Spring Session升级项目遗留的单点登录实现 API网关:基于Nginx构建系统API网关，利用Spring WebFlux实现业务API网关 性能压测:使用Spring AOP替换项目性能埋点实现，并重新评估重构后的API性能指标 性能提升:使用Spring Caching抽象重构Java Caching标准实现，运用Nginx实现动态内容和静态内容分离&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;数据 Spring Cache&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;服务通讯:使用Apache Dubbo替换项目部分REST API同步服务，使用Spring Kafka重构异步服务通讯 数据存储:使用Apache ShardingSphere增加数据库分库分表能力 服务注册与发现:理解Dubbo Registry SPI以及不同的基础设施实现&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;熟悉 Dubbo 注册中心的实现&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;负载均衡:理解Dubbo LoadBalance SPI设计以及各种不同的实现，结合项目实际情况，合理选型 服务路由:理解Dubbo Route SPI设计与实现，并模拟实现多区域用户路由到不同的Dubbo服务机房 配置管理:使用Nacos Spring提升分布式动态配置 服务监控:使用Apache Dubbo Admin提升项目DevOps能力&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;了解 Alibaba Dubbo 的底层原理与 LoadBlance 的实现&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;服务高可用:基于Netflix Hystrix和Alibaba Sentinel实现Web服务和Dubbo服务熔断、降级和限流 安全和控制:基于Spring Security提升Dubbo服务认证和授权能力 全链路压测:基于JMeter技术，再结合库表设计，实现平台业务全链路压测 灰度发布:基于Nginx插件提供平台灰度发布的能力&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;熟悉了熔断、限流的设计思想以及实现方式&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;数据存储: Spring Boot Starter重构MyBatis和Apache ShardingSphere实现 视图渲染:使用Vue.js替换Java Web Server服务端视图渲染 服务通讯:使用Dubbo Spring Cloud重构同步服务，基于Spring Cloud Stream重新实现异步服务&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;了解了 Dubbo 与 Spring 整合的思想以及 Spring Cloud Stream 对异步消息系统的抽象整合&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;测试用例:学习并使用Spring Boot Testing重构集成测试 负载均衡:使用Spring Cloud L oadBalancer抽象重构REST负载均衡 服务监控:理解Spring Boot Actuator体系，使用Spring Boot Admin提升Spring Boot应用运维能力 配置管理:基于Spring Cloud Config实现动态分布式配置 日志管理:基于Spring Cloud Confng实现分布式动态日志管理&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;熟悉了分布式配置以及分布日志&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;访问控制:使用Spring Security OAuth提升认证和授权架构，实现访问控制 Web安全:使用Spring Security Starter配置化实现CSRF、XSS、HSTS API网关:使用Spring Cloud Gateway重构Spring WebFlux实现的业务API网关，使用Dubbo Spring Cloud实现Dubbo服务网关 服务高可用:基于Spring Cloud Circuit Breaker重构服务熔断实现，并结合Spring Cloud Alibaba Sentinel实现服务限流和熔断 分布式跟踪:理解Dapper分布式跟踪理论，使用Spring Cloud Sleuth实现分布式应用服务跟踪 性能压测:使用Spring AOP替换项目性能埋点实现，并重新评估重构后的API性能指标; 性能提升:使用Spring Caching抽象重构Java Caching标准实现，运用Nginx 实现动态内容和静态内容分离，使用Varnish提升Web整体性能&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;熟悉 Spring Security 访问控制，熟悉 Spring Webflux，熟悉 Spring Cloud 体系，了解了分布式追踪系统&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;容器化技术:掌握以Docker为代表的容器化技术，并介绍不同的容器引擎 Kubernetes:理解Kubernetes架构、Pod和容器设计模式、应用编排与管理等 服务注册与发现:使用Spring Cloud Kubernetes替换现有Spring Cloud传统实现，理解Kubernetes API Server架构 服务通讯:使用gRPC升级Dubbo中的传输协议，利用RSocket实现Dubbo异步服务通讯(Reactive)&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;熟悉容器化开发&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;运维建设:构建企业Docker镜像仓库，打造以Docker为基础的CI/CD环境 负载均衡:理解Kubernetes Ingress及负载均衡解决方法 服务监控: (可观测性)理解livenessProbes、readinessProbes、 容器日志收集，使用Prometheus和Grafana的监控系统实践 配置管理:基于Spring Cloud Kubernetes Confng更替已有配置实现，理解Kubernetes ConfigMaps 日志管理:使用Kubernetes平台日志管理方法&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;掌握常用的容器开发技巧&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt; &lt;p&gt;访问控制:了解Kubernetes中API访问安全机制、认证和授权，逐步替代现有实现 API网关:使用Istio Ingress升级API网关实现 服务高可用:使用Istio 替换Spring Cloud Circuit Breaker实现 分布式跟踪:使用Jaeger替换Spring Cloud Sleuth实现 性能提升:使用GraalVM提升Java微服务性能&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h2&gt;了解 Java Native、熟悉 k8s 系统以及 istio&lt;/h2&gt; &lt;/li&gt; &lt;/ul&gt;</content:encoded>
      <pubDate>Wed, 07 Jul 2021 03:21:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营模块七作业</title>
      <link>https://yeung.xin/article/32</link>
      <content:encoded>&lt;p&gt;【背景】&lt;/p&gt; &lt;p&gt;假设现在决定要实现王者荣耀里面的商城的异地多活架构，请你分析设计一下。&lt;/p&gt; &lt;p&gt;【作业要求】&lt;/p&gt; &lt;pre&gt;&lt;code&gt;分析王者荣耀商城的业务特点，设计其异地多活架构； 按照模块 7 第 5 课的方法来设计异地多活架构。 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;【提示】&lt;/p&gt; &lt;pre&gt;&lt;code&gt;王者荣耀的商城是虚拟物品商城，和淘宝这种实物电商有两个很大的区别，注意识别出来； 用户要先调用微信钱包或者 QQ 钱包充值点券，然后在商城里面用点券支付； 用户买英雄和皮肤的时候同样的英雄和皮肤只能买 1 个，不能重复购买； 用户买鲜花、改名卡之类的道具可以买多个； 分析步骤参考模块 7 第 6 课的案例。 &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;业务背景&lt;/h1&gt; &lt;pre&gt;&lt;code&gt;2020.11 月公布数据，全年日均活跃 1 亿，注册玩家数 6 亿，最高同时在线 100 万。 &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;关键业务约束&lt;/h1&gt; &lt;pre&gt;&lt;code&gt;用户登录后才能使用商城系统； 用户要先调用微信钱包或者 QQ 钱包充值点券，然后在商城里面用点券支付； 王者荣耀商城的物品主要包括碎片、英雄、皮肤、夺宝、礼物等虚拟物品，无需考虑库存和物流； 用户买英雄和皮肤的时候同样的英雄和皮肤只能买 1 个，不能重复购买； 用户买鲜花、改名卡道具可以买多个。 &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;业务分级&lt;/h1&gt; &lt;pre&gt;&lt;code&gt;王者荣耀商城涉及核心业务：购买、充值 &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;数据分类&lt;/h1&gt; &lt;pre&gt;&lt;code&gt;RoleID：从第三方(QQ 和微信)登录或者具有全局唯一不变性； 商品信息：修改较少，全局数据 点券：与用户 RoleID 关联，全局强一致 支付信息：依赖 QQ 钱包和微信钱包 商品信息：根据不用商品分类有不同的购买限制 &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;数据同步&lt;/h1&gt; &lt;pre&gt;&lt;code&gt;1、RoleID 和区服对应关系只会新增，不会修改，数据库同步即可 2、点券 ID 在上一步中根据 RoleID 和区服 ID 通过算法自动生成，全局唯一，无需同步 3、点券余额需要保证分布式一致性，使用数据库同步 4、点券充值记录只会新增，不会修改，使用数据库同步 5、订单 ID 每次新建，不会修改，通过数据库同步 6、订单信息每次新建，不会修改，通过数据库同步，同时由于包含全局唯一的订单 ID，也可通过消息队列同步 7、商品 ID 每次新建，全局唯一，不会修改，通过数据库同步 8、商品信息存在修改，通过数据库同步 &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;异常处理&lt;/h1&gt; &lt;pre&gt;&lt;code&gt;【点券充值】点券数量不对，或者未到账，客户介入，事后给予点券补偿 【购买】购买后没有同步到异地机房，玩家看不到买的东西，客服介入，给予点券补偿。 &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;异地多活架构图&lt;/h1&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/07/oq1cl7d4tsiv4qcn2lr86llp89.webp" alt="" title="" /&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Sun, 04 Jul 2021 16:05:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营模块六作业</title>
      <link>https://yeung.xin/article/31</link>
      <content:encoded>&lt;p&gt;【背景】&lt;/p&gt; &lt;p&gt;假设你现在是一个创业公司的 CTO，开发团队大约 30 人左右，包括 5 个前端和 25 个后端，后端开发人员全部都是 Java，现在你们准备从 0 开始做一个小程序电商业务，请你设计微服务拆分的架构以及微服务基础设施选型。&lt;/p&gt; &lt;p&gt;【作业要求】&lt;/p&gt; &lt;pre&gt;&lt;code&gt;需要明确服务拆分思路，并且将拆分后的系统架构图画出来； 需要明确微服务基础设施选型思路，并选择一个微服务框架。 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;【提示】&lt;/p&gt; &lt;pre&gt;&lt;code&gt;需要应用三个火枪手原则； 需要选择拆分方式； 需要选择微服务框架的模式。 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;框架模式&lt;/p&gt; &lt;pre&gt;&lt;code&gt;由于团队都是 Java 程序员，故而可以选择 嵌入 SDK 式的微服务框架模式，在这里选择 Spring Cloud Alibaba + Dubbo 的架构 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;服务拆分&lt;/p&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/06/qf6nap1tuqh8hpd8k28nn3lv06.jpg" alt="" title="" /&gt;&lt;/p&gt; &lt;p&gt;责任划分&lt;/p&gt; &lt;pre&gt;&lt;code&gt;划分15个后端进行业务开发 鉴权认证以及微服务平台的搭建交给另外5个后端 分出2个前端进行小程序端的开发 另外3个进行商家以及管理后台等后端框架的前端开发工作 &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Sun, 20 Jun 2021 12:07:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营模块五作业</title>
      <link>https://yeung.xin/article/30</link>
      <content:encoded>&lt;h2&gt;架构实战营模块五作业&lt;/h2&gt; &lt;h3&gt;基于模块 5 第 6 课的微博实战案例，分析“微博评论”这个核心场景的业务特性，然后设计其高性能高可用计算架构，包括但不限于如下内容：&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;1）计算性能预估（不需要考虑存储性能）&lt;/li&gt; &lt;li&gt;2）非热点事件时的高性能计算架构，需要考虑是否要拆分独立的服务&lt;/li&gt; &lt;li&gt;3）热点事件时的高可用计算架构&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;计算性能预估&lt;/h3&gt; &lt;pre&gt;&lt;code&gt;2020 年 9 月日活 2.24 亿，发微博评论的频率应该介于发微博和看微博之间，我们假设平均一条微博会有 10 条评论，则每天发评论的总次数为 2.5 亿 x10 = 25 亿；  一般用户并不会刷到每条微博都会去看评论，因此看评论的请求量应该是大于发评论而小于看微博，假设一条微博的查看评论请求为 50，则每天看评论的总次数为 2.5 亿 x50 = 125 亿；  大部分人发评论和看评论的时间段分布与发微博时间段基本重合，即高峰时段的四个小时占总量的 60%，则：  发评论的 TPS 峰值计算：25 亿 x 60% / (4x3600) = 100K/s  看评论的 QPS 峰值计算：125 亿 x 60% / (4x3600) = 500K/s &lt;/code&gt;&lt;/pre&gt; &lt;h3&gt;非热点&lt;/h3&gt; &lt;h4&gt;发评论&lt;/h4&gt; &lt;pre&gt;&lt;code&gt;发评论相比发微博来说业务上的时效要求低一些，不需要强一致性，因此可以采用客户端 APP 缓存+服务端写缓冲的方式。  用户量过亿，采用多级负载均衡架构，覆盖 DNS-&amp;gt;LVS-&amp;gt;Nginx-&amp;gt;网关的多级负载均衡  业务服务器数量估算：服务端采用消息队列写缓冲的形式，单笔写请求变成异步，耗时约 30ms，单台 32 核服务器 TPS 约为 1000。按前述业务估计 100K/s 需要 100 台服务器，加上 20%冗余，约需要 120 台服务器。 &lt;/code&gt;&lt;/pre&gt; &lt;h4&gt;读评论&lt;/h4&gt; &lt;pre&gt;&lt;code&gt;看评论也是典型的读场景，适合用缓存架构，由于每天请求量达到 125 亿，需要使用多级缓存架构，尤其是 CDN 缓存。  负载均衡策略与发评论相同  业务服务器数量估算：假设 CDN 承载 90%流量，则服务器需处理的读 QPS 为 500K/sx10%=50K/s,读评论的处理逻辑较简单，主要是读缓存系统，因此可机器数量为 50 台，取 20%冗余，最终机器数量为 60 台。  读评论需要考虑因果一致性 &lt;/code&gt;&lt;/pre&gt; &lt;h3&gt;热点情况&lt;/h3&gt; &lt;h4&gt;发评论&lt;/h4&gt; &lt;pre&gt;&lt;code&gt;热点事件的微博评论相比微博自身时效性要求可以低一些，因此可以考虑对热点事件微博的评论进行限流，最好是采用漏桶算法。原有高性能架构设计中采用了消息队列写缓冲的方式，同时也达到了限流的目的。 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/06/uskqje29qih9rpvk2k4ij9v257.png" alt="alt" title="alt" /&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Sun, 06 Jun 2021 15:55:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营模块四作业</title>
      <link>https://yeung.xin/article/29</link>
      <content:encoded>&lt;p&gt;架构实战营模块四作业 设计千万级学生管理系统的考试试卷存储方案&lt;/p&gt; &lt;p&gt;** 【作业要求】**&lt;/p&gt; &lt;p&gt;基于模块 4 第 6 课的估算结果和 Redis sentinel 的初步方案设计，完善考试试卷存储方案，具体包括： 1）完善 Redis 的数据结构设计，明确具体使用哪种 Redis 数据结构 2）设计具体的读写流程（可以文字描述也可以序列图描述，序列图要有文字辅助说明） 3）对照模块 4 第 6 课的性能估算结果，计算 Redis sentinel 集群的服务器数量和性能&lt;/p&gt; &lt;p&gt;** 【提示】** 性能可以有一定冗余 如果对 Redis sentinel 不熟悉，请参考官方文档： https://redis.io/topics/sentinel&lt;/p&gt; &lt;p&gt;** 【作业】 ** 1） Redis 的数据结构设计 使用 String 字符串类型，原因如下 一、单张试卷内容基本不会太大，图片可以存储图片地址； 二、每个试卷都是独立的，试卷之间没有任何关系； 三、试卷 KEY 设计:ex_学校代码_院系代码_课程代码_年_学期&lt;/p&gt; &lt;p&gt;2） 具体的读写流程&lt;/p&gt; &lt;p&gt;试卷写入： 1、老师登录管理系统，并选择课程、学期再上传试卷； 2、根据课程关联所属的院校、院系信息并根据当前时间计算学年、学期； 3、打包试卷并包含院校、院系、课程、学年、学期等信息发送给试卷系统； 4、试卷系统根据 3 的基础信息生成 key 并写入到 Redis&lt;/p&gt; &lt;p&gt;试卷读取： 1、学生登录管理系统，选择考试的课程； 2、根据用户选择的课程以及时间关联院校、院系、学年、学期等信息； 3、从 Redis 读取信息&lt;/p&gt; &lt;p&gt;3） 对照模块 4 第 6 课的性能估算结果，计算 Redis sentinel 集群的服务器数量和性能 理论上 redis 单机就可以支持 5W/QPS 读取，300/TPS 写入，采用 1 主 2 从部署方式，共计需要 3 台服务器，redis 集群单机内存 32G 即可满足需求；&lt;/p&gt;</content:encoded>
      <pubDate>Sun, 23 May 2021 14:33:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营第三周总结</title>
      <link>https://yeung.xin/article/28</link>
      <content:encoded>&lt;h1&gt;1、架构师的定位&lt;/h1&gt; &lt;ul&gt; &lt;li&gt;架构师是业务和技术之前的桥梁&lt;/li&gt; &lt;li&gt;架构师不能只顾技术不懂业务&lt;/li&gt; &lt;li&gt;架构师很容易两头不太好&lt;/li&gt; &lt;/ul&gt; &lt;h1&gt;2、架构师的三个核心能力&lt;/h1&gt; &lt;ol&gt; &lt;li&gt;业务理解能力、技术能力、沟通能力&lt;/li&gt; &lt;li&gt;技术深度、技术宽度、技术广度&lt;/li&gt; &lt;li&gt;设计理念，说服能力、决断能力&lt;/li&gt; &lt;/ol&gt; &lt;h1&gt;3、架构师的三个关键思维&lt;/h1&gt; &lt;ol&gt; &lt;li&gt;确定性思维：消除模糊、不确定的说法和信息&lt;/li&gt; &lt;li&gt;创造性思维：通过排列组合创新，得到更多的方案&lt;/li&gt; &lt;li&gt;系统思考，有逻辑和推导过程&lt;/li&gt; &lt;/ol&gt; &lt;h1&gt;4、架构师的主要职责&lt;/h1&gt; &lt;h2&gt;1、前期：&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;任务：澄清不确定性、识别复杂性&lt;/li&gt; &lt;li&gt;方式：与业务方交流、与利益干系人交流&lt;/li&gt; &lt;li&gt;输出：业务架构图、核心场景流程&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;2、中期：&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;任务：设备备选方案、选择备选方法&lt;/li&gt; &lt;li&gt;方式：架构小组讨论、写文档、汇报备选方案&lt;/li&gt; &lt;li&gt;输出：备选方案、方案评估、方案汇报&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;3、后期：&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;任务：细化架构、完善架构&lt;/li&gt; &lt;li&gt;方式：写文档、架构宣讲&lt;/li&gt; &lt;li&gt;输出：最终的架构文档&lt;/li&gt; &lt;/ul&gt;</content:encoded>
      <pubDate>Sun, 09 May 2021 15:14:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营第三周作业</title>
      <link>https://yeung.xin/article/27</link>
      <content:encoded>&lt;h1&gt;1. 业务背景&lt;/h1&gt; &lt;h2&gt;【新版本发布】&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;游戏厂家更新游戏版本后，运营人员获取最新的游戏包，更新版本信息，然后上传包 到包管理系统打测试包，运营人员进行基本测试。运营子系统通知论坛有新的包将要 发布，进行预热。&lt;/li&gt; &lt;li&gt;测试完成后，运营管理子系统要通知包管理系统进行打包&lt;/li&gt; &lt;li&gt;游戏准点正式发布的时候，运营子系统要通知 App、Web 站点等即时更新到新版本&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;【玩家充钱】&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;玩家进行充值，充值完成后充值子系统通知 VIP 子系统;&lt;/li&gt; &lt;li&gt;VIP 子系统判断玩家等级，达到 VIP 后，等级子系统要通知福利子系统进行奖品发放，要通知客服子系统安排专属服务人员，要通知商品子系统进行商品打折处理等级子系统的开发人员也是不胜其烦。&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;随着游戏业务发展很快，业务上拆分的子系统越来越多，由此带来几个明显的系统问题：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;性能问题：当玩家充值成功后，会依次通知其他的子系统，而这个过程是同步调用，导致系统响应时间很长。&lt;/li&gt; &lt;li&gt;耦合问题：系统之间不同程度的依赖关系，会导致牵一发而动全身，比如当一个系统接口变动时，依赖这个系统的接口的系统都需要作相应的变动。&lt;/li&gt; &lt;li&gt;效率问题：每个子系统提供的接口参数和实现都有一些细微的差别，导致每次都需要重新设计接口和联调接口，开发团队和测试团队花费了许多重复工作量。&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;基于以上背景，我们需要引入消息队列进行系统解耦，将目前的同步调用改为异步通知。&lt;/p&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/05/382frgq97ej2kr575b5b5nu7l4.png" alt="" title="" /&gt;&lt;/p&gt; &lt;h1&gt;2. 约束和限制&lt;/h1&gt; &lt;ul&gt; &lt;li&gt;中间件团队规模不大，大约 6 人左右。&lt;/li&gt; &lt;li&gt;中间件团队熟悉 Java 语言。&lt;/li&gt; &lt;li&gt;开发平台是 Linux，数据库是 MySQL。&lt;/li&gt; &lt;li&gt;目前整个业务系统是单机房部署，没有双机房。&lt;/li&gt; &lt;li&gt;系统的需要嵌入到已有运维体系，且维护成本不能太高&lt;/li&gt; &lt;li&gt;需要保证可用性，丢消息对业务影响严重&lt;/li&gt; &lt;/ul&gt; &lt;h1&gt;3. 总体架构&lt;/h1&gt; &lt;h2&gt;3.1 架构分析&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;可维护性：各种维护操作要方便，例如收发消息情况、权限控制、上下线等&lt;/li&gt; &lt;li&gt;高性能：不需要高性能，游戏新版本发布和 VIP 充值的消息并不多&lt;/li&gt; &lt;li&gt;高可用：需要，游戏版本发布和 VIP 都是高优先级业务&lt;/li&gt; &lt;li&gt;可扩展：不需要，消息队列的功能基本明确，无需扩展&lt;/li&gt; &lt;li&gt;成本：开发投入人力和时间不能太长&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;综合来看消息队列需要可维护性，高可用，以及较低的开发投入成本，由于游戏新版本发布和 VIP 充值的消息并不多，消息队列的功能基本明确，所以不需要高新能和较高的可扩展性。&lt;/p&gt; &lt;h2&gt;3.2 总体架构&lt;/h2&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/05/2l9o7t56e6h1bqisg8s9tuthk5.png" alt="" title="" /&gt;&lt;/p&gt; &lt;p&gt;描述：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Java 语言编写消息队列服务器&lt;/li&gt; &lt;li&gt;消息存储采用 MySQL&lt;/li&gt; &lt;li&gt;SDK 轮询服务器进行消息写入&lt;/li&gt; &lt;li&gt;SDK 轮询服务器进行消息读取&lt;/li&gt; &lt;li&gt;MySQL 双机保证消息尽量不丢&lt;/li&gt; &lt;li&gt;使用 Netty 自定义消息格式，并且支持 HTTP 接口&lt;/li&gt; &lt;/ul&gt; &lt;h1&gt;4. 详细设计&lt;/h1&gt; &lt;h2&gt;4.1 核心功能&lt;/h2&gt; &lt;h3&gt;4.1.1 消息发布流程&lt;/h3&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/05/4sp9petjeag92onl8u0jrdvg2a.png" alt="" title="" /&gt;&lt;/p&gt; &lt;ol&gt; &lt;li&gt;消息生产者（Message Produce Server）通过 SDK 从注册中心（Queue Manager）中获取已经注册的可用的消息队列服务器（Queue Server）的地址列表。&lt;/li&gt; &lt;li&gt;消息生产者（Message Prodecu Server）通过 SDK 负载均衡策略（Round Robin）选择一台消息主服务器，发送消息写请求。&lt;/li&gt; &lt;li&gt;消息队列服务器（Queue Server）接受到请求，将消息写入到数据库中，并响应结果信息。&lt;/li&gt; &lt;li&gt;消息服务器主节点处理读写请求，从节点处理读请求。&lt;/li&gt; &lt;/ol&gt; &lt;h3&gt;4.1.2 消息读取流程&lt;/h3&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/05/518huqs814g5mq0sk3p885vcpg.png" alt="" title="" /&gt;&lt;/p&gt; &lt;ol&gt; &lt;li&gt;消息消费者（Message Consume Server）通过 SDK 从消息管理系统（Queue Manager）中获取已经注册的可用的消息队列服务器（Queue Server）的地址列表。&lt;/li&gt; &lt;li&gt;消息消费者（Message Consume Server）通过 SDK 负载均衡策略（Round Robin），向消息服务器发起消息读取请求。&lt;/li&gt; &lt;li&gt;消息消费者（Message Consume Server）消费消息完成后，消息队列更新消息的消费状态，同时，异步刷新数据库中的消息状态。&lt;/li&gt; &lt;/ol&gt; &lt;h2&gt;4.2 关键设计&lt;/h2&gt; &lt;h3&gt;4.2.1 消息发送可靠性&lt;/h3&gt; &lt;p&gt;业务服务器中嵌入消息队列系统提供的 SDK，SDK 支持轮询发送消息，当某个分组的主服务器无法发送消息时，SDK 挑选下一个分组主服务器重发消息，依次尝试所有主服务器直到发送成功；如果全部主服务器都无法发送，SDK 可以缓存消息，也可以直接丢弃消息，具体策略可以在启动 SDK 的时候通过配置指定。如果 SDK 缓存了一些消息未发送，此时恰好业务服务器又重启，则所有缓存的消息将永久丢失，这种情况 SDK 不做处理，业务方需要针对某些非常关键的消息自己实现永久存储的功能。&lt;/p&gt; &lt;h3&gt;4.2.2 消息存储可靠性&lt;/h3&gt; &lt;p&gt;消息存储在 MySQL 中，每个分组有一主一备两台 MySQL 服务器，MySQL 服务器之间复制消息以保证消息存储高可用。如果主备间出现复制延迟，恰好此时 MySQL 主服务器宕机导致数据无法恢复，则部分消息会永久丢失，这种情况不做针对性设计，DBA 需要对主备间的复制延迟进行监控，当复制延迟超过 30 秒的时候需要及时告警并进行处理。&lt;/p&gt; &lt;h3&gt;4.2.3 消息如何存储&lt;/h3&gt; &lt;p&gt;每个消息队列对应一个 MySQL 表，消息队列名就是表名，表结构设计为每一个消息用自增主键做 id，每一个消息的内容就是数据库表的一列。建表语句如下：&lt;/p&gt; &lt;pre&gt;&lt;code class="language-sql"&gt;CREATE TABLE `message_queue_name` (  `message_id` int(11) NOT NULL AUTO_INCREMENT,  `message_header` varchar(256) NOT NULL,  `message_body` text NOT NULL,  `message_property` varchar(256) NOT NULL,  PRIMARY KEY (`message_id`), ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 &lt;/code&gt;&lt;/pre&gt; &lt;h2&gt;4.3 设计规范&lt;/h2&gt; &lt;h3&gt;4.3.1 消息服务端&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;服务器基于 Netty 开发，采用 Reactor 网络模型&lt;/li&gt; &lt;li&gt;两台服务器组成一个 sharding，整个系统可以多个 sharding，每个 sharding 包含一主一从两台服务器&lt;/li&gt; &lt;li&gt;主服务器提供消息读写操作，从服务器只提供消息读取操作&lt;/li&gt; &lt;li&gt;服务器基于 KeepAlived 进行主从切换&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;4.3.2 消息客户端&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;客户端采用 Netty 实现&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;4.3.3 消息存储&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;采用 MySQL 主从同步&lt;/li&gt; &lt;li&gt;每个消息队列对应一个表&lt;/li&gt; &lt;li&gt;直接用 MySQL 的主从复制来实现数据复制&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;4.3.4 交互协议&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;客户端与服务端采用 TCP 连接，采用 protobuf 传递数据&lt;/li&gt; &lt;li&gt;为了兼容非 Java 系统，服务端同时提供 HTTP 接口&lt;/li&gt; &lt;/ul&gt; &lt;h1&gt;5. 质量设计&lt;/h1&gt; &lt;h2&gt;5.1 消息队列管理后台&lt;/h2&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2021/05/s18it8ql9eh6noenuobff1nhr1.png" alt="" title="" /&gt;&lt;/p&gt; &lt;h1&gt;6. 演进规则&lt;/h1&gt; &lt;h2&gt;6.1 消息队列一期&lt;/h2&gt; &lt;p&gt;完成消息发送流程、消息消费流程的功能性开发和测试，提供 SDK 给各个子系统做业务联调。&lt;/p&gt; &lt;h2&gt;6.2 消息队列二期&lt;/h2&gt; &lt;p&gt;完成主从切换流程、消息发送可靠性、消息存储可靠性的开发和测试，在保障整体 SLA 的情况下，提供给不强依赖消息队列管理后台的子系统使用。&lt;/p&gt; &lt;h2&gt;6.3 消息队列二期&lt;/h2&gt; &lt;p&gt;完成消息队列管理后台，保证系统的可测试性、可维护性、可观测性，提供给所有需要消息队列系统的子系统线上正式使用。&lt;/p&gt;</content:encoded>
      <pubDate>Sun, 09 May 2021 15:13:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营第二周总结</title>
      <link>https://yeung.xin/article/26</link>
      <content:encoded>&lt;p&gt;一、可扩展架构的设计 1、架构设计复杂度模型： 业务复杂度：业务固有的复杂度，主要体现为难以理解、难以扩展、例如业务数量多(微信)、业 务流程长(支付宝)、业务之间关系复杂 (例如ERP)。 质量付制度：高性能、高可用、成本、安全等质量属性的要求。 业务复杂度和质量复杂度是正交的 2、可扩展复杂度模型 定义：可扩展，可伸缩 模型：架构、应用、代码可扩展 3、拆分：关键点是平衡 4、封装：权衡变化&lt;/p&gt; &lt;p&gt;二、高性能架构的设计 1、单机高性能：单机优化 2、集群高性能：拆分 三、高可用架构的设计 1、计算高可用： 任务分配：将任务分配给多个服务器执行（负载均衡） 任务分解：不同的任务交给不同的服务器执行（服务拆分） 2、存储高可用 分布式，多节点存储 四、架构设计的质量度量 1、低成本：资源成本 2、安全性：架构安全、业务安全 3、可测试性/可维护性/可观测性：系统测试以及运维&lt;/p&gt;</content:encoded>
      <pubDate>Sat, 17 Apr 2021 15:31:00 GMT</pubDate>
    </item>
    <item>
      <title>架构实战营第二周作业</title>
      <link>https://yeung.xin/article/25</link>
      <content:encoded>&lt;p&gt;架构实战营第二周作业下载地址 https://yeung.xin/upload/2021/04/49iiq3g972jauqievgo4r5ju9l.pptx&lt;/p&gt;</content:encoded>
      <pubDate>Sat, 17 Apr 2021 15:30:00 GMT</pubDate>
    </item>
    <item>
      <title>解决 GitHub 访问慢，图片无法显示的问题</title>
      <link>https://yeung.xin/article/24</link>
      <content:encoded>&lt;h2&gt;&lt;code&gt;hosts&lt;/code&gt; 文件中添加一下配置&lt;/h2&gt; &lt;p&gt;&lt;code&gt;hosts&lt;/code&gt; 文件路径&lt;/p&gt; &lt;p&gt;&lt;code&gt;mac: /etc/hosts&lt;/code&gt;&lt;/p&gt; &lt;p&gt;&lt;code&gt;win: C:\\WINDOWS\\system32\\drivers\etc\hosts&lt;/code&gt;&lt;/p&gt; &lt;pre&gt;&lt;code class="language-hosts"&gt;# GitHub Start 140.82.113.4      github.com 140.82.114.4      github.com 140.82.113.4      gist.github.com 140.82.113.6      api.github.com 185.199.108.153   assets-cdn.github.com 185.199.109.153   assets-cdn.github.com 185.199.110.153   assets-cdn.github.com 185.199.111.153   assets-cdn.github.com 199.232.96.133    raw.githubusercontent.com 199.232.96.133    gist.githubusercontent.com 199.232.96.133    cloud.githubusercontent.com 199.232.96.133    camo.githubusercontent.com 199.232.96.133    avatars.githubusercontent.com 199.232.96.133    avatars0.githubusercontent.com 199.232.96.133    avatars1.githubusercontent.com 199.232.96.133    avatars2.githubusercontent.com 199.232.96.133    avatars3.githubusercontent.com 199.232.96.133    avatars4.githubusercontent.com 199.232.96.133    avatars5.githubusercontent.com 199.232.96.133    avatars6.githubusercontent.com 199.232.96.133    avatars7.githubusercontent.com 199.232.96.133    avatars8.githubusercontent.com 199.232.96.133    user-images.githubusercontent.com # GitHub End &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Thu, 18 Mar 2021 02:16:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第十二周总结</title>
      <link>https://yeung.xin/article/23</link>
      <content:encoded>&lt;p&gt;大数据的特点&lt;/p&gt; &lt;p&gt;Hadoop与Spark Hadoop 是一种分布式计算平台，用Java编写，可运行在Linux、Windows以及类Unix系统上。包括两个核心技术，HDFS和Mapreduce。HDFS实现数据的分布式存储，MapReduce实现数据的分布式计算（通过Map和reduce两个函数实现）。&lt;/p&gt; &lt;pre&gt;&lt;code&gt;Spark 比 MapReduce 快，前者使用内存存储中间结果，后者使用HDFS。 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;数据库类型&lt;/p&gt; &lt;pre&gt;&lt;code&gt;关系型数据库是根据表间的索引建立关系，因此叫关系型数据库。代表产品有Oracle、MySQL、DB2。 NoSQL非关系型数据库，四种存储类型： 1、键值； 2、文档（JSON格式）； 3、列存储； 4、图数据库。 代表产品有：Redis；CouchDB、Mongodb；HBase；Neo4J。 &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Thu, 03 Sep 2020 01:18:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第十二周作业</title>
      <link>https://yeung.xin/article/22</link>
      <content:encoded>&lt;h3&gt;在你所在的公司（行业，领域）内，正在用大数据处理哪些业务？可以用大数据实现哪些价值？&lt;/h3&gt; &lt;p&gt;我们公司是做游戏引擎开发的，公司有个产品是 Cocos Analytics， 主要用途有 实时采集数据&lt;/p&gt; &lt;pre&gt;&lt;code&gt;实时采集数据 精准了解各时段数据变化 即时监测产品运营趋势 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;用户分析&lt;/p&gt; &lt;pre&gt;&lt;code&gt;丰富精细的用户数据指标 了解用户每日行为变化 深入有效地掌握游戏用户状态 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;留存分析&lt;/p&gt; &lt;pre&gt;&lt;code&gt;通过新增留存和活跃留存 多维度跟踪分析 了解用户回访率和产品粘性 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;营收分析&lt;/p&gt; &lt;pre&gt;&lt;code&gt;营收等级划分 精准了解 TOP 消费群体及消费能力 精准营销拉动收入 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;渠道追踪&lt;/p&gt; &lt;pre&gt;&lt;code&gt;追踪用户来源 监测不同渠道用户和留存状况 更加全面、快速的分析出投资回报率 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;自定义事件&lt;/p&gt; &lt;pre&gt;&lt;code&gt;路径分析、漏斗分析、分布分析 策略性设计事件和埋点 掌握产品真实动态信息 &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Thu, 03 Sep 2020 01:17:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第十一周作业</title>
      <link>https://yeung.xin/article/20</link>
      <content:encoded>&lt;h2&gt;导致系统不可用的原因有哪些？保障系统稳定高可用的方案有哪些？请分别列举并简述。&lt;/h2&gt; &lt;h3&gt;原因：&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;硬件故障&lt;/li&gt; &lt;li&gt;系统 bug&lt;/li&gt; &lt;li&gt;系统维护升级发布时短时不可用&lt;/li&gt; &lt;li&gt;用户访问量大导致并发压力过高，超过系统承载上限&lt;/li&gt; &lt;li&gt;遭受网络攻击等，导致系统负载过高崩溃&lt;/li&gt; &lt;li&gt;自然灾害等外部因素&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;高可用架构：&lt;/h3&gt; &lt;h4&gt;使用服务集群&lt;/h4&gt; &lt;p&gt;假设只有一台服务器执行所有应用，只要有人不小心踩到了电源插头，就可以导致整个服务宕机。通常系统设计时通常会将应用部署到不同的服务器上，降低故障发生时系统不可用的概率&lt;/p&gt; &lt;h4&gt;无状态组件&lt;/h4&gt; &lt;p&gt;部署服务集群是保证高可用的最基本需求：确保任何一个节点都可以断连、关机、升级，但是剩余的服务依旧正常工作。应用集群一般设计为无状态服务，通过 Session、cache 或是数据库共享信息。&lt;/p&gt; &lt;h4&gt;Load Balancing&lt;/h4&gt; &lt;p&gt;负载均衡既是应对网络并发压力的解决方案，也可以在检测到某实例故障时，无缝切换流量，提高系统容错能力。&lt;/p&gt; &lt;h4&gt;数据备份、恢复&lt;/h4&gt; &lt;p&gt;数据库奔溃比服务器宕机危害更大，因为用户的数据很可能会就此丢失，后果不堪设想。数据库冗余备份是系统设计时必须的考量。每个数据中心都应该具有完整的备份，并事先计划好数据丢失和恢复的策略。&lt;/p&gt; &lt;h4&gt;故障转移&lt;/h4&gt; &lt;p&gt;失效转移指的是当主要组件异常时，其功能转移到备份组件。其要点在于有主有备，且主故障时备可启用并设置为主。通常的实现手段有：主从复制、主主复制，也可以结合数据分片等等技术。&lt;/p&gt; &lt;h4&gt;异地多活&lt;/h4&gt; &lt;p&gt;服务集群、数据库扩展后，有些安全隐患依旧不可避免，比如地震、火灾这类自然灾害很可能导致整个机房遭遇重大破坏。为了避免这类事故，一般会在多地部署机房，实现异地容灾容错。&lt;/p&gt; &lt;h4&gt;故障自动恢复计划&lt;/h4&gt; &lt;p&gt;如上的架构设计仅仅能提高系统的可用性，但依旧不可能完全避免故障产生。因而恢复故障也是一套很复杂的系统流程：能及时地隔离故障设备，确保剩余系统功能正常；建立故障历史记录，并追踪问题根源；通过监控系统收集负载数据并分析趋势；建立一系列恢复手册，并定期测试其实用性；员工培训，以提高设计、部署、运维的能力；还应制定安全策略，抑制安全漏洞……&lt;/p&gt;</content:encoded>
      <pubDate>Thu, 27 Aug 2020 01:07:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第十一周总结</title>
      <link>https://yeung.xin/article/21</link>
      <content:encoded>&lt;h1&gt;安全&lt;/h1&gt; &lt;h2&gt;攻击&lt;/h2&gt; &lt;h3&gt;XSS&lt;/h3&gt; &lt;p&gt;跨站脚本攻击（XSS），是最普遍的Web应用安全漏洞。这类漏洞能够使得攻击者嵌入恶意脚本代码到正常用户会访问到的页面中，当正常用户访问该页面时，则可导致嵌入的恶意脚本代码的执行，从而达到恶意攻击用户的目的。&lt;/p&gt; &lt;h3&gt;SQL注入&lt;/h3&gt; &lt;p&gt;SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严，攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句，在管理员不知情的情况下实现非法操作，以此来实现欺骗数据库服务器执行非授权的任意查询，从而进一步得到相应的数据信息。&lt;/p&gt; &lt;h3&gt;CSRF攻击&lt;/h3&gt; &lt;p&gt;跨站请求伪造，也被称为 one-click attack 或者 session riding，通常缩写为 CSRF 或者 XSRF， 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本（XSS）相比，XSS 利用的是用户对指定网站的信任，CSRF 利用的是网站对用户网页浏览器的信任。&lt;/p&gt; &lt;h3&gt;其它攻击&lt;/h3&gt; &lt;p&gt;Error Code、HTML注释、文件上传、路径遍历&lt;/p&gt; &lt;h3&gt;防御手段&lt;/h3&gt; &lt;p&gt;Web防火墙和网站安全漏洞扫描&lt;/p&gt; &lt;h2&gt;加密&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;单向散列加密&lt;/li&gt; &lt;li&gt;对称加密&lt;/li&gt; &lt;li&gt;非对称加密&lt;/li&gt; &lt;/ul&gt; &lt;h1&gt;高可用&lt;/h1&gt; &lt;h2&gt;解耦&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;高内聚、低耦合的组件设计原则&lt;/li&gt; &lt;li&gt;面向对象基本设计原则&lt;/li&gt; &lt;li&gt;面向对象设计模式&lt;/li&gt; &lt;li&gt;领域驱动设计建模&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;隔离&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;业务与子系统隔离&lt;/li&gt; &lt;li&gt;微服务与中台架构&lt;/li&gt; &lt;li&gt;生产者消费者隔离&lt;/li&gt; &lt;li&gt;虚拟机与容器隔离&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;异步&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;多线程编程&lt;/li&gt; &lt;li&gt;反应式编程&lt;/li&gt; &lt;li&gt;异步通信网络编程&lt;/li&gt; &lt;li&gt;事件驱动异步架构&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;备份&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;集群设计&lt;/li&gt; &lt;li&gt;数据库分布式部署&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;失效转移&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;主失效时，备提供服务&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;幂等&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;多次相同请求结果一致性&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;事务补偿&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;分布式事务&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;重试&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;请求失败时在一定次数内重试&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;熔断&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;服务故障或压力过高时主动停止服务请求，转向其他流程&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;限流&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;丢弃部分用户请求&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;降级&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;主动部分服务不可用&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;异地多活&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;多地多机房部署&lt;/li&gt; &lt;/ul&gt; &lt;h1&gt;高可用自动化运维&lt;/h1&gt; &lt;ul&gt; &lt;li&gt;DevOPS&lt;/li&gt; &lt;/ul&gt;</content:encoded>
      <pubDate>Thu, 27 Aug 2020 01:07:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第九周作业</title>
      <link>https://yeung.xin/article/18</link>
      <content:encoded>&lt;h1&gt;请简述 JVM 垃圾回收原理。&lt;/h1&gt; &lt;h2&gt;1. Java中的四种引用类型&lt;/h2&gt; &lt;p&gt;在Java中，对于引用最基本的解释就是：如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址，就称这块内存代表着一个引用（有点指针的意味）。后来Java还将引用划分为了4种，根据被GC回收的时机可以分为：强引用（Strong Reference）、软引用（Soft Reference）、弱引用（Weak Reference）、虚引用（Phantorm Reference）。这4种引用的强度依次渐弱。&lt;/p&gt; &lt;h2&gt;2.如何判断对象需要被回收&lt;/h2&gt; &lt;h3&gt;2.1 引用计数法&lt;/h3&gt; &lt;p&gt;在对象内部会有一个引用计数器，一旦某个地方引用它时，计数器就加1，表面上看这是一个效率非常高的方式，但是如果出现循环引用时，采用了这种方式判断对象是否存活的GC就难以发挥作用了。&lt;/p&gt; &lt;h3&gt;2.2 可达性分析法&lt;/h3&gt; &lt;p&gt;相比之下，可达性分析算法就要靠谱得多。所谓可达性分析就是通过一系列被称为“GC Roots”的点作为起始点，从这些节点开始向下搜索，搜索的路径称为引用链，当一个对象到GC Roots不可达的时候，则证明此对象是可回收的。&lt;/p&gt; &lt;h2&gt;3.垃圾回收算法&lt;/h2&gt; &lt;h3&gt;3.1 标记清除法&lt;/h3&gt; &lt;p&gt;标记清除法有两个过程，&lt;/p&gt; &lt;ul&gt; &lt;li&gt;一是标记过程，即判定需要回收的对象的过程，通过可达性分析便可分析出来。&lt;/li&gt; &lt;li&gt;二是清除阶段，这个阶段就是对标记了的对象进行回收&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;这种回收算法非常简单粗暴，也很好理解，但是暴露出来问题还是比较大的，需要优化的地方还有很多。&lt;/p&gt; &lt;ul&gt; &lt;li&gt;一是标记和清除的效率都不是很高。&lt;/li&gt; &lt;li&gt;二是执行完GC后会造成大量的内存碎片，如果以后分配大内存对象的的时候无法找到足够大的连续内存，就会频繁触发GC。&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;3.2 复制算法&lt;/h3&gt; &lt;p&gt;为了解决内存碎片问题，复制算法出现了，它将可用内存平均划分为两块，每次只使用其中一块。当这一块用完了，就将还存活的对象复制到另一块，然后再把已使用的内存空间一次清理掉。这样每次GC的时候都直接回收半个内存空间的大小，不必考虑碎片问题。但这种方法带来的代价也不小，牺牲了一半的存储空间。&lt;/p&gt; &lt;h3&gt;3.3 标记整理法&lt;/h3&gt; &lt;p&gt;如果在对象存活率较高的时候采用复制算法的话，复制的操作就会有很多，对程序的运行效率也会产生一定的影响，此时就应该考虑标记整理法。标记整理法的执行过成分为3步：&lt;/p&gt; &lt;ol&gt; &lt;li&gt;用与“标记清除法”一样的操作标记存活的对象；&lt;/li&gt; &lt;li&gt;将被标记的对象全部移动到内存的某一端；&lt;/li&gt; &lt;li&gt;清除边界以外部分的内存。&lt;/li&gt; &lt;/ol&gt; &lt;h3&gt;3.4 分代回收法&lt;/h3&gt; &lt;p&gt;在分代回收算法中，会根据对象的存活周期，将内存划分为几块，一般是新生代（Young Generation）、老年代(Old Generation)、永久代(Permanent Generation)。这样就可以根据不同内存区域的特点执行采用不同的回收算法。像新生代这种经常有大批对象死去的区域，就适合用复制算法。而对于老年代这种对象生存周期较长和永久代这种内存存活率较高，又没有其他担保空间的地方就用标记清除法或标记整理法就行了。&lt;/p&gt; &lt;h2&gt;4.内存分配策略&lt;/h2&gt; &lt;p&gt;JVM的一大优势是解决的内存方面的两个重要的问题：自动给对象分配内存 和 自动回收分配给对象的问题。一般来说，分配对象需要符合以下原则：&lt;/p&gt; &lt;h3&gt;4.1 对象优先在Eden分配&lt;/h3&gt; &lt;p&gt;当Eden区没有足够空间进行分配时，虚拟机将发起一次Minor GC。&lt;/p&gt; &lt;h3&gt;4.2 大对象直接进入老年代&lt;/h3&gt; &lt;p&gt;所谓的大对象是指：需要大量连续内存空间的Java对象。最典型的大对象就是那种很长的字符串以及数组。这样可以有效避免大对象在Eden和Survivor之间的频繁复制操作带来的性能开销。（当然我们在写代码的时候也要注意避免写出生命周期太短的大对象，因为这并不符合老年代的特点）&lt;/p&gt; &lt;h3&gt;4.3 长期存活的对象将会进入老年代&lt;/h3&gt; &lt;p&gt;根据老年代的特点，每当对象熬过了一次Minor GC的时候，它的age就将会增加1，当年龄增长到一定的值时（默认为15岁），它就将进入老年代。&lt;/p&gt; &lt;h3&gt;4.4 动态对象年龄判定&lt;/h3&gt; &lt;p&gt;对于“老年对象”的判定并不一定是要根据”默认的年龄要求（15岁）“，如果在Survivor空间中相同年龄所有对象的大小的总和大于Survivor空间的一半的时候，年龄大于或等于该年龄的对象将会直接进入老年代。&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 05 Aug 2020 15:35:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第九周总结</title>
      <link>https://yeung.xin/article/19</link>
      <content:encoded>&lt;p&gt;架构师训练营第九周总结&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 05 Aug 2020 15:35:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第八周作业</title>
      <link>https://yeung.xin/article/17</link>
      <content:encoded>&lt;p&gt;有两个单向链表（链表长度分别为 m，n），这两个单向链表有可能在某个元素合并，如下图所示的这样，也可能不合并。现在给定两个链表的头指针，在不修改链表的情况下，如何快速地判断这两个链表是否合并？如果合并，找到合并的元素，也就是图中的 x 元素。请用（伪）代码描述算法，并给出时间复杂度和空间复杂度。 &lt;img src="https://yeung.xin/upload/2020/07/vjiq70e478jsmpiung3i7h84fg.png" alt="alt" title="alt" /&gt;&lt;/p&gt; &lt;ol&gt; &lt;li&gt;计算链表1、2的长度m，n，取得长的链表(比如链表2)&lt;/li&gt; &lt;li&gt;链表2头指针后移n-m，使得两个链表同长&lt;/li&gt; &lt;li&gt;遍历第二步产生的两个链表，若节点一样，则返回该节点&lt;/li&gt; &lt;li&gt;若返回null，则链表没有合并，否则为合并后的节点，时间复杂度为O(m+2n)，空间复杂度O(1)&lt;/li&gt; &lt;/ol&gt; &lt;pre&gt;&lt;code&gt;function findMergeNode(link1, link2)    result &amp;lt;- null   m &amp;lt;- link1.length   n &amp;lt;- link2.length   differ &amp;lt;- m &amp;gt; n ? m - n : m -n   [shortLink, longList] &amp;lt;- m &amp;gt; n ? [link1, lnk2] : [link2, link1]   while differ-- &amp;gt; 0 do     longLink &amp;lt;- longLink.next   end while   while longLink do     if longLink == shortLink then       result &amp;lt;- longList     else       longLink &amp;lt;- longLink.next       shortLink &amp;lt;- shortLink.next     end if   end while end function &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Wed, 29 Jul 2020 15:56:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第八周总结</title>
      <link>https://yeung.xin/article/16</link>
      <content:encoded>&lt;h1&gt;数据结构与算法&lt;/h1&gt; &lt;h2&gt;算法性能评测&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;时间复杂度：算法语句执行的次数&lt;/li&gt; &lt;li&gt;空间复杂度：运行中临时占用的空间大小&lt;/li&gt; &lt;/ul&gt; &lt;h2&gt;常用数据结构&lt;/h2&gt; &lt;ol&gt; &lt;li&gt;数组：存储在连续的内存空间，查询快捷，插入较慢。按下标查询时间复杂度O(1)&lt;/li&gt; &lt;li&gt;链表：可以使用零散的内存空间，查询较慢，插入较快。查找时间复杂度O(n)&lt;/li&gt; &lt;li&gt;Hash表：数组加链表&lt;/li&gt; &lt;li&gt;栈：后进先出&lt;/li&gt; &lt;li&gt;队列：先进先出&lt;/li&gt; &lt;/ol&gt; &lt;h1&gt;数据库原理与性能优化&lt;/h1&gt; &lt;h2&gt;数据库架构：&lt;/h2&gt; &lt;ol&gt; &lt;li&gt;连接器（连接池）&lt;/li&gt; &lt;li&gt;语法分析器（校验错误）&lt;/li&gt; &lt;li&gt;语义分析与优化器（语句等价转化、利用索引优化）&lt;/li&gt; &lt;li&gt;执行引擎（执行计划、分析性能）&lt;/li&gt; &lt;/ol&gt; &lt;h2&gt;优化方法&lt;/h2&gt; &lt;ul&gt; &lt;li&gt;prepareStatement预处理，效率更好&lt;/li&gt; &lt;li&gt;添加必要的索引优化SQL查询性能&lt;/li&gt; &lt;li&gt;谨慎使用索引&lt;/li&gt; &lt;/ul&gt;</content:encoded>
      <pubDate>Wed, 29 Jul 2020 15:53:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第七周总结</title>
      <link>https://yeung.xin/article/15</link>
      <content:encoded>&lt;h3&gt;判断系统性能的两个角度&lt;/h3&gt; &lt;p&gt;主观角度和客观角度，主观角度是用户感受到的性能观感，客观角度是是指系统的响应时间之类的性能指标衡量的性能。&lt;/p&gt; &lt;h3&gt;性能测试&lt;/h3&gt; &lt;p&gt;性能测试是性能优化的前提和基础，也是性能优化结果的检查和度量标准。不同视角下的网站有不同的标准，也有不同的优化手段。 性能测试指标&lt;/p&gt; &lt;p&gt;不同角度有不同的性能标准，有不同的性能测试指标，网站性能测试的主要性能指标有响应时间、并发数、吞吐量和性能计数器等等。&lt;/p&gt; &lt;h4&gt;响应时间：指应用系统从发出请求开始到收到最后响应数据所需的时间。&lt;/h4&gt; &lt;h4&gt;并发数：系统能够同时处理请求的数目，这个数字也反映了系统的负载特性。&lt;/h4&gt; &lt;h4&gt;吞吐量：指单位时间内系统处理的请求数，体现系统的处理能力。&lt;/h4&gt; &lt;h4&gt;吞吐量、响应时间和并发数之间的关系：吞吐量=（1000/响应时间ms）*并发数&lt;/h4&gt;</content:encoded>
      <pubDate>Wed, 22 Jul 2020 14:23:47 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第七周作业</title>
      <link>https://yeung.xin/article/14</link>
      <content:encoded>&lt;h3&gt;性能压测的时候，随着并发压力的增加，系统响应时间和吞吐量如何变化，为什么？&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;并发：单位时间内，系统同时处理的提交请求的数量，一般为秒级时间&lt;/li&gt; &lt;li&gt;系统响应时间：系统从收到用户请求到处理完用户请求并返回响应结果的时间间隔&lt;/li&gt; &lt;li&gt;吞吐量：单位时间内，系统处理的请求数量。&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;一般来说，在系统的设计范围之内，吞吐量随系统的并发用户数的增加呈现增加趋势，也就是说你客户端来多少请求数系统吃（处理）多少请求数；当超出这个范围时有两种情况，&lt;/p&gt; &lt;ul&gt; &lt;li&gt;一种是系统只能处理这么多，超过这个数系统不接收了，最后随着并发用户数的增多吞吐量是一个水平的直线；&lt;/li&gt; &lt;li&gt;还有一种情况是不管来多少系统都接收最后导致系统吞吐量下降甚至系统崩溃。&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2020/07/4jgua14caggm7prntddtpdlc16.png" alt="alt" title="alt" /&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 22 Jul 2020 14:23:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第六周作业</title>
      <link>https://yeung.xin/article/12</link>
      <content:encoded>&lt;h3&gt;请简述 CAP 原理。&lt;/h3&gt; &lt;p&gt;CAP原则又称CAP定理，指的是在一个分布式系统中， Consistency（一致性）、 Availability（可用性）、Partition tolerance（分区容错性），三者不可得兼。&lt;/p&gt; &lt;ul&gt; &lt;li&gt;一致性（C）：在分布式系统中的所有数据备份，在同一时刻是否同样的值。（等同于所有节点访问同一份最新的数据副本）&lt;/li&gt; &lt;li&gt;可用性（A）：在集群中一部分节点故障后，集群整体是否还能响应客户端的读写请求。（对数据更新具备高可用性）&lt;/li&gt; &lt;li&gt;分区容忍性（P）：以实际效果而言，分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性，就意味着发生了分区的情况，必须就当前操作在C和A之间做出选择。&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;CAP原则的精髓就是要么AP，要么CP，要么AC，但是不存在CAP。如果在某个分布式系统中数据无副本， 那么系统必然满足强一致性条件， 因为只有独一数据，不会出现数据不一致的情况，此时C和P两要素具备，但是如果系统发生了网络分区状况或者宕机，必然导致某些数据不可以访问，此时可用性条件就不能被满足，即在此情况下获得了CP系统，但是CAP不可同时满足。 因此在进行分布式架构设计时，必须做出取舍。当前一般是通过分布式缓存中各节点的最终一致性来提高系统的性能，通过使用多节点之间的数据异步复制技术来实现集群化的数据一致性。通常使用类似 memcached 之类的 NOSQL 作为实现手段。虽然 memcached 也可以是分布式集群环境的，但是对于一份数据来说，它总是存储在某一台 memcached 服务器上。如果发生网络故障或是服务器死机，则存储在这台服务器上的所有数据都将不可访问。由于数据是存储在内存中的，重启服务器，将导致数据全部丢失。当然也可以自己实现一套机制，用来在分布式 memcached 之间进行数据的同步和持久化，但是实现难度是非常大的。&lt;/p&gt;</content:encoded>
      <pubDate>Thu, 16 Jul 2020 01:03:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第六周总结</title>
      <link>https://yeung.xin/article/13</link>
      <content:encoded>&lt;h3&gt;分布式数据库一主多从复制的优点&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;分摊负载&lt;/li&gt; &lt;li&gt;专机专用&lt;/li&gt; &lt;li&gt;便于冷备&lt;/li&gt; &lt;li&gt;高可用&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;MySQL复制注意事项:&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;主主复制的两个数据库不能并发写入。&lt;/li&gt; &lt;li&gt;复制只是增加了数据的读并发处理能力，没有增加写并发能力和存储能力。&lt;/li&gt; &lt;li&gt;更新表结构会导致巨大的同步延迟。&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;数据分片的挑战&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;需要大量的额外代码，处理逻辑因此变得更加复杂。&lt;/li&gt; &lt;li&gt;无法执行多分片的联合查询。&lt;/li&gt; &lt;li&gt;无法使用数据库的事务。&lt;/li&gt; &lt;li&gt;随着数据的增长，如何增加更多的服务器。&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;CAP原理&lt;/h3&gt; &lt;blockquote&gt; &lt;p&gt;当网络分区失效发生的时候，我们要么取消操作，这样数据就是一致的， 但是系统却不 可用;要么我们继续写入数据，但是数据的一致性就得不到保证。 对于一个分布式系统而言，网络失效一定会发生，也就是说，分区耐受性是必须要保证 的，那么在可用性和一致性上就必须二选一。 当网络分区失效，也就是网络不可用的时候，如果选择了-致性，系统就可能返回一个 错误码或者干脆超时，即系统不可用。如果选择了可用性，那么系统总是可以返回一个 数据，但是并不能保证这个数据是最新的。 所以，关于CAP原理，更准确的说法是，在分布式系统必须要满足分区耐受性的前提下， 可用性和一致性无法同时满足。&lt;/p&gt; &lt;/blockquote&gt; &lt;h3&gt;ACID&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;原子性(Atomicity) :事务要么全部完成，要么全部取消。如果事务 崩溃，状态回到事务之前(事务回滚)&lt;/li&gt; &lt;li&gt;隔离性(Isolation) :如果2个事务T1和T2同时运行，事务T1和T2最终的结果是相同的，不管T1和T2谁先结束，隔离性主要依靠锁现。&lt;/li&gt; &lt;li&gt;持久性(Durability) :一旦事务提交，不管发生什么(崩溃或者出错) ,数据要保存在数据库中。&lt;/li&gt; &lt;li&gt;一致性 (Consistency) : 只有合法的数据(依照关系约束和函数约束)才能写入数据库。&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;BASE&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;基本可用(Basically Available)系统在出现不可预知故障时，允许损失部分可用性，如响应时间.上的损失或功能上的损失。&lt;/li&gt; &lt;li&gt;Soft state (弱状态)软状态，指允许系统中的二数据存在中间状态，并认为该中间状态的存在不会影响系统的整体可用性，即允许系在- 不同节点的数据副本之间进行数据同步的过程存在延时。&lt;/li&gt; &lt;li&gt;Eventually consistent (最终一致性 )指系统中所有的数据副本，在经过一段时间的同步后，最终能够达到一个一致的状态，因此最- 终一致性的本 质是需要系统保证数据能够达到一致，而不需要实时保证系统数据的强-致性。&lt;/li&gt; &lt;/ul&gt;</content:encoded>
      <pubDate>Thu, 16 Jul 2020 01:03:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第五周作业</title>
      <link>https://yeung.xin/article/11</link>
      <content:encoded>&lt;p&gt;用你熟悉的编程语言实现一致性 hash 算法。 编写测试用例测试这个算法，测试 100 万 KV 数据，10 个服务器节点的情况下，计算这些 KV 数据在服务器上分布数量的标准差，以评估算法的存储负载不均衡性。&lt;/p&gt; &lt;p&gt;Node.java&lt;/p&gt; &lt;pre&gt;&lt;code&gt;package com.tale.hash; public class Node {     private String ip;     private String name;     public Node(String ip, String name) { this.ip = ip; this.name = name; }     public String getIp() { return ip; }     public void setIp(String ip) { this.ip = ip; }     public String getName() { return name; }     public void setName(String name) { this.name = name; } } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;ConHashTest.java&lt;/p&gt; &lt;pre&gt;&lt;code&gt;package com.tale.hash;  import java.math.BigDecimal; import java.util.*;  public class ConHashTest {     private static final String IP_PREFIX = &amp;quot;192.168.1.&amp;quot;;// 机器节点IP前缀      // 方差     public static double Variance(int[] x) {         int m = x.length;         double sum = 0;         //求和         for (double value : x) sum += value;         double dAve = sum / m;//求平均值         double dVar = 0;         //求方差         for (double v : x) dVar += (v - dAve) * (v - dAve);         return dVar / m;     }     // 标准差     public static double StandardDivination(int[] x) {         return Math.sqrt(Variance(x));     }      public static void main(String[] args) {         Map&amp;lt;String, Integer&amp;gt; map = new HashMap&amp;lt;&amp;gt;();// 每台真实机器节点上保存的记录条数         HashFunction hashFunction = new HashFunctionImpl();         LinkedHashMap&amp;lt;Integer, Double&amp;gt; variances = new LinkedHashMap&amp;lt;&amp;gt;();                  for (int numberOfReplicas = 100; numberOfReplicas &amp;lt;= 1000; numberOfReplicas += 10) {             System.out.println(&amp;quot;单个机器的虚拟节点: &amp;quot; + numberOfReplicas);             map.clear();             //真实物理节点             List&amp;lt;Node&amp;gt; realNodes = new ArrayList&amp;lt;&amp;gt;();             for (int i = 1; i &amp;lt;= 10; i++) {                 map.put(IP_PREFIX + i, 0);// 每台真实机器节点上保存的记录条数初始为0                 Node node = new Node(IP_PREFIX + i, &amp;quot;node&amp;quot; + i);                 realNodes.add(node);             }             ConsistentHash consistentHash = new ConsistentHash(hashFunction, numberOfReplicas, realNodes);             // 将1000000条记录尽可能均匀的存储到10台机器节点             for (int i = 0; i &amp;lt; 1000000; i++) {                 // 产生随机一个字符串当做一条记录，可以是其它更复杂的业务对象,比如随机字符串相当于对象的业务唯一标识                 String data = UUID.randomUUID().toString() + i;                 // 通过记录找到真实机器节点                 Node node = consistentHash.get(data);                 // 每台真实机器节点上保存的记录条数加1                 map.put(node.getIp(), map.get(node.getIp()) + 1);             }             // 打印每台真实机器节点保存的记录条数             int[] numbers = new int[10];             for (int i = 1; i &amp;lt;= 10; i++) {                 numbers[i - 1] = map.get(&amp;quot;192.168.1.&amp;quot; + i);                 System.out.println(IP_PREFIX + i + &amp;quot;节点记录条数：&amp;quot; + map.get(&amp;quot;192.168.1.&amp;quot; + i));             }             System.out.println(&amp;quot;方差: &amp;quot; + BigDecimal.valueOf(Variance(numbers)));             System.out.println(&amp;quot;标准差: &amp;quot; + BigDecimal.valueOf(StandardDivination(numbers)));             variances.put(numberOfReplicas, StandardDivination(numbers));             System.out.println();             System.out.println();         }         System.out.println(variances);     } } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;ConsistentHash.java&lt;/p&gt; &lt;pre&gt;&lt;code&gt;package com.tale.hash;  import java.util.Collection; import java.util.SortedMap; import java.util.TreeMap;  public class ConsistentHash {      private final HashFunction hashFunction;// hash 函数接口     private final int numberOfReplicas;// 每个机器节点关联的虚拟节点个数     private final SortedMap&amp;lt;Integer, Node&amp;gt; circle = new TreeMap&amp;lt;&amp;gt;();// 环形虚拟节点      /**      * @param hashFunction     hash 函数接口      * @param numberOfReplicas 每个机器节点关联的虚拟节点个数      * @param nodes            真实机器节点      */     public ConsistentHash(HashFunction hashFunction, int numberOfReplicas, Collection&amp;lt;Node&amp;gt; nodes) {         this.hashFunction = hashFunction;         this.numberOfReplicas = numberOfReplicas;         nodes.forEach(this::add);     }      /**      * 增加真实机器节点      */     public void add(Node node) {         for (int i = 0; i &amp;lt; this.numberOfReplicas; i++) {             circle.put(this.hashFunction.hash(node.getIp() + i), node);         }     }      /**      * 删除真实机器节点      */     public void remove(Node node) {         for (int i = 0; i &amp;lt; this.numberOfReplicas; i++) {             circle.remove(this.hashFunction.hash(node.getIp() + i));         }     }      /**      * 取得真实机器节点      */     public Node get(String key) {         if (circle.isEmpty()) return null;         Integer hash = hashFunction.hash(key);         if (!circle.containsKey(hash)) {             SortedMap&amp;lt;Integer, Node&amp;gt; tailMap = circle.tailMap(hash);// 沿环的顺时针找到一个虚拟节点             hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();         }         return circle.get(hash); // 返回该虚拟节点对应的真实机器节点的信息     } } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;HashFunction.java&lt;/p&gt; &lt;pre&gt;&lt;code&gt;package com.tale.hash;  public interface HashFunction {     Integer hash(String key); } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;HashFunctionImpl.java&lt;/p&gt; &lt;pre&gt;&lt;code&gt;package com.tale.hash;  public class HashFunctionImpl implements HashFunction {     @Override     public Integer hash(String key) {         final int p = 16777619;         int hash = (int) 2166136261L;         for (int i = 0; i &amp;lt; key.length(); i++) hash = (hash ^ key.charAt(i)) * p;         hash += hash &amp;lt;&amp;lt; 13;         hash ^= hash &amp;gt;&amp;gt; 7;         hash += hash &amp;lt;&amp;lt; 3;         hash ^= hash &amp;gt;&amp;gt; 17;         hash += hash &amp;lt;&amp;lt; 5;          // 如果算出来的值为负数则取其绝对值         if (hash &amp;lt; 0) hash = Math.abs(hash);         return hash;     } } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2020/07/oqkinovt4kg44p5mr7ch9vojtb.png" alt="alt" title="alt" /&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 08 Jul 2020 15:56:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第五周总结</title>
      <link>https://yeung.xin/article/10</link>
      <content:encoded>&lt;h4 id="1-hash-"&gt;1.一致性hash，引入 虚拟节点的好处：&lt;/h4&gt; &lt;p&gt;1）当节点较少时，两个节点上分布的请求不会差别太大&lt;br&gt;2）各个虚拟节点散落在hash环上，新增节点也是散落在hash环上各处&lt;br&gt;3）避免缓存失效&lt;/p&gt; &lt;h4 id="2-"&gt;2.消息队列的好处：&lt;/h4&gt; &lt;p&gt;1）提高系统的响应速度&lt;br&gt;2）提高系统稳定性&lt;/p&gt; &lt;h4 id="3-ip-"&gt;3.负载均衡服务器可以工作在各个层面，在越底层的性能越高，数据链路层的负载均衡会比IP层的性能高些&lt;/h4&gt; &lt;h4 id="4-session-"&gt;4.管理session的几种方式&lt;/h4&gt; &lt;p&gt;1）session复制  --- 当session较多时，不同服务器间通信复制的数据量较大，可能会影响性能&lt;br&gt;2）session绑定  ----绑定的服务器升级时，session就失效掉了&lt;br&gt;3）使用cookie记录session ---- 需要浏览器支持cookie&lt;br&gt;4)  session服务器 --- 由专用 的服务器来提供 session信息&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 08 Jul 2020 15:55:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第四周总结</title>
      <link>https://yeung.xin/article/8</link>
      <content:encoded>&lt;p&gt;架构的演化 零阶段：最简单的互联网应用架构 &lt;img src="https://yeung.xin/upload/2020/07/palf5of66qiefrtc62klenbav3.png" alt="alt" title="alt" /&gt; 一阶段：应用数据分离 &lt;img src="https://yeung.xin/upload/2020/07/49p2jikp4agnro5fpsk8f61odv.png" alt="alt" title="alt" /&gt; 二阶段：使用缓存改善系统性能 &lt;img src="https://yeung.xin/upload/2020/07/0aus7naukei12pcio15v2oqcd5.png" alt="alt" title="alt" /&gt; 三阶段：使用应用服务器集群改善系统的并发处理能力 &lt;img src="https://yeung.xin/upload/2020/07/2fe8sn7crmj7frhr521jpg52c9.png" alt="alt" title="alt" /&gt; 四阶段：数据库读写分离 &lt;img src="https://yeung.xin/upload/2020/07/57j7gutjuchp5r1hld1sdejlar.png" alt="alt" title="alt" /&gt; 五阶段：使用反向代理和 CDN 加速网站响应 &lt;img src="https://yeung.xin/upload/2020/07/ugd71laopag8dopggim6ae3uk3.png" alt="alt" title="alt" /&gt; 六阶段：使用分布式文件系统和分布式数据库系统 &lt;img src="https://yeung.xin/upload/2020/07/1gi1n3jugkh7srs88fv624ftf5.png" alt="alt" title="alt" /&gt; 七阶段：使用 NoSQL 和搜索引擎 &lt;img src="https://yeung.xin/upload/2020/07/qvqdskev5mih8o9brelcb92vaj.png" alt="alt" title="alt" /&gt; 八阶段：业务拆分 &lt;img src="https://yeung.xin/upload/2020/07/16e0d6co36igup41tktr22ch8j.png" alt="alt" title="alt" /&gt; 九阶段：微服务以及中台化 &lt;img src="https://yeung.xin/upload/2020/07/v3q3062klmg00rcoifrrft103t.png" alt="alt" title="alt" /&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 01 Jul 2020 14:26:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第四周作业</title>
      <link>https://yeung.xin/article/9</link>
      <content:encoded>&lt;h3&gt;一个典型的大型互联网应用系统使用了哪些技术方案和手段，主要解决什么问题？请列举描述。&lt;/h3&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2020/07/va9069oioogm7q19hsd0fvmud2.jpeg" alt="alt" title="alt" /&gt;&lt;/p&gt; &lt;h4&gt;1、项目管理/Bug管理/问题管理&lt;/h4&gt; &lt;p&gt;项目管理软件是整个业务的需求，问题，流程等等的集中地，大家的跨部门沟通协同大多依赖于项目管理工具。&lt;/p&gt; &lt;h4&gt;2、DNS&lt;/h4&gt; &lt;p&gt;DNS 是一个很通用的服务，创业公司基本上选择一个合适的云厂商就行了，国内主要是两家： 阿里万网：阿里 2014 年收购了万网，整合了其域名服务，最终形成了现在的阿里万网，其中就包含 DNS 这块的服务； 腾讯 DNSPod：腾讯 2012 年以 4000 万收购 DNSPod 100% 股份，主要提供域名解析和一些防护功能；&lt;/p&gt; &lt;h4&gt;3、LB（负载均衡）&lt;/h4&gt; &lt;p&gt;LB（负载均衡）是一个通用服务，一般云厂商的 LB 服务基本都会如下功能：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;支持四层协议请求（包括 TCP、UDP 协议）；&lt;/li&gt; &lt;li&gt;支持七层协议请求（包括 HTTP、HTTPS 协议）；&lt;/li&gt; &lt;li&gt;集中化的证书管理系统支持 HTTPS 协议；&lt;/li&gt; &lt;li&gt;健康检查；&lt;/li&gt; &lt;/ul&gt; &lt;h4&gt;4、RPC 框架&lt;/h4&gt; &lt;p&gt;远程过程调用（Remote Procedure Call，RPC）是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序，而程序员无需额外地为这个交互作用编程。&lt;/p&gt; &lt;h4&gt;5、数据库&lt;/h4&gt; &lt;p&gt;数据存储&lt;/p&gt; &lt;h4&gt;6、消息中间件&lt;/h4&gt; &lt;p&gt;消息中间件在后台系统中是必不可少的一个组件，一般我们会在以下场景中使用消息中间件： 异步处理、系统解耦、削峰填谷&lt;/p&gt; &lt;h4&gt;8、代码管理&lt;/h4&gt; &lt;p&gt;代码是互联网创业公司的命脉之一，代码管理很重要，常见的考量点包括两块： 安全和权限管理、代码管理工具&lt;/p&gt; &lt;h4&gt;9、持续集成&lt;/h4&gt; &lt;p&gt;持续集成为研发流程提供了代码分支管理/比对、编译、检查、发布物输出等基础工作，为测试的覆盖率版本编译、生成等提供统一支持。&lt;/p&gt; &lt;h4&gt;10、日志系统&lt;/h4&gt; &lt;p&gt;日志系统一般包括打日志，采集，中转，收集，存储，分析，呈现，搜索还有分发等。&lt;/p&gt; &lt;h4&gt;11、监控系统&lt;/h4&gt; &lt;p&gt;监控系统只包含与后台相关的，如 Prometheus。&lt;/p&gt; &lt;h4&gt;12、配置系统&lt;/h4&gt; &lt;p&gt;随着程序功能的日益复杂，程序的配置日益增多：各种功能的开关、降级开关，灰度开关，参数的配置、服务器的地址、数据库配置等等，除此之外，对后台程序配置的要求也越来越高：配置修改后实时生效，灰度发布，分环境、分用户，分集群管理配置，完善的权限、审核机制等等&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 01 Jul 2020 14:23:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第三周作业</title>
      <link>https://yeung.xin/article/6</link>
      <content:encoded>&lt;p&gt;架构师训练营第三周作业&lt;/p&gt; &lt;h3&gt;1. 请在草稿纸上手写一个单例模式的实现代码，拍照提交作业。&lt;/h3&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2020/06/upj5n3l0q6iavp8e06j7goapov.jpg" alt="alt" title="alt" /&gt;&lt;/p&gt; &lt;h3&gt;2. 请用组合设计模式编写程序，打印输出图 1 的窗口，窗口组件的树结构如图 2 所示，打印输出示例参考图 3。&lt;/h3&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2020/06/u5efl0ouaqjpfq4ggjilurf1t8.png" alt="alt" title="alt" /&gt;&lt;/p&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2020/06/2aicav992mirqoc20kl907tkpf.png" alt="alt" title="alt" /&gt;&lt;/p&gt; &lt;p&gt;&lt;a href="https://yeung.xin/upload/2020/06/6vqppkocf0jahor5pgkd672q2n.java" target="_blank"&gt;Code&lt;/a&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 24 Jun 2020 14:47:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第三周总结</title>
      <link>https://yeung.xin/article/7</link>
      <content:encoded>&lt;h3&gt;设计模式四部分：名称、待解问题、解决方案、利弊&lt;/h3&gt; &lt;h3&gt;设计模式功能分类：创建型、结构型、 行为性&lt;/h3&gt; &lt;h3&gt;设计模式方式分类：&lt;/h3&gt; &lt;ul&gt; &lt;li&gt;类模式：以继承的方式实现，静态的&lt;/li&gt; &lt;li&gt;对象模式：已组合的方式实现，动态的&lt;/li&gt; &lt;/ul&gt;</content:encoded>
      <pubDate>Wed, 24 Jun 2020 14:46:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第二周总结</title>
      <link>https://yeung.xin/article/5</link>
      <content:encoded>&lt;h3&gt;面向对象的设计目的&lt;/h3&gt; &lt;pre&gt;&lt;code&gt;强内聚、低耦合，让系统 易扩展 易于增加新的功能 更强壮 不容易被粗心的程序员破坏 可移植 能够在多样的环境下运行 更简单 容易理解、容易维护 &lt;/code&gt;&lt;/pre&gt; &lt;h3&gt;面向对象的设计的基本原则&lt;/h3&gt; &lt;h4&gt;OOD原则一：开闭原则（OCP）&lt;/h4&gt; &lt;pre&gt;&lt;code&gt;开闭原则的思想是，对扩展是开放的、对修改是关闭的。 如何满足这样的需求？最关键的就是抽象！ &lt;/code&gt;&lt;/pre&gt; &lt;h4&gt;OOD原则二：依赖倒置原则（DIP）&lt;/h4&gt; &lt;pre&gt;&lt;code&gt;依赖倒置原则告诉我们，高层的模块不能依赖底层模块，而应该依赖抽象。 高层和底层一起都依赖抽象。 这样的好处是是抽象往往是最不容易改动的，如果抽象频繁改动，那可能说明你的抽象有问题。 抽象不易改变就决定了，无论高层改动，还是底层改动都不会对对方造成影响。这也就能保证了易扩展、更强壮的特性。 &lt;/code&gt;&lt;/pre&gt; &lt;h4&gt;OOD原则三：Liskov替换原则（LSP）&lt;/h4&gt; &lt;pre&gt;&lt;code&gt;里式替换原则的思想是子类型必须能够替换掉他们的基类型。 里式替换是结合场景来分析的，如果我们在设计的时候发现一个场景中，继承的多个类之间不能替换，那我们这个设计之间可能就存在问题，或许应该考虑不用继承而使用其他方式来实现。 解决里式替换的办法是提取共性到基类、或者通过组合的方式来解决。 由 is 转变为 has。 &lt;/code&gt;&lt;/pre&gt; &lt;h4&gt;OOD原则四：单一职责原则（SRP）&lt;/h4&gt; &lt;pre&gt;&lt;code&gt;SPR又被称为内聚性原则，一个类，只能有一个引起他变化的原因。 一个职责就是一个变化的原因。 &lt;/code&gt;&lt;/pre&gt; &lt;h3&gt;OOD原则五：接口分离原则（ISP）&lt;/h3&gt; &lt;pre&gt;&lt;code&gt;不应该强迫客户程序依赖他们不需要的方法。 ISP和SRP时相关的，都和内聚性有关。 ISP指出应该如何设计一个接口，从客户的角度出发，强调不让客户看到他们不需要的方法。 &lt;/code&gt;&lt;/pre&gt; &lt;h3&gt;OOD原则五：迪米特法则，又称最少知道原则（DP）&lt;/h3&gt; &lt;pre&gt;&lt;code&gt;一个实体应当尽量少地与其他实体之间发生相互作用，使得系统功能模块相对独立。 &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Wed, 17 Jun 2020 18:18:00 GMT</pubDate>
    </item>
    <item>
      <title>架构师训练营第二周作业</title>
      <link>https://yeung.xin/article/4</link>
      <content:encoded>&lt;h3&gt;作业一：&lt;/h3&gt; &lt;p&gt;&lt;code&gt;请描述什么是依赖倒置原则，为什么有时候依赖倒置原则又被称为好莱坞原则？&lt;/code&gt;&lt;/p&gt; &lt;p&gt;依赖倒置原则的包含如下的三层含义：&lt;/p&gt; &lt;ul&gt; &lt;li&gt;高层模块不应该依赖低层模块，两者都应该依赖其抽象&lt;/li&gt; &lt;li&gt;抽象不应该依赖细节&lt;/li&gt; &lt;li&gt;细节应该依赖抽象&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;每一个逻辑的实现都是由原子逻辑组成的，不可分割的原子逻辑就是低层模块(一般是接口，抽象类)，原子逻辑的组装就是高层模块。在Java语言中，抽象就是指接口和或抽象类，两者都不能被直接实例化。细节就是实现类，实现接口或继承抽象类而产生的类就是细节，可以被直接实例化。&lt;/p&gt; &lt;ul&gt; &lt;li&gt;模块间的依赖通过抽象发生，实现类之间不发生直接的依赖关系，其依赖关系是通过接口或抽象类产生的&lt;/li&gt; &lt;li&gt;接口或抽象类不依赖于实现类&lt;/li&gt; &lt;li&gt;实现类依赖于接口或抽象类&lt;/li&gt; &lt;/ul&gt; &lt;h3&gt;作业二：&lt;/h3&gt; &lt;p&gt;&lt;code&gt;请描述一个你熟悉的框架，是如何实现依赖倒置原则的。&lt;/code&gt;&lt;/p&gt; &lt;p&gt;JDK 数据库驱动也是一种依赖倒置，由jdk定义好了Drive、Connection接口，每个数据库厂商都实现了这个抽象的接口，同时在DriveManager中会在合适的时机来通过抽象来调用厂商的数据库实现，这也是一种依赖倒置。&lt;/p&gt; &lt;h3&gt;作业三：&lt;/h3&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2020/06/4dvuj6nkaqhthqqh1ijt7egasf.png" alt="Image text" title="Image text" /&gt;&lt;/p&gt; &lt;p&gt;&lt;img src="https://yeung.xin/upload/2020/06/qd1ve9t0j2jngotll7kjgor34q.png" alt="Image text" title="Image text" /&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Mon, 27 May 2019 14:46:00 GMT</pubDate>
    </item>
  </channel>
</rss>

