diff --git a/docs/database/sql/sql-questions-01.md b/docs/database/sql/sql-questions-01.md index c0e3b2f8..4bf08f0f 100644 --- a/docs/database/sql/sql-questions-01.md +++ b/docs/database/sql/sql-questions-01.md @@ -1095,13 +1095,14 @@ WHERE b.prod_id = 'BR01' ```sql # 写法 1:子查询 -SELECT o.cust_id AS cust_id, tb.total_ordered AS total_ordered -FROM (SELECT order_num, Sum(item_price * quantity) AS total_ordered +SELECT o.cust_id, SUM(tb.total_ordered) AS `total_ordered` +FROM (SELECT order_num, SUM(item_price * quantity) AS total_ordered FROM OrderItems GROUP BY order_num) AS tb, Orders o WHERE tb.order_num = o.order_num -ORDER BY total_ordered DESC +GROUP BY o.cust_id +ORDER BY total_ordered DESC; # 写法 2:连接表 SELECT b.cust_id, Sum(a.quantity * a.item_price) AS total_ordered @@ -1111,6 +1112,8 @@ GROUP BY cust_id ORDER BY total_ordered DESC ``` +关于写法一详细介绍可以参考: [issue#2402:写法 1 存在的错误以及修改方法](https://github.com/Snailclimb/JavaGuide/issues/2402)。 + ### 从 Products 表中检索所有的产品名称以及对应的销售总数 `Products` 表中检索所有的产品名称:`prod_name`、产品 id:`prod_id` @@ -1653,12 +1656,12 @@ ORDER BY prod_name 注意:`vend_id` 列会显示在多个表中,因此在每次引用它时都需要完全限定它。 ```sql -SELECT vend_id, COUNT(prod_id) AS prod_id -FROM Vendors -LEFT JOIN Products +SELECT v.vend_id, COUNT(prod_id) AS prod_id +FROM Vendors v +LEFT JOIN Products p USING(vend_id) -GROUP BY vend_id -ORDER BY vend_id +GROUP BY v.vend_id +ORDER BY v.vend_id ``` ## 组合查询 diff --git a/docs/high-availability/performance-test.md b/docs/high-availability/performance-test.md index fe2ce946..47201441 100644 --- a/docs/high-availability/performance-test.md +++ b/docs/high-availability/performance-test.md @@ -8,15 +8,15 @@ icon: et-performance 这篇文章是我会结合自己的实际经历以及在测试这里取的经所得,除此之外,我还借鉴了一些优秀书籍,希望对你有帮助。 -## 一 不同角色看网站性能 +## 不同角色看网站性能 -### 1.1 用户 +### 用户 当用户打开一个网站的时候,最关注的是什么?当然是网站响应速度的快慢。比如我们点击了淘宝的主页,淘宝需要多久将首页的内容呈现在我的面前,我点击了提交订单按钮需要多久返回结果等等。 所以,用户在体验我们系统的时候往往根据你的响应速度的快慢来评判你的网站的性能。 -### 1.2 开发人员 +### 开发人员 用户与开发人员都关注速度,这个速度实际上就是我们的系统**处理用户请求的速度**。 @@ -31,7 +31,7 @@ icon: et-performance 7. 项目使用的 Redis 缓存多大?服务器性能如何?用的是机械硬盘还是固态硬盘? 8. …… -### 1.3 测试人员 +### 测试人员 测试人员一般会根据性能测试工具来测试,然后一般会做出一个表格。这个表格可能会涵盖下面这些重要的内容: @@ -40,63 +40,87 @@ icon: et-performance 3. 吞吐量; 4. …… -### 1.4 运维人员 +### 运维人员 运维人员会倾向于根据基础设施和资源的利用率来判断网站的性能,比如我们的服务器资源使用是否合理、数据库资源是否存在滥用的情况、当然,这是传统的运维人员,现在 Devops 火起来后,单纯干运维的很少了。我们这里暂且还保留有这个角色。 -## 二 性能测试需要注意的点 +## 性能测试需要注意的点 几乎没有文章在讲性能测试的时候提到这个问题,大家都会讲如何去性能测试,有哪些性能测试指标这些东西。 -### 2.1 了解系统的业务场景 +### 了解系统的业务场景 **性能测试之前更需要你了解当前的系统的业务场景。** 对系统业务了解的不够深刻,我们很容易犯测试方向偏执的错误,从而导致我们忽略了对系统某些更需要性能测试的地方进行测试。比如我们的系统可以为用户提供发送邮件的功能,用户配置成功邮箱后只需输入相应的邮箱之后就能发送,系统每天大概能处理上万次发邮件的请求。很多人看到这个可能就直接开始使用相关工具测试邮箱发送接口,但是,发送邮件这个场景可能不是当前系统的性能瓶颈,这么多人用我们的系统发邮件, 还可能有很多人一起发邮件,单单这个场景就这么人用,那用户管理可能才是性能瓶颈吧! -### 2.2 历史数据非常有用 +### 历史数据非常有用 -当前系统所留下的历史数据非常重要,一般情况下,我们可以通过相应的些历史数据初步判定这个系统哪些接口调用的比较多、哪些 service 承受的压力最大,这样的话,我们就可以针对这些地方进行更细致的性能测试与分析。 +当前系统所留下的历史数据非常重要,一般情况下,我们可以通过相应的些历史数据初步判定这个系统哪些接口调用的比较多、哪些服务承受的压力最大,这样的话,我们就可以针对这些地方进行更细致的性能测试与分析。 另外,这些地方也就像这个系统的一个短板一样,优化好了这些地方会为我们的系统带来质的提升。 -### 三 性能测试的指标 +## 常见性能指标 -### 3.1 响应时间 +### 响应时间 -**响应时间就是用户发出请求到用户收到系统处理结果所需要的时间。** 重要吗?实在太重要! +**响应时间 RT(Response-time)就是用户发出请求到用户收到系统处理结果所需要的时间。** -比较出名的 2-5-8 原则是这样描述的:通常来说,2 到 5 秒,页面体验会比较好,5 到 8 秒还可以接受,8 秒以上基本就很难接受了。另外,据统计当网站慢一秒就会流失十分之一的客户。 +RT 是一个非常重要且直观的指标,RT 数值大小直接反应了系统处理用户请求速度的快慢。 -但是,在某些场景下我们也并不需要太看重 2-5-8 原则 ,比如我觉得系统导出导入大数据量这种就不需要,系统生成系统报告这种也不需要。 +### 并发数 -### 3.2 并发数 +**并发数可以简单理解为系统能够同时供多少人访问使用也就是说系统同时能处理的请求数量。** -**并发数是系统能同时处理请求的数目即同时提交请求的用户数目。** +并发数反应了系统的负载能力。 -不得不说,高并发是现在后端架构中非常非常火热的一个词了,这个与当前的互联网环境以及中国整体的互联网用户量都有很大关系。一般情况下,你的系统并发量越大,说明你的产品做的就越大。但是,并不是每个系统都需要达到像淘宝、12306 这种亿级并发量的。 +### QPS 和 TPS -### 3.3 吞吐量 - -吞吐量指的是系统单位时间内系统处理的请求数量。衡量吞吐量有几个重要的参数:QPS(TPS)、并发数、响应时间。 - -1. QPS(Query Per Second):服务器每秒可以执行的查询次数; -2. TPS(Transaction Per Second):服务器每秒处理的事务数(这里的一个事务可以理解为客户发出请求到收到服务器的过程); -3. 并发数;系统能同时处理请求的数目即同时提交请求的用户数目。 -4. 响应时间:一般取多次请求的平均响应时间 - -理清他们的概念,就很容易搞清楚他们之间的关系了。 - -- **QPS(TPS)** = 并发数/平均响应时间 -- **并发数** = QPS\*平均响应时间 +- **QPS(Query Per Second)** :服务器每秒可以执行的查询次数; +- **TPS(Transaction Per Second)** :服务器每秒处理的事务数(这里的一个事务可以理解为客户发出请求到收到服务器的过程); 书中是这样描述 QPS 和 TPS 的区别的。 > QPS vs TPS:QPS 基本类似于 TPS,但是不同的是,对于一个页面的一次访问,形成一个 TPS;但一次页面请求,可能产生多次对服务器的请求,服务器对这些请求,就可计入“QPS”之中。如,访问一个页面会请求服务器 2 次,一次访问,产生一个“T”,产生 2 个“Q”。 -### 3.4 性能计数器 +### 吞吐量 -**性能计数器是描述服务器或者操作系统的一些数据指标如内存使用、CPU 使用、磁盘与网络 I/O 等情况。** +**吞吐量指的是系统单位时间内系统处理的请求数量。** -### 四 几种常见的性能测试 +一个系统的吞吐量与请求对系统的资源消耗等紧密关联。请求对系统资源消耗越多,系统吞吐能力越低,反之则越高。 + +TPS、QPS 都是吞吐量的常用量化指标。 + +- **QPS(TPS)** = 并发数/平均响应时间(RT) +- **并发数** = QPS \* 平均响应时间(RT) + +## 系统活跃度指标 + +### PV(Page View) + +访问量, 即页面浏览量或点击量,衡量网站用户访问的网页数量;在一定统计周期内用户每打开或刷新一个页面就记录 1 次,多次打开或刷新同一页面则浏览量累计。UV 从网页打开的数量/刷新的次数的角度来统计的。 + +### UV(Unique Visitor) + +独立访客,统计 1 天内访问某站点的用户数。1 天内相同访客多次访问网站,只计算为 1 个独立访客。UV 是从用户个体的角度来统计的。 + +### DAU(Daily Active User) + +日活跃用户数量。 + +### MAU(monthly active users) + +月活跃用户人数。 + +举例:某网站 DAU 为 1200w, 用户日均使用时长 1 小时,RT 为 0.5s,求并发量和 QPS。 + +平均并发量 = DAU(1200w)\* 日均使用时长(1 小时,3600 秒) /一天的秒数(86400)=1200w/24 = 50w + +真实并发量(考虑到某些时间段使用人数比较少) = DAU(1200w)\* 日均使用时长(1 小时,3600 秒) /一天的秒数-访问量比较小的时间段假设为 8 小时(57600)=1200w/16 = 75w + +峰值并发量 = 平均并发量 \* 6 = 300w + +QPS = 真实并发量/RT = 75W/0.5=150w/s + +## 性能测试分类 ### 性能测试 @@ -118,25 +142,27 @@ icon: et-performance 模拟真实场景,给系统一定压力,看看业务是否能稳定运行。 -## 五 常用性能测试工具 +## 常用性能测试工具 -这里就不多扩展了,有时间的话会单独拎一个熟悉的说一下。 +### 后端常用 -### 5.1 后端常用 +既然系统设计涉及到系统性能方面的问题,那在面试的时候,面试官就很可能会问:**你是如何进行性能测试的?** -没记错的话,除了 LoadRunner 其他几款性能测试工具都是开源免费的。 +推荐 4 个比较常用的性能测试工具: -1. Jmeter:Apache JMeter 是 JAVA 开发的性能测试工具。 -2. LoadRunner:一款商业的性能测试工具。 -3. Galtling:一款基于 Scala 开发的高性能服务器性能测试工具。 -4. ab:全称为 Apache Bench 。Apache 旗下的一款测试工具,非常实用。 +1. **Jmeter** :Apache JMeter 是 JAVA 开发的性能测试工具。 +2. **LoadRunner**:一款商业的性能测试工具。 +3. **Galtling** :一款基于 Scala 开发的高性能服务器性能测试工具。 +4. **ab** :全称为 Apache Bench 。Apache 旗下的一款测试工具,非常实用。 -### 5.2 前端常用 +没记错的话,除了 **LoadRunner** 其他几款性能测试工具都是开源免费的。 -1. Fiddler:抓包工具,它可以修改请求的数据,甚至可以修改服务器返回的数据,功能非常强大,是 Web 调试的利器。 -2. HttpWatch: 可用于录制 HTTP 请求信息的工具。 +### 前端常用 -## 六 常见的性能优化策略 +1. **Fiddler**:抓包工具,它可以修改请求的数据,甚至可以修改服务器返回的数据,功能非常强大,是 Web 调试的利器。 +2. **HttpWatch**: 可用于录制 HTTP 请求信息的工具。 + +## 常见的性能优化策略 性能优化之前我们需要对请求经历的各个环节进行分析,排查出可能出现性能瓶颈的地方,定位问题。 diff --git a/docs/high-performance/images/message-queue/message-queue-pub-sub-model.png b/docs/high-performance/images/message-queue/message-queue-pub-sub-model.png deleted file mode 100644 index a5a77736..00000000 Binary files a/docs/high-performance/images/message-queue/message-queue-pub-sub-model.png and /dev/null differ diff --git a/docs/high-performance/images/message-queue/message-queue-queue-model.png b/docs/high-performance/images/message-queue/message-queue-queue-model.png deleted file mode 100644 index 8fb2cd6a..00000000 Binary files a/docs/high-performance/images/message-queue/message-queue-queue-model.png and /dev/null differ diff --git a/docs/high-performance/message-queue/message-queue.md b/docs/high-performance/message-queue/message-queue.md index 672b9dc7..50582cdd 100644 --- a/docs/high-performance/message-queue/message-queue.md +++ b/docs/high-performance/message-queue/message-queue.md @@ -23,9 +23,9 @@ tag: 参与消息传递的双方称为 **生产者** 和 **消费者** ,生产者负责发送消息,消费者负责处理消息。 -![发布/订阅(Pub/Sub)模型](../images/message-queue/message-queue-pub-sub-model.png) +![发布/订阅(Pub/Sub)模型](https://oss.javaguide.cn/github/javaguide/high-performance/message-queue/message-queue-pub-sub-model.png) -我们知道操作系统中的进程通信的一种很重要的方式就是消息队列。我们这里提到的消息队列稍微有点区别,更多指的是各个服务以及系统内部各个组件/模块之前的通信,属于一种 **中间件** 。 +操作系统中的进程通信的一种很重要的方式就是消息队列。我们这里提到的消息队列稍微有点区别,更多指的是各个服务以及系统内部各个组件/模块之前的通信,属于一种 **中间件** 。 维基百科是这样介绍中间件的: @@ -43,7 +43,7 @@ tag: 通常来说,使用消息队列主要能为我们的系统带来下面三点好处: -1. 通过异步处理提高系统性能(减少响应所需时间) +1. 异步处理 2. 削峰/限流 3. 降低系统耦合性 @@ -51,11 +51,11 @@ tag: 如果在面试的时候你被面试官问到这个问题的话,一般情况是你在你的简历上涉及到消息队列这方面的内容,这个时候推荐你结合你自己的项目来回答。 -### 通过异步处理提高系统性能(减少响应时间) +### 异步处理 ![通过异步处理提高系统性能](https://oss.javaguide.cn/github/javaguide/Asynchronous-message-queue.png) -将用户的请求数据存储到消息队列之后就立即返回结果。随后,系统再对消息进行消费。 +将用户请求中包含的耗时操作,通过消息队列实现异步处理,将对应的消息发送到消息队列之后就立即返回结果,减少响应时间,提高用户体验。随后,系统再对消息进行消费。 因为用户请求数据写入消息队列之后就立即返回给用户了,但是请求数据在后续的业务校验、写数据库等操作中可能失败。因此,**使用消息队列进行异步处理之后,需要适当修改业务流程进行配合**,比如用户在提交订单之后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单之后,甚至出库后,再通过电子邮件或短信通知用户订单成功,以免交易纠纷。这就类似我们平时手机订火车票和电影票。 @@ -69,11 +69,11 @@ tag: ### 降低系统耦合性 -使用消息队列还可以降低系统耦合性。我们知道如果模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块影响较小,这样系统的可扩展性无疑更好一些。还是直接上图吧: +使用消息队列还可以降低系统耦合性。如果模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块影响较小,这样系统的可扩展性无疑更好一些。 -![解耦](https://oss.javaguide.cn/github/javaguide/high-performance/message-queue/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97-%E8%A7%A3%E8%80%A6.png) +生产者(客户端)发送消息到消息队列中去,消费者(服务端)处理消息,需要消费的系统直接去消息队列取消息进行消费即可而不需要和其他系统有耦合,这显然也提高了系统的扩展性。 -生产者(客户端)发送消息到消息队列中去,接受者(服务端)处理消息,需要消费的系统直接去消息队列取消息进行消费即可而不需要和其他系统有耦合,这显然也提高了系统的扩展性。 +![发布/订阅(Pub/Sub)模型](https://oss.javaguide.cn/github/javaguide/high-performance/message-queue/message-queue-pub-sub-model.png) **消息队列使用发布-订阅模式工作,消息发送者(生产者)发布消息,一个或多个消息接受者(消费者)订阅消息。** 从上图可以看到**消息发送者(生产者)和消息接受者(消费者)之间没有直接耦合**,消息发送者将消息发送至分布式消息队列即结束对消息的处理,消息接受者从分布式消息队列获取该消息后进行后续处理,并不需要知道该消息从何而来。**对新增业务,只要对该类消息感兴趣,即可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展性设计**。 @@ -87,7 +87,7 @@ tag: ### 实现分布式事务 -我们知道分布式事务的解决方案之一就是 MQ 事务。 +分布式事务的解决方案之一就是 MQ 事务。 RocketMQ、 Kafka、Pulsar、QMQ 都提供了事务相关的功能。事务允许事件流应用将消费,处理,生产消息整个过程定义为一个原子操作。 @@ -103,6 +103,14 @@ RocketMQ、 Kafka、Pulsar、QMQ 都提供了事务相关的功能。事务允 消息发送后不会立即被消费,而是指定一个时间,到时间后再消费。大部分消息队列,例如 RocketMQ、RabbitMQ、Pulsar、Kafka,都支持定时/延时消息。 +![](https://oss.javaguide.cn/github/javaguide/tools/docker/rocketmq-schedule-message.png) + +### 即时通讯 + +MQTT(消息队列遥测传输协议)是一种轻量级的通讯协议,采用发布/订阅模式,非常适合于物联网(IoT)等需要在低带宽、高延迟或不可靠网络环境下工作的应用。它支持即时消息传递,即使在网络条件较差的情况下也能保持通信的稳定性。 + +RabbitMQ 内置了 MQTT 插件用于实现 MQTT 功能(默认不启用,需要手动开启)。 + ### 数据流处理 针对分布式系统产生的海量数据流,如业务日志、监控数据、用户行为等,消息队列可以实时或批量收集这些数据,并将其导入到大数据处理引擎中,实现高效的数据流管理和处理。 @@ -133,13 +141,13 @@ JMS 定义了五种不同的消息正文格式以及调用的消息类型,允 #### 点到点(P2P)模型 -![队列模型](../images/message-queue/message-queue-queue-model.png) +![队列模型](https://oss.javaguide.cn/github/javaguide/high-performance/message-queue/message-queue-queue-model.png) 使用**队列(Queue)**作为消息通信载体;满足**生产者与消费者模式**,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。比如:我们生产者发送 100 条消息的话,两个消费者来消费一般情况下两个消费者会按照消息发送的顺序各自消费一半(也就是你一个我一个的消费。) #### 发布/订阅(Pub/Sub)模型 -![发布/订阅(Pub/Sub)模型](../images/message-queue/message-queue-pub-sub-model.png) +![发布/订阅(Pub/Sub)模型](https://oss.javaguide.cn/github/javaguide/high-performance/message-queue/message-queue-pub-sub-model.png) 发布订阅模型(Pub/Sub) 使用**主题(Topic)**作为消息通信载体,类似于**广播模式**;发布者发布一条消息,该消息通过主题传递给所有的订阅者。 diff --git a/docs/open-source-project/system-design.md b/docs/open-source-project/system-design.md index e4197052..d3a3e92b 100644 --- a/docs/open-source-project/system-design.md +++ b/docs/open-source-project/system-design.md @@ -71,6 +71,7 @@ icon: "xitongsheji" - [MyBatis-Plus](https://github.com/baomidou/mybatis-plus) : [MyBatis](http://www.mybatis.org/mybatis-3/) 增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 - [MyBatis-Flex](https://gitee.com/mybatis-flex/mybatis-flex):一个优雅的 MyBatis 增强框架,无其他任何第三方依赖,支持 CRUD、分页查询、多表查询、批量操作。 +- [jOOQ](https://github.com/jOOQ/jOOQ):用 Java 编写 SQL 的最佳方式。 - [Redisson](https://github.com/redisson/redisson "redisson"):Redis 基础上的一个 Java 驻内存数据网格(In-Memory Data Grid),支持超过 30 个对象和服务:`Set`,`SortedSet`, `Map`, `List`, `Queue`, `Deque` ……,并且提供了多种分布式锁的实现。更多介绍请看:[《Redisson 项目介绍》](https://github.com/redisson/redisson/wiki/Redisson%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D "Redisson项目介绍")。 ### 数据同步 diff --git a/docs/readme.md b/docs/readme.md index 483e0b25..ec8e0b87 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -20,7 +20,7 @@ footer: |- JavaGuide 已经持续维护 5 年多了,累计提交了 **5000+** commit ,共有 **440** 多位朋友参与维护。真心希望能够把这个项目做好,真正能够帮助到有需要的朋友! -如果觉得 JavaGuide 的内容对你有帮助的话,还请点个免费的 Star(绝不强制点 Star,你觉得内容不错再点赞就好),这是对我最大的鼓励,感谢各位一起同行,共勉!传送门:[GitHub](https://github.com/Snailclimb/JavaGuide) | [Gitee](https://gitee.com/SnailClimb/JavaGuide)。 +如果觉得 JavaGuide 的内容对你有帮助的话,还请点个免费的 Star(绝不强制点 Star,觉得内容不错有收货再点赞就好),这是对我最大的鼓励,感谢各位一路同行,共勉!传送门:[GitHub](https://github.com/Snailclimb/JavaGuide) | [Gitee](https://gitee.com/SnailClimb/JavaGuide)。 - [项目介绍](./javaguide/intro.md) - [贡献指南](./javaguide/contribution-guideline.md)