作者:微信小助手
<p data-mpa-powered-by="yiban.io" style="margin-right: 8px;margin-left: 8px;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">消息中间件是分布式系统常用的组件,无论是异步化、解耦、削峰等都有广泛的应用价值。</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p data-mpa-powered-by="yiban.io" style="margin-right: 8px;margin-left: 8px;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.75" src="/upload/919a82fce2ab39681d96bb324a50e1ae.jpg" data-type="jpeg" data-w="1280"></span></p> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">我们通常会认为,消息中间件是一个可靠的组件——这里所谓的可靠是指,只要我把消息成功投递到了消息中间件,消息就不会丢。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">即消息肯定会至少保证消息能被消费者成功消费一次,这是消息中间件最基本的特性之一。</strong></span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">也就是我们常说的“AT LEAST ONCE”,即消息至少会被“成功消费一遍”。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.8896797153024911" data-type="jpeg" data-w="281" src="/upload/6262ac4e308b779f7fd13f1eb8e7b25b.jpg" style="outline: 0px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 84px !important;"> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">一个消息 M 发送到了消息中间件,消息投递到了消费程序 A。A 接受到了消息,然后进行消费。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">但在消费到一半的时候程序重启了,这时候这个消息并没有标记为消费成功,这个消息还会继续投递给这个消费者,直到其消费成功了,消息中间件才会停止投递。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">然而这种可靠的特性会导致消息可能被多次地投递。</strong></span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">还是刚刚这个例子。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">程序 A 接受到这个消息 M 并完成消费逻辑之后,正想通知消息中间件“我已经消费成功了”的时候,程序就重启了,那么对于消息中间件来说,这个消息并没有成功消费过,所以它还会继续投递。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">这时候对于应用程序 A 来说,看起来就是这个消息明明消费成功了,但是消息中间件还在重复投递。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">这在 RockectMQ 的场景来看,就是同一个 messageId 的消息重复投递下来了。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">基于消息的投递可靠(消息不丢)是优先级更高的,所以消息不重的任务就会转移到应用程序自我实现,这也是为什么 RocketMQ 的文档里强调的,消费逻辑需要自我实现幂等。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">背后的逻辑其实就是:不丢和不重是矛盾的(在分布式场景下),但消息重复是有解决方案的,而消息丢失是很麻烦的。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">关于 RocketMQ 消息重复的场景,官方文档上给出了这三种情况:</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1.发送时消息重复</strong></span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">当一条消息已被成功发送到服务端并完成持久化,此时出现了网络闪断或者客户端宕机,导致服务端对客户端应答失败。如果此时生产者意识到消息发送失败并尝试再次发送消息,消费者后续会收到两条内容相同并且Message ID也相同的消息。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">2.投递时消息重复</strong></span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">消息消费的场景下,消息已投递到消费者并完成业务处理,当客户端给服务端反馈应答的时候网络闪断。为了保证消息至少被消费一次,消息队列RocketMQ版的服务端将在网络恢复后再次尝试投递之前已被处理过的消息,消费者后续会收到两条内容相同并且Message ID也相同的消息。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">3.<strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">负载均衡时消息重复</strong>(包括但不限于网络抖动、Broker重启以及消费者应用重启)</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">当消息队列RocketMQ版的Broker或客户端重启、扩容或缩容时,会触发Rebalance,此时消费者可能会收到重复消息。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">那么,有什么解决方案呢?</span> </section> <h2 data-tool="mdnice编辑器" style="margin: 15px 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 17px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></strong><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 17px;box-sizing: border-box !important;overflow-wrap: break-word !important;">简单的消息去重解决方案</span></strong></h2> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">假设我们业务的消息消费逻辑是:插入某张订单表的数据,然后更新库存。</span> </section> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <pre style="outline: 0px;max-width: 100%;background: none;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 8px;margin-left: 8px;padding: 5.20625px;outline: 0px;max-width: 100%;border-radius: 4px;font-size: 0.85em;background: rgb(248, 248, 248);overflow-x: auto;white-space: nowrap;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 39px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">insert</span> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 26px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">into</span> t_order <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 39px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">values</span> ..... <br mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 39px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">update</span> t_inv <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 19px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">set</span> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 33px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">count</span> = <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 33px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">count</span> <span style="outline: 0px;max-width: 100%;color: rgb(0, 128, 128);background: rgba(0, 0, 0, 0);width: 13px;text-decoration-style: solid;text-decoration-color: rgb(0, 128, 128);box-sizing: border-box !important;overflow-wrap: break-word !important;">-1</span> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 33px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">where</span> good_id = <span style="outline: 0px;max-width: 100%;color: rgb(221, 17, 68);background: rgba(0, 0, 0, 0);width: 60px;text-decoration-style: solid;text-decoration-color: rgb(221, 17, 68);box-sizing: border-box !important;overflow-wrap: break-word !important;">'good123'</span>; </section></pre> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">要实现消息的幂等,我们可能会采取这样的方案:</span> </section> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <pre style="outline: 0px;max-width: 100%;background: none;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 8px;margin-left: 8px;padding: 5.20625px;outline: 0px;max-width: 100%;border-radius: 4px;font-size: 0.85em;background: rgb(248, 248, 248);overflow-x: auto;white-space: nowrap;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 13px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 39px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">select</span> * <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 27px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">from</span> t_order <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 33px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">where</span> order_no = <span style="outline: 0px;max-width: 100%;color: rgb(221, 17, 68);background: rgba(0, 0, 0, 0);width: 66px;text-decoration-style: solid;text-decoration-color: rgb(221, 17, 68);box-sizing: border-box !important;overflow-wrap: break-word !important;">'order123'</span><br mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 13px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">if</span>(order != <span style="outline: 0px;max-width: 100%;color: rgb(0, 128, 128);background: rgba(0, 0, 0, 0);width: 26px;text-decoration-style: solid;text-decoration-color: rgb(0, 128, 128);box-sizing: border-box !important;overflow-wrap: break-word !important;">null</span>) {<br mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 40px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">return</span> ;<span style="outline: 0px;max-width: 100%;color: rgb(153, 153, 136);background: rgba(0, 0, 0, 0);width: 121px;text-decoration-style: solid;text-decoration-color: rgb(153, 153, 136);font-style: italic;box-sizing: border-box !important;overflow-wrap: break-word !important;">//消息重复,直接返回</span><br mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}</span> </section></pre> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">这对于很多情况下,的确能起到不错的效果,但是在并发场景下,还是会有问题。</span> </section> <h2 data-tool="mdnice编辑器" style="margin: 15px 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 17px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span></strong><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 17px;box-sizing: border-box !important;overflow-wrap: break-word !important;">并发重复消息</span></strong></h2> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">假设这个消费的所有代码加起来需要 1 秒,有重复的消息在这 1 秒内(假设 100 毫秒)内到达。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">例如生产者快速重发,Broker 重启等。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">那么很可能,上面去重代码里面会发现,数据依然是空的,因为上一条消息还没消费完,还没成功更新订单状态。</span> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">具体一点就是两个线程在间隔非常短甚至是同时执行这个逻辑:</span> </section> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <pre style="outline: 0px;max-width: 100%;background: none;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 8px;margin-left: 8px;padding: 5.20625px;outline: 0px;max-width: 100%;border-radius: 4px;font-size: 0.85em;background: rgb(248, 248, 248);overflow-x: auto;white-space: nowrap;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 13px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 39px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">select</span> * <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 27px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">from</span> t_order <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 33px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">where</span> order_no = <span style="outline: 0px;max-width: 100%;color: rgb(221, 17, 68);background: rgba(0, 0, 0, 0);width: 66px;text-decoration-style: solid;text-decoration-color: rgb(221, 17, 68);box-sizing: border-box !important;overflow-wrap: break-word !important;">'order123'</span></span> </section></pre> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">然后发现都没有查到数据,于是走入到这个逻辑中:</span> <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <pre style="outline: 0px;max-width: 100%;background: none;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 8px;margin-left: 8px;padding: 5.20625px;outline: 0px;max-width: 100%;border-radius: 4px;font-size: 0.85em;background: rgb(248, 248, 248);overflow-x: auto;white-space: nowrap;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 13px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 13px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">if</span>(order != <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 26px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">null</span>) {<br mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 40px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">return</span> ;<span style="outline: 0px;max-width: 100%;color: rgb(153, 153, 136);background: rgba(0, 0, 0, 0);width: 121px;text-decoration-style: solid;text-decoration-color: rgb(153, 153, 136);font-style: italic;box-sizing: border-box !important;overflow-wrap: break-word !important;">//消息重复,直接返回</span><br mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}</span> </section></pre> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">那么就会穿透掉检查的挡板,最后导致重复的消息消费逻辑进入到非幂等安全的业务代码中,从而引发重复消费的问题,如主键冲突抛出异常、库存被重复扣减而没释放等。</span> </section> <section style="margin-right: 8px;margin-bottom: 10px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;">要解决上面并发场景下的消息幂等问题,一个可取的方案是开启事务把 select 改成 select for update 语句,把记录进行锁定:</span> </section> <section data-mpa-preserve-tpl-color="t" data-mpa-template="t" mpa-preserve="t" mpa-from-tpl="t" style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <pre style="outline: 0px;max-width: 100%;background: none;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-right: 8px;margin-left: 8px;padding: 5.20625px;outline: 0px;max-width: 100%;border-radius: 4px;font-size: 0.85em;background: rgb(248, 248, 248);overflow-x: auto;white-space: nowrap;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 39px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">select</span> * <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 27px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">from</span> t_order <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 33px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">where</span> order_no = <span style="outline: 0px;max-width: 100%;color: rgb(221, 17, 68);background: rgba(0, 0, 0, 0);width: 99px;text-decoration-style: solid;text-decoration-color: rgb(221, 17, 68);box-sizing: border-box !important;overflow-wrap: break-word !important;">'THIS_ORDER_NO'</span> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 19px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">for</span> update <span style="outline: 0px;max-width: 100%;color: rgb(153, 153, 136);background: rgba(0, 0, 0, 0);width: 61px;text-decoration-style: solid;text-decoration-color: rgb(153, 153, 136);font-style: italic;box-sizing: border-box !important;overflow-wrap: break-word !important;">//开启事务</span> <br mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 13px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">if</span>(order.status != <span style="outline: 0px;max-width: 100%;color: rgb(0, 128, 128);background: rgba(0, 0, 0, 0);width: 27px;text-decoration-style: solid;text-decoration-color: rgb(0, 128, 128);box-sizing: border-box !important;overflow-wrap: break-word !important;">null</span>) { <br mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;background: rgba(0, 0, 0, 0);width: 40px;text-decoration-style: solid;text-decoration-color: rgb(51, 51, 51);font-weight: 700;box-sizing: border-box !important;overflow-wrap: break-word !important;">return</span> ; <span style="outline: 0px;max-width: 100%;color: rgb(153, 153, 136);background: rgba(0, 0, 0, 0);width: 121px;text-decoration-style: solid;text-decoration-color: rgb(153, 153, 136);font-style: italic;box-sizing: border-box !important;overflow-wrap: break-word !important;">//消息重复,直接返回</span> <br mpa-from-tpl="t" style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">} </section></pre> </section> <section style="margin-right: 8px;margin-left: 8px;padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;font-size: 15px;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-w
作者:微信小助手
<section class="mp_profile_iframe_wrp" data-mpa-powered-by="yiban.io"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzA5MTU0OTY0Ng==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/zc3KLDBfJlmPt0J5PXYOoiaG8wsQPZrLevbxMZSfgQ0YypNYaicnbS0P9UicluuOySLSP4CjTcRUVHCZzYeXQ9WlA/0?wx_fmt=png" data-nickname="Java派" data-alias="javapai" data-signature="专注Java相关技术栈:Spring全家筒、Docker、k8s、Mysql、集群、微服务、中间件等知识。" data-from="0"></mpprofile> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;line-height: 1.6;letter-spacing: 0.034em;color: rgb(63, 63, 63);font-size: 16px;"> <h1 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 24px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/CKvMdchsUwme4OFNzAXCM5sZMZdMbysRxUeu0xF2koDqvh4MHLwJNyAwiaC4EibBibKePnf8WJvlgYwUqnjOscX1w/640?wx_fmt=png");background-position: center top;background-repeat: no-repeat;background-size: 75px;line-height: 95px;margin-top: 38px;margin-bottom: 10px;"></h1> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(106, 115, 125);margin-bottom: 20px;margin-top: 20px;padding: 15px 20px;line-height: 27px;border-left-color: rgb(53, 179, 120);"> <section style="font-size: 15px;color: rgb(89, 89, 89);line-height: normal;"> <span style="font-size: 12px;color: rgb(214, 214, 214);">作者:云深i不知处</span> </section> <section style="font-size: 15px;color: rgb(89, 89, 89);line-height: normal;"> <span style="font-size: 12px;color: rgb(214, 214, 214);">来源:blog.csdn.net/mu_wind/article/details/109516995</span> </section> </blockquote> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7512899896800825" src="/upload/d508eee23bb5ba57a86ea1dd14e496aa.png" data-type="png" data-w="969" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">大家好,我先贴上几个案例,水平高超的同学可以挑战一下:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">从员工集合中筛选出salary大于8000的员工,并放置到新的集合里。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">统计员工的最高薪资、平均薪资、薪资之和。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">将员工按薪资从高到低排序,同样薪资者年龄小者在前。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">将员工按性别分类,将员工按性别和地区分类,将员工按薪资是否高于8000分为两部分。</p> </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">用传统的迭代处理也不是很难,但代码就显得冗余了,跟Stream相比高下立判。Java 8 是一个非常成功的版本,这个版本新增的<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Stream</code>,配合同版本出现的 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Lambda</code> ,给我们操作集合(Collection)提供了极大的便利。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/CKvMdchsUwme4OFNzAXCM5sZMZdMbysRSiaE6MkfnpibsDBJxniafUhM6UK4ICId9QBQEW1O54JhWKUXwflkWMP9Q/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">那么什么是<code>Stream</code>?</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Stream</code>将要处理的元素集合看作一种流,在流的过程中,借助<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Stream API</code>对流中的元素进行操作,比如:筛选、排序、聚合等。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Stream</code>可以由数组或集合创建,对流的操作分为两种:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">中间操作,每次返回一个新的流,可以有多个。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。</p> </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">另外,<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Stream</code>有几个特性:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">stream不会改变数据源,通常情况下会产生一个新的集合或一个值。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <p style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。</p> </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Stream</code>可以通过集合数组创建。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">1、通过 <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">java.util.Collection.stream()</code> 方法用集合创建流</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">List<String> list = Arrays.asList(<span style="color: #98c379;line-height: 26px;">"a"</span>, <span style="color: #98c379;line-height: 26px;">"b"</span>, <span style="color: #98c379;line-height: 26px;">"c"</span>);<br><span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建一个顺序流</span><br>Stream<String> stream = list.stream();<br><span style="color: #5c6370;font-style: italic;line-height: 26px;">// 创建一个并行流</span><br>Stream<String> parallelStream = list.parallelStream();<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">2、使用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">java.util.Arrays.stream(T[] array)</code>方法用数组创建流</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #c678dd;line-height: 26px;">int</span>[] array={<span style="color: #d19a66;line-height: 26px;">1</span>,<span style="color: #d19a66;line-height: 26px;">3</span>,<span style="color: #d19a66;line-height: 26px;">5</span>,<span style="color: #d19a66;line-height: 26px;">6</span>,<span style="color: #d19a66;line-height: 26px;">8</span>};<br>IntStream stream = Arrays.stream(array);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">3、使用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Stream</code>的静态方法:<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">of()、iterate()、generate()</code></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">Stream<Integer> stream = Stream.of(<span style="color: #d19a66;line-height: 26px;">1</span>, <span style="color: #d19a66;line-height: 26px;">2</span>, <span style="color: #d19a66;line-height: 26px;">3</span>, <span style="color: #d19a66;line-height: 26px;">4</span>, <span style="color: #d19a66;line-height: 26px;">5</span>, <span style="color: #d19a66;line-height: 26px;">6</span>);<br><br>Stream<Integer> stream2 = Stream.iterate(<span style="color: #d19a66;line-height: 26px;">0</span>, (x) -> x + <span style="color: #d19a66;line-height: 26px;">3</span>).limit(<span style="color: #d19a66;line-height: 26px;">4</span>);<br>stream2.forEach(System.out::println);<br><br>Stream<Double> stream3 = Stream.generate(Math::random).limit(<span style="color: #d19a66;line-height: 26px;">3</span>);<br>stream3.forEach(System.out::println);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">输出结果:</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(106, 115, 125);margin-bottom: 20px;margin-top: 20px;padding: 15px 20px;line-height: 27px;border-left-color: rgb(53, 179, 120);"> <p style="line-height: 26px;font-size: 15px;color: rgb(89, 89, 89);">0 3 6 9 0.6796156909271994 0.1914314208854283 0.8116932592396652</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">stream</code>和<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">parallelStream</code>的简单区分:</strong> <code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">stream</code>是顺序流,由主线程按顺序对流执行操作,而<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">parallelStream</code>是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如筛选集合中的奇数,两者的处理不同之处:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7913043478260869" src="/upload/ece19ebc6d8e6cec578f96607f85db08.png" data-type="png" data-w="690" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">如果流中的数据量足够大,并行流可以加快处速度。除了直接创建并行流,还可以通过<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">parallel()</code>把顺序流转换成并行流:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">Optional<Integer> findFirst = list.stream().parallel().filter(x->x><span style="color: #d19a66;line-height: 26px;">6</span>).findFirst();<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">在使用stream之前,先理解一个概念:<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Optional</code> 。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(106, 115, 125);margin-bottom: 20px;margin-top: 20px;padding: 15px 20px;line-height: 27px;border-left-color: rgb(53, 179, 120);"> <p style="line-height: 26px;font-size: 15px;color: rgb(89, 89, 89);"><code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">Optional</code>类是一个可以为<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">null</code>的容器对象。如果值存在则<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">isPresent()</code>方法会返回<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">true</code>,调用<code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">get()</code>方法会返回该对象。更详细说明请见:菜鸟教程Java 8 Optional类</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><strong style="line-height: 1.75em;">接下来,大批代码向你袭来!我将用20个案例将Stream的使用整得明明白白,只要跟着敲一遍代码,就能很好地掌握。</strong></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.9501915708812261" src="/upload/b2c0cb53421138f4716bf46cddedc879.png" data-type="png" data-w="261" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/CKvMdchsUwme4OFNzAXCM5sZMZdMbysRSiaE6MkfnpibsDBJxniafUhM6UK4ICId9QBQEW1O54JhWKUXwflkWMP9Q/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">案例使用的员工类</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这是后面案例中使用的员工类:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">List<Person> personList = <span style="color: #c678dd;line-height: 26px;">new</span> ArrayList<Person>();<br>personList.add(<span style="color: #c678dd;line-height: 26px;">new</span> Person(<span style="color: #98c379;line-height: 26px;">"Tom"</span>, <span style="color: #d19a66;line-height: 26px;">8900</span>, <span style="color: #98c379;line-height: 26px;">"male"</span>, <span style="color: #98c379;line-height: 26px;">"New York"</span>));<br>personList.add(<span style="color: #c678dd;line-height: 26px;">new</span> Person(<span style="color: #98c379;line-height: 26px;">"Jack"</span>, <span style="color: #d19a66;line-height: 26px;">7000</span>, <span style="color: #98c379;line-height: 26px;">"male"</span>, <span style="color: #98c379;line-height: 26px;">"Washington"</span>));<br>personList.add(<span style="color: #c678dd;line-height: 26px;">new</span> Person(<span style="color: #98c379;line-height: 26px;">"Lily"</span>, <span style="color: #d19a66;line-height: 26px;">7800</span>, <span style="color: #98c379;line-height: 26px;">"female"</span>, <span style="color: #98c379;line-height: 26px;">"Washington"</span>));<br>personList.add(<span style="color: #c678dd;line-height: 26px;">new</span> Person(<span style="color: #98c379;line-height: 26px;">"Anni"</span>, <span style="color: #d19a66;line-height: 26px;">8200</span>, <span style="color: #98c379;line-height: 26px;">"female"</span>, <span style="color: #98c379;line-height: 26px;">"New York"</span>));<br>personList.add(<span style="color: #c678dd;line-height: 26px;">new</span> Person(<span style="color: #98c379;line-height: 26px;">"Owen"</span>, <span style="color: #d19a66;line-height: 26px;">9500</span>, <span style="color: #98c379;line-height: 26px;">"male"</span>, <span style="color: #98c379;line-height: 26px;">"New York"</span>));<br>personList.add(<span style="color: #c678dd;line-height: 26px;">new</span> Person(<span style="color: #98c379;line-height: 26px;">"Alisa"</span>, <span style="color: #d19a66;line-height: 26px;">7900</span>, <span style="color: #98c379;line-height: 26px;">"female"</span>, <span style="color: #98c379;line-height: 26px;">"New York"</span>));<br><br><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span> <span style="color: #e6c07b;line-height: 26px;">Person</span> </span>{<br> <span style="color: #c678dd;line-height: 26px;">private</span> String name; <span style="color: #5c6370;font-style: italic;line-height: 26px;">// 姓名</span><br> <span style="color: #c678dd;line-height: 26px;">private</span> <s
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;" data-mpa-powered-by="yiban.io"> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">前言</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">日志是快速定位问题的好帮手,是<strong>撕逼和甩锅</strong>的利器!打印好日志非常重要。今天我们来聊聊<strong>日志打印</strong>的15个好建议~</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">1. 选择恰当的日志级别</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">常见的日志级别有5种,分别是error、warn、info、debug、trace。日常开发中,我们需要选择恰当的日志级别,不要反手就是打印info哈~</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.06" src="/upload/3838ca7733a3cce415f60d6cc82fe0b0.jpg" data-type="jpeg" data-w="200" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> error:错误日志,指比较严重的错误,对正常业务有影响,需要 <strong style="color: black;">运维配置监控的</strong>; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> warn:警告日志,一般的错误,对业务影响不大,但是需要 <strong style="color: black;">开发关注</strong>; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> info:信息日志,记录排查问题的关键信息,如调用时间、出参入参等等; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> debug:用于开发DEBUG的,关键逻辑里面的运行时数据; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> trace:最详细的信息,一般这些信息只记录到日志文件中。 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">2. 日志要打印出方法的入参、出参</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我们并不需要打印很多很多日志,只需要打印可以<strong>快速定位问题的有效日志</strong>。有效的日志,是甩锅的利器!</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.0208333333333333" src="/upload/bc30d3e9b71059487e92aba68a691538.png" data-type="png" data-w="240" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">哪些算得的上<strong>有效关键</strong>的日志呢?比如说,方法进来的时候,打印<strong>入参</strong>。再然后呢,在方法返回的时候,就是<strong>打印出参,返回值</strong>。入参的话,一般就是<strong>userId或者bizSeq这些关键</strong>信息。正例如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">public String testLogMethod(Document doc, Mode mode){<br> log.debug(“method enter param:{}”,userId);<br> String id = <span style="color: #a6e22e;line-height: 26px;">"666"</span>;<br> log.debug(“method <span style="color: #a6e22e;line-height: 26px;">exit</span> param:{}”,id);<br> <span style="color: #a6e22e;line-height: 26px;">return</span> id;<br>}<br></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">3. 选择合适的日志格式</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">理想的日志格式,应当包括这些最基本的信息:如当<strong>前时间戳</strong>(一般毫秒精确度)、<strong>日志级别</strong>,<strong>线程名字</strong>等等。在logback日志里可以这么配置:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><appender name=<span style="color: #a6e22e;line-height: 26px;">"STDOUT"</span> class=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.core.ConsoleAppender"</span>><br> <encoder><br> <pattern>%d{HH:mm:ss.SSS} %-5level [%thread][%logger{0}] %m%n</pattern><br> </encoder><br></appender> <br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果我们的日志格式,连当前时间都沒有记录,那<strong>连请求的时间点都不知道了</strong>?</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.9266666666666666" src="/upload/de7cba572cbd14216c2dd665f27ec2f0.png" data-type="png" data-w="300" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">4. 遇到if...else...等条件时,每个分支首行都尽量打印日志</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当你碰到<strong>if...else...或者switch</strong>这样的条件时,可以在分支的首行就打印日志,这样排查问题时,就可以通过日志,确定进入了哪个分支,代码逻辑更清晰,也更方便排查问题了。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.0533333333333332" src="/upload/ca4e71d7d04a50de9438eee815719161.png" data-type="png" data-w="300" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正例:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">if</span>(user.isVip()){<br> log.info(<span style="color: #a6e22e;line-height: 26px;">"该用户是会员,Id:{},开始处理会员逻辑"</span>,user,getUserId());<br> //会员逻辑<br>}<span style="color: #f92672;font-weight: bold;line-height: 26px;">else</span>{<br> log.info(<span style="color: #a6e22e;line-height: 26px;">"该用户是非会员,Id:{},开始处理非会员逻辑"</span>,user,getUserId())<br> //非会员逻辑<br>}<br></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">5.日志级别比较低时,进行日志开关判断</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对于trace/debug这些比较低的日志级别,必须进行日志级别的开关判断。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正例:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">User user = new User(666L, <span style="color: #a6e22e;line-height: 26px;">"公众号"</span>, <span style="color: #a6e22e;line-height: 26px;">"捡田螺的小男孩"</span>);<br><span style="color: #f92672;font-weight: bold;line-height: 26px;">if</span> (log.isDebugEnabled()) {<br> log.debug(<span style="color: #a6e22e;line-height: 26px;">"userId is: {}"</span>, user.getId());<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">因为当前有如下的日志代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">logger.debug(<span style="color: #a6e22e;line-height: 26px;">"Processing trade with id: "</span> + id + <span style="color: #a6e22e;line-height: 26px;">" and symbol: "</span> + symbol);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果<strong>配置的日志级别是warn</strong>的话,上述日志不会打印,但是会执行字符串拼接操作,如果<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">symbol</code>是对象, 还会执行<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">toString()</code>方法,浪费了系统资源,执行了上述操作,最终日志却没有打印,因此建议<strong>加日志开关判断。</strong></p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">6. 不能直接使用日志系统(Log4j、Logback)中的 API,而是使用日志框架SLF4J中的API。</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">SLF4J 是门面模式的日志框架,有利于维护和各个类的日志处理方式统一,并且可以在保证不修改代码的情况下,很方便的实现底层日志框架的更换。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.336" src="/upload/996e3208ffd357e0a63ebd56694f80a3.png" data-type="png" data-w="250" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正例:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">import org.slf4j.Logger; <br>import org.slf4j.LoggerFactory;<br><br>private static final Logger logger = LoggerFactory.getLogger(TianLuoBoy.class);<br></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">7. 建议使用参数占位{},而不是用+拼接。</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">反例:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">logger.info(<span style="color: #a6e22e;line-height: 26px;">"Processing trade with id: "</span> + id + <span style="color: #a6e22e;line-height: 26px;">" and symbol: "</span> + symbol);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">上面的例子中,使用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">+</code>操作符进行字符串的拼接,有一定的<strong>性能损耗</strong>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正例如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">logger.info(<span style="color: #a6e22e;line-height: 26px;">"Processing trade with id: {} and symbol : {} "</span>, id, symbol); <br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我们使用了大括号<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">{}</code>来作为日志中的占位符,比于使用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">+</code>操作符,更加优雅简洁。并且,<strong>相对于反例</strong>,使用占位符仅是替换动作,可以有效提升性能。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">8. 建议使用异步的方式来输出日志。</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 日志最终会输出到文件或者其它输出流中的,IO性能会有要求的。如果异步,就可以显著提升IO性能。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 除非有特殊要求,要不然建议使用异步的方式来输出日志。以logback为例吧,要配置异步很简单,使用AsyncAppender就行 </section></li> </ul> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><appender name=<span style="color: #a6e22e;line-height: 26px;">"FILE_ASYNC"</span> class=<span style="color: #a6e22e;line-height: 26px;">"ch.qos.logback.classic.AsyncAppender"</span>><br> <appender-ref ref=<span style="color: #a6e22e;line-height: 26px;">"ASYNC"</span>/><br></appender><br></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">9. 不要使用e.printStackTrace()</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.98" src="/upload/2bc93aeaf4a6e5b47493f9ba3658a9e.png" data-type="png" data-w="300" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">反例:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">try{<br> // 业务代码处理<br>}catch(Exception e){<br> e.printStackTrace();<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正例:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">try{<br> // 业务代码处理<br>}catch(Exception e){<br> log.error(<span style="color: #a6e22e;line-height: 26px;">"你的程序有异常啦"</span>,e);<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>理由:</strong></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> e.printStackTrace()打印出的堆栈日志跟业务代码日志是交错混合在一起的,通常排查异常日志不太方便。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> e.printStackTrace()语句产生的字符串记录的是堆栈信息,如果信息太长太多,字符串常量池所在的内存块没有空间了,即内存满了,那么,用户的请求就卡住啦~ </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">10. 异常日志不要只打一半,要输出全部错误信息</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.6966666666666667" src="/upload/7375ae529aeff24054fa035367774200.png" data-type="png" data-w="300" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">反例1:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">try {<br> //业务代码处理<br>} catch (Exception e) {<br> // 错误<br> LOG.error(<span style="color: #a6e22e;line-height: 26px;">'你的程序有异常啦'</span>);<br>} <br><br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 异常e都没有打印出来,所以压根不知道出了什么类型的异常。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">反例2:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">try {<br> //业务代码处理<br>} catch (Exception e) {<br> // 错误<br> LOG.error(<span style="color: #a6e22e;line-height: 26px;">'你的程序有异常啦'</span>, e.getMessage());<br>} <br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">e.getMessage()</code>不会记录详细的堆栈异常信息,只会记录错误基本描述信息,不利于排查问题。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正例:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">try {<br> //业务代码处理<br>} catch (Exception e) {<br> // 错误<br> LOG.error(<span style="color: #a6e22e;line-height: 26px;">'你的程序有异常啦'</span>, e);<br>} <br></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">11. 禁止在线上环境开启 debug</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">禁止在线上环境开启debug,这一点非常重要。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.975" src="/upload/d97e21aff3fb5beb20425a9a20d9c252.png" data-type="png" data-w="400" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">因为一般系统的debug日志会很多,并且各种框架中也大量使用 debug的日志,线上开启debug不久可能会打满磁盘,影响业务系统的正常运行。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">12.不要记录了异常,又抛出异常</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.9535714285714286" src="/upload/d0fdc61cc95b1044c0ce7e5254f5a64e.png" data-type="png" data-w="280" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">反例如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">log.error(<span style="color: #a6e22e;line-height: 26px;">"IO exception"</span>, e);<br>throw new MyException(e);<br></code></pre> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 这样实现的话,通常会把栈信息打印两次。这是因为捕获了MyException异常的地方,还会再打印一次。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 这样的日志记录,或者包装后再抛出去,不要同时使用!否则你的日志看起来会让人很迷惑。 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">13.避免重复打印日志</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">避免重复打印日志,酱紫会浪费磁盘空间。如果你已经有一行日志清楚表达了意思,<strong>避免再冗余打印</strong>,反例如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">if</span>(user.isVip()){<br> log.info(<span style="color: #a6e22e;line-height: 26px;">"该用户是会员,Id:{}"</span>,user,getUserId());<br> //冗余,可以跟前面的日志合并一起<br> log.info(<span style="color: #a6e22e;line-height: 26px;">"开始处理会员逻辑,id:{}"</span>,user,getUserId());<br> //会员逻辑<br>}<span style="color: #f92672;font-weight: bold;line-height: 26px;">else</span>{<br> //非会员逻辑<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果你是使用log4j日志框架,务必在<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">log4j.xml</code>中设置 additivity=false,因为可以避免重复打印日志</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">正例:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/eytJa9K5jkqg7LvVmfl8nGOribDjYSzia1UNxVicP6oLYKP6t7KiaeJhTzOPkDTg20TNWuTfiahrmicnXmw68sZl31k04jQEotS7sM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;"><logger name=<span style="color: #a6e22e;line-height: 26px;">"com.taobao.dubbo.config"</span> additivity=<span style="color: #a6e22e;line-height: 26px;">"false"</span>> <br></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">14.日志文件分离</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.1412213740458015" src="/upload/93ae7ab09bb0df10e59963b369776241.png" data-type="png" data-w="262" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 我们可以把不同类型的日志分离出去,比如access.log,或者error级别error.log,都可以单独打印到一个文件里面。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 当然,也可以根据不同的业务模块,打印到不同的日志文件里,这样我们排查问题和做数据统计的时候,都会比较方便啦。 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">15. 核心功能模块,建议打印较完整的日志</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.06" src="/upload/fbdda959ea8ff99ad83c628e87cf0f30.png" data-type="png" data-w="200" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 我们日常开发中,如果核心或者逻辑复杂的代码,建议添加详细的注释,以及较详细的日志。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 日志要多详细呢?脑洞一下,如果你的核心程序哪一步出错了,通过日志可以定位到,那就可以啦。 </section></li> </ul> </section>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;outline: 0px;max-width: 100%;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.6;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.05em;color: rgb(89, 89, 89);box-sizing: border-box !important;overflow-wrap: break-word !important;" data-mpa-powered-by="yiban.io"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;font-size: 18px;box-sizing: border-box !important;overflow-wrap: break-word !important;">一、注解(annotations)列表</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">1、@SpringBootApplication</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">包含了</span><code style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">@ComponentScan</span></code><span style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">、</span><code style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">@Configuration</span></code><span style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">和</span><code style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">@EnableAutoConfiguration</span></code><span style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">注解。<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">其中</span><code style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">@ComponentScan</span
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" data-mpa-powered-by="yiban.io"> <p style="white-space: normal;"><span style="color: rgb(171, 25, 66);"><strong><span style="font-size: 15px;text-align: left;"></span></strong></span></p> <p style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"></span><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;text-align: justify;">OpenFeign 是 SpringCloud 中的重要组件,它是一种声明式的 HTTP 客户端。</span><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;text-align: justify;">使用OpenFeign 调用远程服务就像调用本地方法一样,但是如果使用不当,很容易踩到坑。</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></p> <h2 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">坑一、用对 Http Client</span></strong></span></h2> <p><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;"><br></span></strong></span></p> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">1.1 feign 中 http client</span></strong></span></h3> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">如果不做特殊配置,OpenFeign 默认使用 JDK 自带的 HttpURLConnection。</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">我们知道,HttpURLConnection 没有连接池、性能和效率比较低,如果采用默认,很可能会遇到性能问题导致系统故障。</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">可以采用 Apache HttpClient,properties 文件中增加下面配置:</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><br></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer">feign.httpclient.enabled=<span class="code-snippet__literal">true</span></span></code></pre> </section> <pre data-tool="mdnice编辑器" style="text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></pre> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">pom 文件中增加依赖:</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">dependency</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">groupId</span>></span>io.github.openfeign<span class="code-snippet__tag"></<span class="code-snippet__name">groupId</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">artifactId</span>></span>feign-httpclient<span class="code-snippet__tag"></<span class="code-snippet__name">artifactId</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">version</span>></span>9.3.1<span class="code-snippet__tag"></<span class="code-snippet__name">version</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"></<span class="code-snippet__name">dependency</span>></span></span></code></pre> </section> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"></span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">也可以采用 OkHttpClient,properties 文件中增加下面配置:</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer">feign.okhttp.enabled=<span class="code-snippet__literal">true</span></span></code></pre> </section> <pre data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><br><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"></span></pre> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">pom文件中增加依赖:</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">dependency</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">groupId</span>></span>io.github.openfeign<span class="code-snippet__tag"></<span class="code-snippet__name">groupId</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">artifactId</span>></span>feign-okhttp<span class="code-snippet__tag"></<span class="code-snippet__name">artifactId</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">version</span>></span>10.2.0<span class="code-snippet__tag"></<span class="code-snippet__name">version</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"></<span class="code-snippet__name">dependency</span>></span></span></code></pre> </section> <pre data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><br><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"></span></pre> <h3 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">1.2 ribbon 中的 Http Client</span></strong></span></h3> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">通过 OpenFeign 作为注册中心的客户端时,默认使用 Ribbon 做负载均衡,Ribbon 默认也是用 JDK 自带的 HttpURLConnection。需要给 Ribbon 也设置一个 Http client,比如使用 okhttp,在 properties 文件中增加下面配置:</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><br></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="javascript"><code><span class="code-snippet_outer">ribbon.okhttp.enabled=<span class="code-snippet__literal">true</span></span></code></pre> </section> <pre data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"></span></pre> <h2 data-tool="mdnice编辑器"><br></h2> <h2 data-tool="mdnice编辑器"><span style="color: rgb(171, 25, 66);"><strong><span style="color: rgb(171, 25, 66);font-size: 15px;text-align: left;">坑二、全局超时时间</span></strong></span></h2> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><br></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">OpenFeign 可以设置超时时间,简单粗暴。</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">设置一个全局的超时时间,如下:</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer">feign.client.config.<span class="code-snippet__keyword">default</span>.connectTimeout=<span class="code-snippet__number">2000</span></span></code><code><span class="code-snippet_outer">feign.client.config.<span class="code-snippet__keyword">default</span>.readTimeout=<span class="code-snippet__number">60000</span></span></code></pre> </section> <pre data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"></span><br></pre> <p style="white-space: normal;text-align: left;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;color: rgb(136, 136, 136);font-size: 14px;">如果不配置超时时间,默认是连接超时 10s,读超时 60s。在源码 feign.Request 的内部类 Options 中定义。</span></p> <p style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">这个接口设置了最大的 readTimeout 是 60s。这个时间必须大于调用的所有外部接口的 readTimeout,否则处理时间大于 readTimeout 的接口就会调用失败。</span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;"><br></span></p> <p data-tool="mdnice编辑器" style="white-space: normal;text-align: left;"><span style="font-size: 15px;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: justify;">如下图,在一个系统中使用 OpenFeign 调用外部三个服务,每个服务提供两个接口。其中,serviceC 的一个接口需要 60s 才能返回,那上面的 readTimeout 必须设置成60s。</span></p> <p data-tool="mdnice编辑器" style="white-sp
作者:微信小助手
<p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;"><img src="/upload/9fe0432351a521890bdca11c730bd577.jpg" data-cropx1="0" data-cropx2="1200" data-cropy1="35.294117647058826" data-cropy2="629.0657439446368" data-ratio="0.49583333333333335" src="https://mmbiz.qpic.cn/mmbiz_jpg/l89kosVutokYzUsGbdibhA79hCYicyqUO63JbBbI0icuLICdJY37Tb6XUibM5hPfFBw5XYIVic72aiahfcPafFia6En7g/640?wx_fmt=jpeg" data-type="jpeg" data-w="1200" style="width: 525px;height: 261px;"></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;text-align: center;"><br></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">今天的内容给大家介绍下如何利用阿里云提供的免费私人容器镜像服务,来实现对个人项目容器镜像的管理,以及通过k8s集群来发布阿里云私人容器镜像服务中管理的服务。本文适合个人及创业团队学习/使用基于容器、镜像仓库、k8s等云原生技术时的参考。</span><span style="color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;caret-color: rgb(60, 60, 60);"></span></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;min-height: 1em;white-space: normal;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;color: rgb(60, 60, 60);font-size: 16px;font-weight: bold;letter-spacing: 1px;text-align: center;line-height: 1.8;background-color: rgb(255, 255, 255);z-index: 10000;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;color: rgb(0, 0, 0);font-size: medium;text-align: start;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 12pt;font-family: 宋体;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(0, 0, 0);text-align: start;font-size: 12pt;font-family: 宋体;">创建阿里云个人版容器镜像实例</span><span style="color: rgb(0, 0, 0);font-size: medium;text-align: start;"></span></span></strong><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.053125" src="/upload/16c3bc26d4547f0344ee22af769e1434.png" data-type="png" data-w="640" style="outline: 0px;color: rgb(60, 60, 60);font-weight: bold;letter-spacing: 1px;text-align: center;font-size: 15px;display: inline-block;left: 0px;transform: rotateX(60deg);margin-top: 5px !important;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 632px !important;"></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">一般来说大型企业都会自己搭建内部私有镜像仓库(例如Harbor),但对于小公司来说也可以直接使用云服务提供的容器镜像服务。接下来以阿里云免费提供的个人版容器镜像服务,演示容器镜像服务的具体使用。</span><span style="color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;caret-color: rgb(60, 60, 60);">步骤如下:</span></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">(1)、登录阿里云,点击->控制台->找到“容器镜像服务”,如下图所示:</span></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5760661998726926" data-s="300,640" src="/upload/2ddb6dba4dd7fc2ca509272339078960.png" data-type="png" data-w="1571" style="width: 576px;height: 332px;"></p> <p style="text-align: center;"><br></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">如果入口比较难找,可以直接在阿里云搜索框搜索“容器镜像服务”。</span><span style="color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;caret-color: rgb(60, 60, 60);">阿里云提供收费的企业版实例,也提供限制使用的个人版实例。</span><span style="color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;caret-color: rgb(60, 60, 60);">这里选择个人版实例。</span></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span><br></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">(2)、创建成功后,设置镜像仓库登陆密码。如下图所示:</span><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(0, 0, 0);font-size: medium;text-align: start;"></span></span></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5795665634674922" data-s="300,640" src="/upload/d07afbbfa28ff7b060fb3b08e60e4b40.png" data-type="png" data-w="1615" style=""></p> <p style="text-align: center;"><br></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">提示:<br>设置一个自己能记住的密码,例如我这里设置的是“wudimanong”。<span style="font-family: 楷体_GB2312;background-color: rgb(242, 242, 242);color: rgb(0, 0, 0);font-size: 10pt;text-indent: 20pt;"></span></p> </blockquote> </section> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">(3)密码设置成功后,点击“创建镜像仓库”,最终效果如下图所示:</span></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5734308348567947" data-s="300,640" src="/upload/44427abfb6d2250d1896c6352805ded9.png" data-type="png" data-w="1641" style=""></p> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5806845965770171" data-s="300,640" src="/upload/a472a1553650881a088447777083445.png" data-type="png" data-w="1636" style=""></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">选择本地仓库,后面通过本地构建直接将Docker镜像推送至阿里云私有镜像仓库。</span></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.5787523162445954" data-s="300,640" src="/upload/e97871bc0ff42fab6b59440fd9487f1f.png" data-type="png" data-w="1619" style=""></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">之后就可以根据提示登录该阿里云镜像仓库,并向其中Push镜像了。</span></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p style="padding-right: 10px;padding-left: 9px;outline: 0px;max-width: 100%;min-height: 1em;white-space: normal;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;color: rgb(60, 60, 60);font-size: 16px;font-weight: bold;letter-spacing: 1px;text-align: center;line-height: 1.8;background-color: rgb(255, 255, 255);z-index: 10000;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;color: rgb(0, 0, 0);font-size: medium;text-align: start;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;font-size: 12pt;font-family: 宋体;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="font-size: 12pt;"><span style="color: rgb(0, 0, 0);text-align: start;font-size: 12pt;font-family: 宋体;">配置</span><span lang="EN-US" style="color: rgb(0, 0, 0);text-align: start;font-size: 12pt;font-family: "Times New Roman";">k8s</span><span style="color: rgb(0, 0, 0);text-align: start;font-size: 12pt;font-family: 宋体;">集群与镜像仓库的连接</span><span style="color: rgb(0, 0, 0);font-size: medium;text-align: start;"></span></span><span style="font-size: medium;"></span></span></strong><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.053125" src="/upload/16c3bc26d4547f0344ee22af769e1434.png" data-type="png" data-w="640" style="outline: 0px;color: rgb(60, 60, 60);font-weight: bold;letter-spacing: 1px;text-align: center;font-size: 15px;display: inline-block;left: 0px;transform: rotateX(60deg);margin-top: 5px !important;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 632px !important;"></p> <p style="outline: 0px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="letter-spacing: 0.544px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">创建私有镜像仓库之后,为了安全设置了用户名及密码,如果k8s集群需要从镜像仓库拉取镜像,则每次都需要登陆是很麻烦的,所以可以进行相关设置。</span></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></span></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: rgb(60, 60, 60);color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;">Kubernetes 集群使用 docker-registry 类型的 Secret 来通过容器仓库的身份验证,进而提取私有映像。</span></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;caret-color: rgb(60, 60, 60);">创建Secret,命名为 regcred:</span></p> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;caret-color: rgb(60, 60, 60);"><br></span></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"># kubectl <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">create</span> secret docker-registry regcred <span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;">--docker-server=registry.cn-hangzhou.aliyuncs.com --docker-username=jqadmin --docker-password=wudimanong</span><br>secret/regcred created<br></code></pre> </section> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(60, 60, 60);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 1px;caret-color: rgb(60, 60, 60);"></span><br></p> <section style="font-size: 16px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;"> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">提示:<br>上述账号密码为你自己创建镜像仓库时设置的。</p> </blockquote> </section> <p style="white-space: normal;outline: 0px;max-width: 100%;min-height: 1em;font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino San
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><span style="letter-spacing: 0px;">今天这篇文章给大家带来MySQL中重要的两个日志 - </span><code style="letter-spacing: 0px;font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">redo log</code><span style="letter-spacing: 0px;">、</span><code style="letter-spacing: 0px;font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">binlog</code><span style="letter-spacing: 0px;">,从理论概念出发,结合图解分析,看完这篇文章之后,你能对</span><code style="letter-spacing: 0px;font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">redo log</code><span style="letter-spacing: 0px;">、</span><code style="letter-spacing: 0px;font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">binlog</code><span style="letter-spacing: 0px;">有深入的理解。</span><span style="letter-spacing: 0px;"></span></p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">文章导读</span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7923784494086727" src="/upload/777d1e105893bf76335c87597a1372ed.png" data-type="png" data-w="761" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> MySQL两个日志 </figcaption> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">浅谈MySQL分层架构</span></h2> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">在讲具体的日志之前,先稍微铺垫下MySQL分层的架构,让大家知道<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">redo log</code>、<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">binlog</code>是由MySQL的哪一层产生的。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1" src="/upload/7322bae7c72fb16f4a048dfd36ebbac7.png" data-type="png" data-w="621" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> MySQL分层架构图 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">MySQL整体分为3层:客户端层,Server层和存储引擎层。我们的binlog日志,由Server层生成,redo log是InnoDB特有的日志,由InnoDB引擎生成。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">重做日志(redo log)</span></h2> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">什么是redo log</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">InnoDB为了能够支持事务一系列操作,而事务有4种特性:<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">原子性</code>、<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">一致性</code>、<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">隔离性</code>、<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">持久性</code>,在事务操作中,要么全部执行,要么全部不执行,这就是事务的目的。而我们的redo log用来保证事务的持久性,即我们常说的ACID中的D。我们只需要知道它是通过一套什么样的机制,来保证持久性,就能掌握好<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">redo log</code>。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">这里的说的持久性,是说最后落盘到redo log文件(即常见的<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">ib_logfile</code>文件),因为最后我们异常情况的恢复,都是根据文件来做恢复的。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">那么我们的MySQL InnoDB是通过一套什么样的机制来确保<strong style="color: black;">速度</strong>与<strong style="color: black;">可靠性</strong>的呢?</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">WAL</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">在计算机体系中,CPU处理速度和硬盘的速度,是不在同一个数量级上的,为了让它们速度匹配,从而催生了我们的内存模块,但是内存有一个特点,就是掉电之后,数据就会丢失,不是持久的,我们需要持久化的数据,最后都需要存储到硬盘上。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">InnoDB引擎设计者也利用了类似的设计思想,先写内存,再写硬盘,这样就不会因为redo log写硬盘IO而导致数据库性能问题。在InnoDB中,这种技术有一个专业名称,叫做<strong style="color: black;">Write-Ahead Log(预先日志持久化)</strong></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.12524461839530332" src="/upload/2ddc7a3f93b28da962d0a9b2454c0be.png" data-type="png" data-w="511" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 先写buffer 再写磁盘 </figcaption> </figure> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">redo log写入策略</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">上边是保证了处理的速度,但是怎么样保证写入到硬盘的可靠性呢?</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">InnoDB引擎的设计者也设计了一种写入的策略,首先有一个后台线程,每隔1秒,就会把<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">redo log buffer</code>中的日志,调用write写到文件系统的<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">page cache</code>,然后调用<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">fsync</code>持久化到磁盘(即redo log文件 <code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">ib_logfile0 ib_logfile1</code>)。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">为了控制 redo log写入策略,InnoDB提供了<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">innodb_flush_log_at_trx_commit</code>配置参数,它有三种取值:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 设置为 0 的时候,表示每次事务提交时都只是把 redo log 留在 redo log buffer 中 ; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 设置为 1 的时候,表示每次事务提交时都将 redo log 直接持久化到磁盘; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 设置为 2 的时候,表示每次事务提交时都只是把 redo log 写到 page cache。 </section></li> </ol> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><strong style="color: black;">如果不是对性能要求高的,一般把该参数设置为 1</strong></p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">redo log的擦除</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">通过上边的设计,<strong style="color: black;">速度</strong>和<strong style="color: black;">可靠性</strong>的问题都解决了,但是我们仔细想想,还会有什么问题?</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">随着文件的增加,落盘的速度会越来越慢,直到有一天 ...</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">聪明的设计者这样子想着,如果我一直处理小文件,最大不能超过某个大小,不就行了?</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">也确实是这样子处理的,但是这里就涉及到一个删除日志文件的算法,即我们的<strong style="color: black;">redo log擦除</strong>。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">redo log 的大小是固定的,比如可以配置一组4个文件,每个文件大小是8M,那么这个redo log总共就可以记录32M的操作,这个参数可以通过<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">innodb_log_file_size</code>设置。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">下图是具体的擦除算法,ib_logfile 从头开始写,写到末尾就又回到开头循环写。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7495621716287215" src="/upload/340484979adda7eeb69acae34e608ad3.png" data-type="png" data-w="1142" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 擦除示意图 - 来自丁奇MySQL连边编辑 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">write pos是当前记录的位置,一边写一边后移,写到第3号文件末尾后就回到0号文件开头。checkpoint是当前要擦除的位置,也是往后移动并且循环的,擦除记录前要把记录更新到数据文件,write pos与check point之间为剩余可用写入的空间。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">何时会擦除redo log并更新到数据文件中</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 系统空闲时 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> Redo log文件没有空闲空间时,即write pos追上check point的时候; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> MySQL Server正常关闭时 </section></li> </ol> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">crash-safe</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">有了以上这一些机制保障,我们可以相信redo log是可靠的,只要持久化到redo log文件中了,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,而我们把这个能力称为 <code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">crash-safe</code>。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">归档日志(binlog)</span></h2> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">在写这篇文章的时候,纠结到底先写redo log还是binlog,最后还是秉承<strong style="color: black;">先苦后甜</strong>的原则,把redo log写在前面了。如果redo log的部分看懂了,binlog掌握是轻松的,跟着我的思路,我们继续binlog~</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">前边讲过,redo log是InnoDB引擎特有的日志,是引擎层面的日志,而在我们的数据库的Server层面,也有自己的日志,称为binlog(归档日志)。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">binlog是逻辑日志,怎么样来理解这个<strong style="color: black;">逻辑日志</strong>呢?</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">我们通过查看一段binlog来理解。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">理解逻辑日志</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><strong style="color: black;">这里一大段的操作,都是为了查看binlog文件里边存储的是什么内容,熟悉的读者可以直接略过。</strong></p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">执行命令,写入新binlog文件,不让之前的逻辑影响。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">执行一次flush logs命令行,就会在data目录下新增一个mysql-bin.00000x文件</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/ciaIftfPzwlpXk9kSHaAdnBxDpvPzhgbYDfib4JXLwx0DLEkI8nIib66u2RQZXo64IZSv9R9WibSPm5UIdmM8oSqIUYxru1pF3j6/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #61aeee;line-height: 26px;">#</span><span style="line-height: 26px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"># 登陆MySQL命令行</span></span><br>mysql -uroot -p<br><span style="color: #61aeee;line-height: 26px;">#</span><span style="line-height: 26px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"># 刷新binlog</span></span><br>flush logs;<br><span style="color: #61aeee;line-height: 26px;">#</span><span style="line-height: 26px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"># 确认刷新binlog成功</span></span><br>show master status;<br><span style="color: #61aeee;line-height: 26px;">#</span><span style="line-height: 26px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"># 查询binlog日志位置</span></span><br> show variables like'log_bin%';<br></code></pre> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.33955223880597013" src="/upload/864d2905cb8429304ab2f0887714dc3f.png" data-type="png" data-w="268" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> data目录下的mysql-bin文件 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">测试数据</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/ciaIftfPzwlpXk9kSHaAdnBxDpvPzhgbYDfib4JXLwx0DLEkI8nIib66u2RQZXo64IZSv9R9WibSPm5UIdmM8oSqIUYxru1pF3j6/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">## 创建表</span><br><span style="color: #c678dd;line-height: 26px;">CREATE</span> <span style="color: #c678dd;line-height: 26px;">TABLE</span> <span style="color: #98c379;line-height: 26px;">`User`</span> (<br> <span style="color: #98c379;line-height: 26px;">`id`</span> <span style="color: #e6c07b;line-height: 26px;">int</span>(<span style="color: #d19a66;line-height: 26px;">11</span>) <span style="color: #c678dd;line-height: 26px;">NOT</span> <span style="color: #56b6c2;line-height: 26px;">NULL</span> AUTO_INCREMENT,<br> <span style="color: #98c379;line-height: 26px;">`name`</span> <span style="color: #e6c07b;line-height: 26px;">varchar</span>(<span style="color: #d19a66;line-height: 26px;">10</span>) <span style="color: #e6c07b;line-height: 26px;">CHARACTER</span> <span style="color: #c678dd;line-height: 26px;">SET</span> gb2312 <span style="color: #c678dd;line-height: 26px;">COLLATE</span> gb2312_chinese_ci <span style="color: #c678dd;line-height: 26px;">NOT</span> <span style="color: #56b6c2;line-height: 26px;">NULL</span>,<br> <span style="color: #98c379;line-height: 26px;">`age`</span> <span style="color: #e6c07b;line-height: 26px;">int</span>(<span style="color: #d19a66;line-height: 26px;">11</span>) <span style="color: #c678dd;line-height: 26px;">UNSIGNED</span> <span style="color: #c678dd;line-height: 26px;">NOT</span> <span style="color: #56b6c2;line-height: 26px;">NULL</span>,<br> PRIMARY <span style="color: #c678dd;line-height: 26px;">KEY</span> (<span style="color: #98c379;line-height: 26px;">`id`</span>) <span style="color: #c678dd;line-height: 26px;">USING</span> BTREE<br>) <span style="color: #c678dd;line-height: 26px;">ENGINE</span> = <span style="color: #c678dd;line-height: 26px;">InnoDB</span> AUTO_INCREMENT = <span style="color: #d19a66;line-height: 26px;">1</span> <span style="color: #e6c07b;line-height: 26px;">CHARACTER</span> <span style="color: #c678dd;line-height: 26px;">SET</span> = utf8mb4 <span style="color: #c678dd;line-height: 26px;">COLLATE</span> = utf8mb4_bin ROW_FORMAT = <span style="color: #c678dd;line-height: 26px;">Compact</span>;<br><br><span style="color: #5c6370;font-style: italic;line-height: 26px;">## 新增</span><br><span style="color: #c678dd;line-height: 26px;">INSERT</span> <span style="color: #98c379;line-height: 26px;">`User`</span> <span style="color: #c678dd;line-height: 26px;">VALUES</span>(<span style="color: #98c379;line-height: 26px;">"1"</span>, <span style="color: #98c379;line-height: 26px;">"张三"</span>, <span style="color: #d19a66;line-height: 26px;">18</span>);<br><span style="color: #c678dd;line-height: 26px;">INSERT</span> <span style="color: #98c379;line-height: 26px;">`User`</span> <span style="color: #c678dd;line-height: 26px;">VALUES</span>(<span style="color: #98c379;line-height: 26px;">"2"</span>, <span style="color: #98c379;line-height: 26px;">"李四"</span>, <span style="color: #d19a66;line-height: 26px;">20</span>);<br><span style="color: #5c6370;font-style: italic;line-height: 26px;">## 修改</span><br><span style="color: #c678dd;line-height: 26px;">DELETE</span> <span style="color: #c678dd;line-height: 26px;">FROM</span> <span style="color: #98c379;line-height: 26px;">`User`</span> <span style="color: #c678dd;line-height: 26px;">WHERE</span> <span style="color: #c678dd;line-height: 26px;">id</span> = <span style="color: #d19a66;line-height: 26px;">1</span>;<br></code></pre> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4563106796116505" src="/upload/d7f28dd33340a336f6fd54f5681b2146.png" data-type="png" data-w="824" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 执行语句截图 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">翻译binlog二进制文件</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/ciaIftfPzwlpXk9kSHaAdnBxDpvPzhgbYDfib4JXLwx0DLEkI8nIib66u2RQZXo64IZSv9R9WibSPm5UIdmM8oSqIUYxru1pF3j6/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">sudo /usr/local/mysql/bin/mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000006 > mysqlbin.sql<br></code></pre> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7921077959576516" src="/upload/711c49b92722fe5a10bd1d3cbe7bf524.png" data-type="png" data-w="1039" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> binlog翻译 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">这是翻译出来的sql文件,是因为我在<code style="font-size: 14px;word-wrap: break-word;border-radius: 4px;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #9b6e23;background-color: #fff5e3;padding: 3px;margin: 3px;">mysqlbinlog -v</code>参数加工而成的。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><strong style="color: black;">由此可知,逻辑日志里边就是记录着sql语句,通过sql语句记录着逻辑的变化,比如insert, update等动作,但不是记录具体数据,那个由物理日志完成。</strong></p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">与redo log的区别</span><span style="display: none;"></span></h3> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> redo log是innoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都能使用; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> redo log是循环写的,空间固定会用完;binlog是追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。 </section></li> </ol> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">binlog写入策略</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">通过与redo log的区别,我们知道,binlog是追加写入的,所以与redo log写入相比,没有擦除的概念。那么,还有一些什么样的其他的区别呢?</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">binlog的写入逻辑比较简单:事务执行过程中,先把日志写到binlog cahce,事务提交的时候,再把binlog cache写到binlog文件中(落盘)。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4836488812392427" src="/upload/157b5dd541fafb7f81614b72825a7470.png" data-type="png" data-w="581" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> binlog写入 </figcaption> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">从上图可以看到,每个线程都有自己的binlog cache,但是共用同一份binlog文件。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">图中的write,指的就是把日志写入到数据库系统的page cache,并没有把数据持久化到磁盘,所有速度很快;</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">图中的fsync,才是将数据持久化到磁盘的操作。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">write 和 fsync 的时机,是由参数 sync_binlog 控制的:</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">sync_binlog=0 的时候,表示每次提交事务都只 write,不 fsync;</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">sync_binlog=1 的时候,表示每次提交事务都会执行 fsync;</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">sync_binlog=N(N>1) 的时候,表示每次提交事务都 write,但累积 N 个事务后才 fsync。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(255, 177, 27);background: rgb(255, 245, 227);"> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">因此,在出现 IO 瓶颈的场景里,将 sync_binlog 设置成一个比较大的值,可以提升性能。在实际的业务场景中,考虑到丢失日志量的可控性,一般不建议将这个参数设成 0,比较常见的是将其设置为 100~1000 中的某个数值。</p> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">但是,将 sync_binlog 设置为 N,对应的风险是:如果主机发生异常重启,会丢失最近 N 个事务的 binlog 日志。</p> <p style="font-size: 16px;line-height: 26px;color: rgb(89, 89, 89);">引用《极客时间MySQL45讲》</p> </blockquote> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: none;"></span><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">浅谈两阶段提交</span></h2> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">这里讲的两阶段提交,就是纯粹的指redo log和binlog日志的两阶段提交。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">而两阶段提交的目的就是让redo log和binlog两个日志逻辑上一致。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">如果redo log持久化并进行了提交,而binlog未持久化数据库就crash了,则从库从binlog拉取数据会少于主库,造成不一致。因此需要内部事务来保证两种日志的一致性。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">两阶段提交步骤</span><span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.0887728459530026" src="/upload/35c8f54b87d9403b5f2756880f0667d5.png" data-type="png" data-w="383" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> <figcaption style="margin-top: 5px;text-align: center;color: #dda52d;font-size: 14px;"> 两阶段提交 </figcaption> </figure> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 将语句执行 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 记录redo log,并将记录状态设置为prepare </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 通知Server,已经修改好了,可以提交事务了 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 将更新的内容写入binlog </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> commit,提交事务 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 将redo log里这个事务相关的记录状态设置为commited </section></li> </ol> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><strong style="color: black;">prepare:</strong> redolog写入log buffer,并fsync持久化到磁盘,在redolog事务中记录2PC的XID,在redolog事务打上prepare标识</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><strong style="color: black;">commit:</strong> binlog写入log buffer,并fsync持久化到磁盘,在binlog事务中记录2PC的XID,同时在redolog事务打上commit标识 其中,prepare和commit阶段所提到的“事务”,都是指内部XA事务,即2PC</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;line-height: 1.4;padding-top: 10px;margin-top: 10px;margin-bottom: 5px;"><span style="display: none;"></span><span style="color: rgb(81, 81, 81);font-size: 1em;padding-left: 20px;border-left: 3px solid rgb(249, 191, 69);">恢复步骤</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">redolog中的事务如果经历了二阶段提交中的prepare阶段,则会打上prepare标识,如果经历commit阶段,则会打上commit标识(此时redolog和binlog均已落盘)。</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 按顺序扫描redolog,如果redolog中的事务既有prepare标识,又有commit标识,就直接提交(复制redolog disk中的数据页到磁盘数据页) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 如果redolog事务只有prepare标识,没有commit标识,则说明当前事务在commit阶段crash了,binlog中当前事务是否完整未可知,此时拿着redolog中当前事务的XID(redolog和binlog中事务落盘的标识),去查看binlog中是否存在此XID </section></li> <ol style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: lower-alpha;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 如果binlog中有当前事务的XID,则提交事务(复制redolog disk中的数据页到磁盘数据页) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 如果binlog中没有当前事务的XID,则回滚事务(使用undolog来删除redolog中的对应事务) </section></li> </ol> </ol> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">可以将mysql redolog和binlog二阶段提交和广义上的二阶段提交进行对比,广义上的二阶段提交,若某个参与者超时未收到协调者的ack通知,则会进行回滚,回滚逻辑需要开发者在各个参与者中进行记录。mysql二阶段提交是通过xid进行恢复。</p> </section>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">今天和大家聊一个常见的问题:慢SQL。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">通过本文你将了解到以下内容:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 慢SQL的危害 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> SQL语句的执行过程 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 存储引擎和索引的那些事儿 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 慢SQL解决之道 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">后续均以MySQL默认存储引擎InnoDB为例进行展开,话不多说,开搞!</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin-top: 24px;margin-bottom: 12px;"><span style="display: none;"></span><span style="color: #e7642b;text-align: center;display: block;background-color: #e7642b;color: white;padding: 3px 11px;border-radius: 1px;">1.慢SQL的危害</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">慢SQL,就是跑得很慢的SQL语句,你可能会问慢SQL会有啥问题吗?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">试想一个场景:</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">大白和小黑端午出去玩,机票太贵于是买了高铁,火车站的人真是乌央乌央的。</p> </blockquote> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">马上检票了,大白和小黑准备去厕所清理下库存,坑位不多,排队的人还真不少。</p> </blockquote> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">小黑发现其中有3个坑的乘客贼慢,其他2个坑位换了好几波人,这3位坑主就是不出来。</p> </blockquote> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">等在外面的大伙,心里很是不爽,长期占用公共资源,后面的人没法用。</p> </blockquote> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">小黑苦笑道:这不就是厕所版的慢SQL嘛!</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">这是实际生活中的例子,换到MySQL服务器也是一样的,毕竟科技源自生活嘛。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">MySQL服务器的资源(CPU、IO、内存等)是有限的,尤其在高并发场景下需要快速处理掉请求,否则一旦出现慢SQL就会阻塞掉很多正常的请求,造成大面积的失败/超时等。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7542262678803641" src="/upload/51a56c98aac845ab0ffadfe9df6d620.png" data-type="png" data-w="1538" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin-top: 24px;margin-bottom: 12px;"><span style="display: none;"></span><span style="color: #e7642b;text-align: center;display: block;background-color: #e7642b;color: white;padding: 3px 11px;border-radius: 1px;">2.SQL语句执行过程</span></h2> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.3701188455008489" src="/upload/f23682ebb466a7de41b751d901e13fd1.png" data-type="png" data-w="1178" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">客户端和MySQL服务端的交互过程简介:</p> <ol data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 客户端发送一条SQL语句给服务端,服务端的连接器先进行账号/密码、权限等环节验证,有异常直接拒绝请求。 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 服务端查询缓存,如果SQL语句命中了缓存,则返回缓存中的结果,否则继续处理。 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 服务端对SQL语句进行词法解析、语法解析、预处理来检查SQL语句的合法性。 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 服务端通过优化器对之前生成的解析树进行优化处理,生成最优的物理执行计划。 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 将生成的物理执行计划调用存储引擎的相关接口,进行数据查询和处理。 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 处理完成后将结果返回客户端。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">客户端和MySQL服务端的交互过程简图:<img data-ratio="1.138095238095238" src="/upload/4219190c9925ae7cc86dee88bb907135.png" data-type="png" data-w="1260" style="display: block;border-radius: 5px;margin: 12px auto;"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">俗话说"条条大路通罗马",优化器的作用就是找到这么多路中最优的那一条。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">存储引擎更是决定SQL执行的核心组件,适当了解其中原理十分有益。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin-top: 24px;margin-bottom: 12px;"><span style="display: none;"></span><span style="color: #e7642b;text-align: center;display: block;background-color: #e7642b;color: white;padding: 3px 11px;border-radius: 1px;">3. 存储引擎和索引的那些事儿</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;font-size: 18px;color: rgb(66, 75, 93);"><span style="display: none;"></span>3.1 存储引擎<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">InnoDB存储引擎(Storage Engine)是MySQL默认之选,所以非常典型。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">存储引擎的主要作用是进行数据的存取和检索,也是真正执行SQL语句的组件。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">InnoDB的整体架构分为两个部分:内存架构和磁盘架构,如图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.76875" src="/upload/a085e57fa3075fc06c8bad9f598dd76b.png" data-type="png" data-w="640" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">存储引擎的内容非常多,并不是一篇文章能说清楚的,本文不过多展开,我们在此只需要了解内存架构和磁盘架构的大致组成即可。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">InnoDB 引擎是面向行存储的,数据都是存储在磁盘的数据页中,数据页里面按照固定的行格式存储着每一行数据。</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">行格式主要分为四种类型Compact、Redundant、Dynamic和Compressed,默认为Compact格式。</p> </blockquote> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.3352941176470588" src="/upload/fa52b3f422946a6eb66c26f662794cb2.png" data-type="png" data-w="1360" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;color: rgb(66, 75, 93);"><span style="display: none;"></span>磁盘预读机制和局部性原理<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">当计算机访问一个数据时,不仅会加载当前数据所在的数据页,还会将当前数据页相邻的数据页一同加载到内存,磁盘预读的长度一般为页的整倍数,<span style="color: rgb(66, 75, 93);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 1px;text-align: left;word-spacing: 3px;">从而有效降低磁盘IO的次数。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5628834355828221" src="/upload/266e18325f1c65113433c80b2c3c525f.png" data-type="png" data-w="1304" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;color: rgb(66, 75, 93);"><span style="display: none;"></span>磁盘和内存的交互<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">MySQL中磁盘的数据需要被交换到内存,才能完成一次SQL交互,大致如图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5955414012738853" src="/upload/507b42aa513149bb6771909f221b787a.png" data-type="png" data-w="1256" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 扇区是硬盘的读写的基本单位,通常情况下每个扇区的大小是 512B </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 磁盘块文件系统读写数据的最小单位,相邻的扇区组合在一起形成一个块,一般是4KB </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 页是内存的最小存储单位,页的大小通常为磁盘块大小的 2^n 倍 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> InnoDB页面的默认大小是16KB,是数倍个操作系统的页 </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5098039215686274" src="/upload/32fc5fc95e7c7a73fe9874a80be182ad.png" data-type="png" data-w="918" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;color: rgb(66, 75, 93);"><span style="display: none;"></span>随机磁盘IO<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">MySQL的数据是一行行存储在磁盘上的,并且这些数据并非物理连续地存储,这样的话要查找数据就无法避免随机在磁盘上读取和写入数据。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">对于MySQL来说,当出现大量磁盘随机IO时,大部分时间都被浪费到寻道上,磁盘呼噜呼噜转,就是传输不了多少数据。</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">一次磁盘访问由三个动作组成:</p> <ul style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 寻道:磁头移动定位到指定磁道 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 旋转:等待指定扇区从磁头下旋转经过 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 数据传输:数据在磁盘与内存之间的实际传输 </section></li> </ul> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">对于存储引擎来说,如何有效降低随机IO是个非常重要的问题。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;font-size: 18px;color: rgb(66, 75, 93);"><span style="display: none;"></span>3.2 索引<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">可以实现增删改查的数据结构非常多,包括:哈希表、二叉搜索树、AVL、红黑树、B树、B+树等,这些都是可以作为索引的候选数据结构。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">结合MySQL的实际情况:磁盘和内存交互、随机磁盘IO、排序和范围查找、增删改的复杂度等等,综合考量之下B+树脱颖而出。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">B+树作为多叉平衡树,对于范围查找和排序都可以很好地支持,并且更加矮胖,访问数据时的平均磁盘IO次数取决于树的高度,因此B+树可以让磁盘的查找次数更少。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">在InnoDB中B+树的高度一般都在2~4层,并且根节点常驻内存中,也就是说查找某值的行记录时最多只需要1~3次磁盘I/O操作。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">MyISAM是将数据和索引分开存储的,InnoDB存储引擎的数据和索引没有分开存储,这也就是为什么有人说Innodb索引即数据,数据即索引,如图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4496951219512195" src="/upload/6df3466f0552df162a8a43ba5ff18ae3.png" data-type="png" data-w="1312" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">说到InnoDB的数据和索引的存储,就提到一个名词:<strong>聚集索引</strong>。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;color: rgb(66, 75, 93);"><span style="display: none;"></span>聚集索引<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">聚集索引将索引和数据完美地融合在一起,是每个Innodb表都会有的一个特殊索引,一般来说是借助于表的主键来构建的B+树。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">假设我们有student表,将id作为主键索引,那么聚集索引的B+树结构,如图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5038051750380518" src="/upload/35b601ac98901dfa28dd3f146319ec08.png" data-type="png" data-w="1314" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 非叶子节点不存数据,只有主键和相关指针 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 叶子节点包含主键、行数据、指针 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 叶子节点之间由双向指针串联形成有序双向链表,叶子节点内部也是有序的 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">聚集索引按照如下规则创建:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 有主键时InnoDB利用主键来生成 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 没有主键,InnoDB会选择一个非空的唯一索引来创建 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 无主键且非NULL唯一索引时,InnoDB会隐式创建一个自增的列来创建 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">假如我们要查找id=10的数据,大致过程如下:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 索引的根结点在内存中,10>9 因此找到P3指针 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> P3指向的数据并没有在内存中,因此产生1次磁盘IO读取磁盘块3到内存 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 在内存中对磁盘块3进行二分查找,找到ID=9的全部值 </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;color: rgb(66, 75, 93);"><span style="display: none;"></span>非聚集索引<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">非聚集索引的叶子节点中存放的是二级索引值和主键键值,非叶子节点和叶子节点都没有存储整行数据值。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">假设我们有student表,将name作为二级索引,那么非聚集索引的B+树结构,如图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4888558692421991" src="/upload/3467948dae90531a4290f47471c36540.png" data-type="png" data-w="1346" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">由于非聚集索引的叶子节点没有存储行数据,如果通过非聚集索引来查找非二级索引值,需要分为两步:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 第一:通过非聚集索引的叶子节点来确定数据行对应的主键 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 第二:通过相应的主键值在聚集索引中查询到对应的行记录 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">我们把通过非聚集索引找到主键值,再根据主键值从聚集索引找对于行数据的过程称为:<strong>回表查询</strong>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">换句话说:select * from student where name = 'Bob' 将产生回表查询,因为在name索引的叶子节点没有其他值,只能从聚集索引获得。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">所以如果查找的字段在非聚集索引就可以完成,就可以避免一次回表过程,这种称为:覆盖索引,所以select * 并不是好习惯,需要什么拿什么就好。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">假如我们要查找name=Tom的记录的所有值,大致过程如下:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 从非聚集索引开始,根节点在内存中,按照name的字典序找到P3指针 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> P3指针所指向的磁盘块不在内存中,产生1次磁盘IO加载到内存 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 在内存中对磁盘块3的数据进行搜索,获得name=tom的记录的主键值为4 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 根据主键值4从聚集索引的根节点中获得P2指针 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> P2指针所指向的磁盘块不在内存中,产生第2次磁盘IO加载到内存 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 将上一步获得的数据,在内存中进行二分查找获得全部行数据 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">上述查询就包含了一次回表过程,因此性能比主键查询慢了一倍,因此尽量使用主键查询,一次完事。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin-top: 24px;margin-bottom: 12px;"><span style="display: none;"></span><span style="color: #e7642b;text-align: center;display: block;background-color: #e7642b;color: white;padding: 3px 11px;border-radius: 1px;">4. 慢SQL解决思路</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">出现慢SQL的原因很多,我们抛开单表数亿记录和无索引的特殊情况,来讨论一些更有普遍意义的慢SQL原因和解决之道。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">我们从两个方面来进行阐述:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 数据库表索引设置不合理 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> SQL语句有问题,需要优化 </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.33779761904761907" src="/upload/4c21524afc64b0f497d96aaadf580967.png" data-type="png" data-w="1344" style="display: block;border-radius: 5px;margin: 12px auto;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;font-size: 18px;color: rgb(66, 75, 93);"><span style="display: none;"></span>4.1 索引设置原则<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">程序员的角度和存储引擎的角度是不一样的,索引写的好,SQL跑得快。</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>索引区分度低</strong> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">假如表中有1000w记录,其中有status字段表示状态,可能90%的数据status=1,可以不将status作为索引,因为其对数据记录区分度很低。</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>切忌过多创建索引</strong> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">每个索引都需要占用磁盘空间,修改表数据时会对索引进行更新,索引越多,更新越复杂。</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">因为每添加一个索引,.ibd文件中就需要多维护一个B+Tree索引树,如果某一个table中存在10个索引,那么就需要维护10棵B+Tree,写入效率会降低,并且会浪费磁盘空间。</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>常用查询字段建索引</strong> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">如果某个字段经常用来做查询条件,那么该字段的查询速度会影响整个表的查询速度,属于热门字段,为其建立索引非常必要。</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>常排序/分组/去重字段建索引</strong> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">对于需要经常使用ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段建立索引,可以有效借助B+树的特性来加速执行。</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>主键和外键建索引</strong> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">主键可以用来创建聚集索引,外键也是唯一的且常用于表关联的字段,也需要建索引来提高性能。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;font-size: 18px;color: rgb(66, 75, 93);"><span style="display: none;"></span>4.2 SQL的优化<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">如果数据库表的索引设置比较合理,SQL语句书写不当会造成索引失效,甚至造成全表扫描,迅速拉低性能。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;color: rgb(66, 75, 93);"><span style="display: none;"></span>索引失效<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">我们在写SQL的时候在某些情况下会出现索引失效的情况:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>对索引使用函数</strong> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">select id from std upper(name) = 'JIM';</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>对索引进行运算</strong> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">select id from std where id+1=10;</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>对索引使用<> 、not in 、not exist、!=</strong> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">select id from std where name != 'jim';</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>对索引进行前导模糊查询</strong> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">select id from std name like '%jim';</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>隐式转换会导致不走索引</strong> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">比如:字符串类型索引字段不加引号,select id from std name = 100;保持变量类型与字段类型一致</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>非索引字段的or连接</strong> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">并不是所有的or都会使索引失效,如果or连接的所有字段都设置了索引,是会走索引的,一旦有一个字段没有索引,就会走全表扫描。</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>联合索引仅包含复合索引非前置列</strong> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">联合索引包含key1,key2,key3三列,但SQL语句没有key1,根据联合索引的最左匹配原则,不会走联合索引。<br>select name from table where key2=1 and key3=2;</p> </blockquote> <h4 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;color: rgb(66, 75, 93);"><span style="display: none;"></span>好的建议</h4> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;"><strong>使用连接代替子查询</strong></p> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">对于数据库来说,在绝大部分情况下,连接会比子查询更快,使用连接的方式,MySQL优化器一般可以生成更佳的执行计划,更高效地处理查询<br>而子查询往往需要运行重复的查询,子查询生成的临时表上也没有索引, 因此效率会更低。</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>LIMIT偏移量过大的优化</strong> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">禁止分页查询偏移量过大,如limit 100000,10</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;"><strong>使用覆盖索引</strong><br>减少select * 借助覆盖索引,减少回表查询次数。</p> </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;"><strong>多表关联查询时,小表在前,大表在后</strong></p> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">在MySQL中,执行from后的表关联查询是从左往右执行的,第一张表会涉及到全表扫描,所以将小表放在前面,先扫小表,扫描快效率较高,在扫描后面的大表,或许只扫描大表的前100行就符合返回条件并return了。</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <strong>调整Where字句中的连接顺序</strong> </section></li> </ul> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">MySQL采用从左往右的顺序解析where子句,可以将过滤数据多的条件放在前面,最快速度缩小结果集。</p> </blockquote> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;"><strong>使用小范围事务,而非大范围事务</strong></p> </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;"><strong>遵循最左匹配原则</strong></p> </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> <p style="padding-top: 8px;padding-bottom: 8px;font-size: 16px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;"><strong>使用联合索引,而非建立多个单独索引</strong></p> </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;font-size: 18px;color: rgb(66, 75, 93);"><span style="display: none;"></span>4.3 慢SQL的分析<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">在分析慢SQL之前需要通过MySQL进行相关设置:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;padding-left: 24px;color: rgb(66, 75, 93);" class="list-paddingleft-2"> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 开启慢SQL日志 </section></li> <li> <section style="margin-top: 4px;margin-bottom: 4px;line-height: 24px;"> 设置慢SQL的执行时间阈值 </section></li> </ul> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin: 12px auto;border-radius: 5px;box-shadow: 0 1px 2px -2px rgba(0,0,0,.16), 0 3px 6px 0 rgba(0,0,0,.12), 0 5px 12px 4px rgba(0,0,0,.09) !important;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/3a3QxMHZ8Yy6ngT3yG3G78PcQSv93yGOjGTmR4kLFhq1BRiaky4GKHy7pG40rWLB4JQFicHr5ib07AticjtdHLEupYPxicPVnISAM/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">开启:SET GLOBAL slow_query_log = 1;<br>开启状态:SHOW VARIABLES LIKE <span style="color: #98c379;line-height: 26px;">'%slow_query_log%'</span>;<br>设置阈值:SET GLOBAL long_query_time=3;<br>查看阈值:SHOW GLOBAL VARIABLES LIKE <span style="color: #98c379;line-height: 26px;">'long_query_time%'</span>; <br></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 24px;margin-bottom: 12px;font-weight: bold;color: rgb(66, 75, 93);"><span style="display: none;"></span>explain分析SQL<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">explain命令只需要加在select之前即可,例如:</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin: 0px 8px;border-width: initial;border-style: none;border-color: initial;background: rgb(255, 255, 255);box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 2px -2px, rgba(0, 0, 0, 0.12) 0px 3px 6px 0px, rgba(0, 0, 0, 0.09) 0px 5px 12px 4px;"> <p style="padding-top: 8px;padding-bottom: 8px;word-spacing: 3px;letter-spacing: 1px;font-size: 14px;color: rgb(66, 75, 93);line-height: 24px;">explain select * from std where id < 100;</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">该命令会展示sql语句的详细执行过程,帮助我们定位问题,网上关于explain的用法和讲解很多,本文不再展开。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin-top: 24px;margin-bottom: 12px;"><span style="display: none;"></span><span style="color: #e7642b;text-align: center;display: block;background-color: #e7642b;color: white;padding: 3px 11px;border-radius: 1px;">5. 小结</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;word-spacing: 3px;letter-spacing: 1px;color: rgb(66, 75, 93);">本文从慢SQL的危害、Innodb存储引擎、聚集索引、非聚集索引、索引失效、SQL优化、慢SQL分析等角度进行了阐述。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;text-align: left;white-space: normal;letter-spacing: 0.544px;font-size: 14px;text-size-adjust: auto;background-color: rgb(255, 255, 255);caret-color: rgb(0, 0, 0);display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"></figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;text-align: left;white-space: normal;letter-spacing: 0.544px;font-size: 14px;color: rgb(64, 64, 64);text-size-adjust: auto;background-color: rgb(255, 255, 255);caret-color: rgb(0, 0, 0);display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"></figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;text-align: left;white-space: normal;letter-spacing: 0.544px;font-size: 14px;text-size-adjust: auto;background-color: rgb(255, 255, 255);caret-color: rgb(0, 0, 0);display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"></figure> </section>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;line-height: 1.6;letter-spacing: 0.034em;color: rgb(63, 63, 63);font-size: 16px;" data-mpa-powered-by="yiban.io"> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/uL371281oDFpywBzMdt5EHAekqHT61dCrNAsn8v3Nu1Zj4iaYWYFQEspFic6A0oFaVoiaZ3icyLEKKXdibGttCLGmYg/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">前言</span><br></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">在分布式系统中,由于redis分布式锁相对于更简单和高效,成为了分布式锁的首先,被我们用到了很多实际业务场景当中。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">但不是说用了redis分布式锁,就可以高枕无忧了,如果没有用好或者用对,也会引来一些意想不到的问题。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">今天我们就一起聊聊redis分布式锁的一些坑,给有需要的朋友一个参考。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.8096" src="/upload/64f3b31fac6395bb5cbf57e9748ea732.png" data-type="png" data-w="1250" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/uL371281oDFpywBzMdt5EHAekqHT61dCrNAsn8v3Nu1Zj4iaYWYFQEspFic6A0oFaVoiaZ3icyLEKKXdibGttCLGmYg/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">1 非原子操作</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">使用redis的分布式锁,我们首先想到的可能是<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">setNx</code>命令。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/AbruuZ3ILCksBz8lu4TWm4kLiaD4QHSBicPCZTQibRjVYicjySa6Or5apkGebpNE8KD1OCWfbFJq85ppB8gdeKiaYGg3BSr0ZByRH/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">if</span> (jedis.setnx(lockKey, val) == <span style="color: #d19a66;line-height: 26px;">1</span>) {<br> jedis.expire(lockKey, timeout);<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">容易,三下五除二,我们就可以把代码写好。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这段代码确实可以加锁成功,但你有没有发现什么问题?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">加锁操作</code>和后面的<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">设置超时时间</code>是分开的,并<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">非原子操作</code>。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">假如加锁成功,但是设置超时时间失败了,该lockKey就变成永不失效。假如在高并发场景中,有大量的lockKey加锁成功了,但不会失效,有可能直接导致redis内存空间不足。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">那么,有没有保证原子性的加锁命令呢?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">答案是:有,请看下面。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/uL371281oDFpywBzMdt5EHAekqHT61dCrNAsn8v3Nu1Zj4iaYWYFQEspFic6A0oFaVoiaZ3icyLEKKXdibGttCLGmYg/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">2 忘了释放锁</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">上面说到使用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">setNx</code>命令加锁操作和设置超时时间是分开的,并非原子操作。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">而在redis中还有<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">set</code>命令,该命令可以指定多个参数。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/AbruuZ3ILCksBz8lu4TWm4kLiaD4QHSBicPCZTQibRjVYicjySa6Or5apkGebpNE8KD1OCWfbFJq85ppB8gdeKiaYGg3BSr0ZByRH/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">String result = jedis.set(lockKey, requestId, <span style="color: #98c379;line-height: 26px;">"NX"</span>, <span style="color: #98c379;line-height: 26px;">"PX"</span>, expireTime);<br><span style="color: #c678dd;line-height: 26px;">if</span> (<span style="color: #98c379;line-height: 26px;">"OK"</span>.equals(result)) {<br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">true</span>;<br>}<br><span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">false</span>;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">其中:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">lockKey</code>:锁的标识 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">requestId</code>:请求id </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">NX</code>:只在键不存在时,才对键进行设置操作。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">PX</code>:设置键的过期时间为 millisecond 毫秒。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">expireTime</code>:过期时间 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">set</code>命令是原子操作,加锁和设置超时时间,一个命令就能轻松搞定。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">nice</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">使用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">set</code>命令加锁,表面上看起来没有问题。但如果仔细想想,加锁之后,每次都要达到了超时时间才释放锁,会不会有点不合理?加锁后,如果不及时释放锁,会有很多问题。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">分布式锁更合理的用法是:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 手动加锁 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 业务操作 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 手动释放锁 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 如果手动释放锁失败了,则达到超时时间,redis会自动释放锁。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">大致流程图如下:<img data-ratio="0.7063339731285988" src="/upload/eaa49d32d02ebc6512fc1094ccb181f.png" data-type="png" data-w="1042" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;">那么问题来了,如何释放锁呢?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">伪代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/AbruuZ3ILCksBz8lu4TWm4kLiaD4QHSBicPCZTQibRjVYicjySa6Or5apkGebpNE8KD1OCWfbFJq85ppB8gdeKiaYGg3BSr0ZByRH/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">try</span>{<br> String result = jedis.set(lockKey, requestId, <span style="color: #98c379;line-height: 26px;">"NX"</span>, <span style="color: #98c379;line-height: 26px;">"PX"</span>, expireTime);<br> <span style="color: #c678dd;line-height: 26px;">if</span> (<span style="color: #98c379;line-height: 26px;">"OK"</span>.equals(result)) {<br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">true</span>;<br> }<br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">false</span>;<br>} <span style="color: #c678dd;line-height: 26px;">finally</span> {<br> unlock(lockKey);<br>} <br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">需要捕获业务代码的异常,然后在<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">finally</code>中释放锁。换句话说就是:无论代码执行成功或失败了,都需要释放锁。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">此时,有些朋友可能会问:假如刚好在释放锁的时候,系统被重启了,或者网络断线了,或者机房断点了,不也会导致释放锁失败?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这是一个好问题,因为这种小概率问题确实存在。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">但还记得前面我们给锁设置过超时时间吗?即使出现异常情况造成释放锁失败,但到了我们设定的超时时间,锁还是会被redis自动释放。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">但只在finally中释放锁,就够了吗?</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/uL371281oDFpywBzMdt5EHAekqHT61dCrNAsn8v3Nu1Zj4iaYWYFQEspFic6A0oFaVoiaZ3icyLEKKXdibGttCLGmYg/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">3 释放了别人的锁</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">做人要厚道,先回答上面的问题:只在finally中释放锁,当然是不够的,因为释放锁的姿势,还是不对。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">哪里不对?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">答:在多线程场景中,可能会出现释放了别人的锁的情况。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">有些朋友可能会反驳:假设在多线程场景中,线程A获取到了锁,但如果线程A没有释放锁,此时,线程B是获取不到锁的,何来释放了别人锁之说?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">答:假如线程A和线程B,都使用lockKey加锁。线程A加锁成功了,但是由于业务功能耗时时间很长,超过了设置的超时时间。这时候,redis会自动释放lockKey锁。此时,线程B就能给lockKey加锁成功了,接下来执行它的业务操作。恰好这个时候,线程A执行完了业务功能,接下来,在finally方法中释放了锁lockKey。这不就出问题了,线程B的锁,被线程A释放了。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">我想这个时候,线程B肯定哭晕在厕所里,并且嘴里还振振有词。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">那么,如何解决这个问题呢?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">不知道你们注意到没?在使用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">set</code>命令加锁时,除了使用lockKey锁标识,还多设置了一个参数:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">requestId</code>,为什么要需要记录requestId呢?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">答:requestId是在释放锁的时候用的。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">伪代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/AbruuZ3ILCksBz8lu4TWm4kLiaD4QHSBicPCZTQibRjVYicjySa6Or5apkGebpNE8KD1OCWfbFJq85ppB8gdeKiaYGg3BSr0ZByRH/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">if</span> (jedis.get(lockKey).equals(requestId)) {<br> jedis.del(lockKey);<br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">true</span>;<br>}<br><span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #c678dd;line-height: 26px;">false</span>;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">在释放锁的时候,先获取到该锁的值(之前设置值就是requestId),然后判断跟之前设置的值是否相同,如果相同才允许删除锁,返回成功。如果不同,则直接返回失败。</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgb(251, 249, 253);color: rgb(106, 115, 125);margin-bottom: 20px;margin-top: 20px;padding: 15px 20px;line-height: 27px;border-left-color: rgb(53, 179, 120);"> <p style="line-height: 26px;font-size: 15px;color: rgb(89, 89, 89);">换句话说就是:自己只能释放自己加的锁,不允许释放别人加的锁。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这里为什么要用requestId,用userId不行吗?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">答:如果用userId的话,对于请求来说并不唯一,多个不同的请求,可能使用同一个userId。而requestId是全局唯一的,不存在加锁和释放锁乱掉的情况。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">此外,使用lua脚本,也能解决释放了别人的锁的问题:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/AbruuZ3ILCksBz8lu4TWm4kLiaD4QHSBicPCZTQibRjVYicjySa6Or5apkGebpNE8KD1OCWfbFJq85ppB8gdeKiaYGg3BSr0ZByRH/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">if</span> redis.call(<span style="color: #98c379;line-height: 26px;">'get'</span>, KEYS[<span style="color: #d19a66;line-height: 26px;">1</span>]) == ARGV[<span style="color: #d19a66;line-height: 26px;">1</span>] then <br> <span style="color: #c678dd;line-height: 26px;">return</span> redis.call(<span style="color: #98c379;line-height: 26px;">'del'</span>, KEYS[<span style="color: #d19a66;line-height: 26px;">1</span>]) <br><span style="color: #c678dd;line-height: 26px;">else</span> <br> <span style="color: #c678dd;line-height: 26px;">return</span> <span style="color: #d19a66;line-height: 26px;">0</span> <br>end<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">lua脚本能保证查询锁是否存在和删除锁是原子操作,用它来释放锁效果更好一些。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">说到lua脚本,其实加锁操作也建议使用lua脚本:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/AbruuZ3ILCksBz8lu4TWm4kLiaD4QHSBicPCZTQibRjVYicjySa6Or5apkGebpNE8KD1OCWfbFJq85ppB8gdeKiaYGg3BSr0ZByRH/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #c678dd;line-height: 26px;">if</span> (redis.call(<span style="color: #98c379;line-height: 26px;">'exists'</span>, KEYS[<span style="color: #d19a66;line-height: 26px;">1</span>]) == <span style="color: #d19a66;line-height: 26px;">0</span>) then<br> redis.call(<span style="color: #98c379;line-height: 26px;">'hset'</span>, KEYS[<span style="color: #d19a66;line-height: 26px;">1</span>], ARGV[<span style="color: #d19a66;line-height: 26px;">2</span>], <span style="color: #d19a66;line-height: 26px;">1</span>); <br> redis.call(<span style="color: #98c379;line-height: 26px;">'pexpire'</span>, KEYS[<span style="color: #d19a66;line-height: 26px;">1</span>], ARGV[<span style="color: #d19a66;line-height: 26px;">1</span>]); <br> <span style="color: #c678dd;line-height: 26px;">return</span> nil; <br><span style="line-height: 26px;">end<br><span style="color: #61aeee;line-height: 26px;">if</span> <span style="line-height: 26px;">(redis.call(<span style="color: #98c379;line-height: 26px;">'hexists'</span>, KEYS[<span style="color: #d19a66;line-height: 26px;">1</span>], ARGV[<span style="color: #d19a66;line-height: 26px;">2</span>])</span> </span>== <span style="color: #d19a66;line-height: 26px;">1</span>)<br> redis.call(<span style="color: #98c379;line-height: 26px;">'hincrby'</span>, KEYS[<span style="color: #d19a66;line-height: 26px;">1</span>], ARGV[<span style="color: #d19a66;line-height: 26px;">2</span>], <span style="color: #d19a66;line-height: 26px;">1</span>); <br> redis.call(<span style="color: #98c379;line-height: 26px;">'pexpire'</span>, KEYS[<span style="color: #d19a66;line-height: 26px;">1</span>], ARGV[<span style="color: #d19a66;line-height: 26px;">1</span>]); <br> <span style="color: #c678dd;line-height: 26px;">return</span> nil; <br>end; <br><span style="color: #c678dd;line-height: 26px;">return</span> redis.call(<span style="color: #98c379;line-height: 26px;">'pttl'</span>, KEYS[<span style="color: #d19a66;line-height: 26px;">1</span>]);<br></code></pre> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这是redisson框架的加锁代码,写的不错,大家可以借鉴一下。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">有趣,下面还有哪些好玩的东西?</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/uL371281oDFpywBzMdt5EHAekqHT61dCrNAsn8v3Nu1Zj4iaYWYFQEspFic6A0oFaVoiaZ3icyLEKKXdibGttCLGmYg/640?wx_fmt=png");background-position: center center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 50px;margin-top: 1em;margin-bottom: 10px;"><span style="display: none;"></span><span style="display: inline-block;height: 38px;line-height: 42px;color: rgb(72, 179, 120);background-position: left center;background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-size: 63px;margin-top: 38px;font-size: 18px;margin-bottom: 10px;">4 大量失败请求</span></h2> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">上面的加锁方法看起来好像没有问题,但如果你仔细想想,如果有1万的请求同时去竞争那把锁,可能只有一个请求是成功的,其余的9999个请求都会失败。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">在秒杀场景下,会有什么问题?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">答:每1万个请求,有1个成功。再1万个请求,有1个成功。如此下去,直到库存不足。这就变成均匀分布的秒杀了,跟我们想象中的不一样。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">如何解决这个问题呢?</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">此外,还有一种场景:</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">比如,有两个线程同时上传文件到sftp,上传文件前先要创建目录。假设两个线程需要创建的目录名都是当天的日期,比如:20210920,如果不做任何控制,直接并发的创建目录,第二个线程必然会失败。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这时候有些朋友可能会说:这还不容易,加一个redis分布式锁就能解决问题了,此外再判断一下,如果目录已经存在就不创建,只有目录不存在才需要创建。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">伪代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-sha
作者:微信小助手
<section data-mpa-powered-by="yiban.io" style="outline: 0px;max-width: 100%;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="outline: 0px;max-width: 100%;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="outline: 0px;max-width: 100%;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 300px !important;"> <img data-ratio="0.2857142857142857" data-type="gif" data-w="700" title="阅读原文 小猫 动图" class="__bg_gif" src="/upload/1875234db1a3829b7af199c1b6ebf56e.png" style="outline: 0px;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 300px !important;visibility: visible !important;"> </section> </section> </section> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;outline: 0px;max-width: 100%;white-space: normal;background-color: rgb(255, 255, 255);font-size: 16px;color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">一、Nginx Rewrite 规则</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1. Nginx rewrite规则</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">Rewrite规则含义就是某个URL重写成特定的URL(类似于Redirect),从某种意义上说为了美观或者对搜索引擎友好,提高收录量及排名等。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">语法:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;max-width: 100%;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;">rewrite <regex> <replacement> [flag]</code>关键字 || 正则 || 替代内容 || flag标记</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">Rewrite规则的flag标记主要有以下几种:</p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> last :相当于Apache里的(L)标记,表示完成rewrite; </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> break:本条规则匹配完成后,终止匹配,不再匹配后面的规则 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> redirect:返回302临时重定向,浏览器地址会显示跳转后的URL地址 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> permanent:返回301永久重定向,浏览器地址栏会显示跳转后的URL地址 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><em style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">last和break用来实现URL重写,浏览器地址栏URL地址不变</em></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">2. Nginx rewrite例子</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">a) 例如用户访问www.dbspread.com,想直接跳转到网站下面的某个页面,www.dbspread.com/new.index.html如何来实现呢?我们可以使用Nginx Rewrite 来实现这个需求,具体如下:在server中加入如下语句即可:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;outline: 0px;max-width: 100%;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">server {<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> listen 80; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#监听80端口</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> server_name www.dbspread.com; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#域名</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#rewrite规则</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> index index.jsp index.html index.htm;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> root /usr/<span style="outline: 0px;max-width: 100%;color: rgb(230, 192, 123);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">local</span>/nginx/html; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#定义服务器的默认网站根目录位置</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#监听完成以后通过斜杆(/)拦截请求转发到后端的tomcat服务器</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> location / <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> {<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#如果后端的服务器返回502、504、执行超时等错误,自动将请求转发到upstream负载均衡池中的另一台服务器,实现故障转移。</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> proxy_next_upstream http_502 http_504 error timeout invalid_header;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> proxy_set_header Host <span style="outline: 0px;max-width: 100%;color: rgb(209, 154, 102);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">$host</span>; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#获取客户端的主机名存到变量Host里面,从而让tomcat取到客户端机器的信息</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> proxy_set_header X-Real-IP <span style="outline: 0px;max-width: 100%;color: rgb(209, 154, 102);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">$remote_addr</span>; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#获取客户端的主机名存到变量X-Real-IP里面,从而让tomcat取到客户端机器的信息</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> proxy_set_header X-Forwarded-For <span style="outline: 0px;max-width: 100%;color: rgb(209, 154, 102);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">$proxy_add_x_forwarded_for</span>;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> rewrite ^/$ http://www.dbspread.com/new.index.html permanent;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> proxy_pass http://web1; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#跳转到对应的应用web1</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> }<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">效果图如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.24533333333333332" data-type="png" data-w="1125" src="/upload/967ea9002e6f125f5b95a4472df2fc48.png" style="margin-right: auto;margin-left: auto;outline: 0px;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> </figure> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;outline: 0px;max-width: 100%;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">rewrite ^/$ http://www.dbspread.com/new.index.html permanent;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">对应如下语法:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;max-width: 100%;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;">rewrite <regex> <replacement> [flag];</code>关键字 || 正则 || 替代内容 || flag标记</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">正则表达式说明:</strong></p> <blockquote data-tool="mdnice编辑器" style="margin-top: 20px;margin-bottom: 20px;padding: 10px 10px 10px 20px;outline: 0px;border-left-color: rgb(239, 112, 96);color: rgb(106, 115, 125);font-size: 0.9em;max-width: 100%;border-top: none;border-right: none;border-bottom: none;overflow: auto;background: rgb(255, 249, 249);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;font-size: 16px;color: black;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">*代表前面0或更多个字符 +代表前面1或更多个字符 ?代表前面0或1个字符 ^代表字符串的开始位置 $代表字符串结束的位置 。为通配符,代表任何字符</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">b)例如多个域名跳转到同一个域名,nginx rewrite规则写法如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;outline: 0px;max-width: 100%;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">server {<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> listen 80; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#监听80端口</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> server_name www.dbspread.com; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#域名</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#rewrite规则</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> index index.jsp index.html index.htm;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> root /usr/<span style="outline: 0px;max-width: 100%;color: rgb(230, 192, 123);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">local</span>/nginx/html; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#定义服务器的默认网站根目录位置</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(198, 120, 221);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">if</span> (<span style="outline: 0px;max-width: 100%;color: rgb(209, 154, 102);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">$host</span> != <span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">'www.dbspread.com'</span> ){ <br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> rewrite ^/(.*)$ http://www.dbspread.com/<span style="outline: 0px;max-width: 100%;color: rgb(209, 154, 102);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">$1</span> permanent;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> }<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">格式:</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;max-width: 100%;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;">rewrite <regex> <replacement> [flag];</code>关键字 || 正则 || 替代内容 || flag标记</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">说明:</strong></p> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> rewrite为固定关键字,表示开始进行rewrite匹配规则、 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> regex部分是 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;max-width: 100%;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;">^/(.*)</code> ,这是一个正则表达式,匹配完整的域名和后面的路径地址 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> replacement部分是 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;max-width: 100%;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;">http://www.dbspread.com/$1</code>, <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;max-width: 100%;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;">$1</code>是取自regex部分( )里的内容。匹配成功后跳转到的URL。 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> flag部分 permanent表示永久301重定向标记,即跳转到新的 <code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;max-width: 100%;font-size: 14px;border-radius: 4px;background-color: rgba(27, 31, 35, 0.047);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;">http://www.dbspread.com/$1</code> 地址上 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">二、Nginx 防盗链</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1. 什么是防盗链</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">比如http://www.dbspread.com/download/av123.rmvb 这个视频下载地址被其他网站引用,比如在www.test.com的index.html引用download/av123.rmvb就叫盗链,我们要禁止这种引用就叫做防盗链</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">2. 怎么实现防盗链</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">在nginx的nginx.conf的server里面配置如下代码</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;outline: 0px;max-width: 100%;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">server {<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> listen 80;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> server_name www.dbspread.com *.dbspread.com;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> location ~* \.(rmvb|jpg|png|swf|flv)$ { <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#rmvb|jpg|png|swf|flv表示对rmvb|jpg|png|swf|flv后缀的文件实行防盗链</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> valid_referers none blocked www.dbspread.com; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#表示对www.dbspread.com此域名开通白名单,比如在www.test.com的index.html引用download/av123.rmvb,无效</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> root html/b;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(198, 120, 221);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">if</span> (<span style="outline: 0px;max-width: 100%;color: rgb(209, 154, 102);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">$invalid_referer</span>) { <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#如果请求不是从www.dbspread.com白名单发出来的请求,直接重定向到403.html这个页面或者返回403 </span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#rewrite ^/ http://www.dbspread.com/403.html;</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(230, 192, 123);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">return</span> 403;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> }<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> }<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> }<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 1.3em;max-width: 100%;border-bottom: 2px solid rgb(239, 112, 96);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="margin-right: 3px;padding: 3px 10px 1px;outline: 0px;max-width: 100%;display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);border-top-right-radius: 3px;border-top-left-radius: 3px;box-sizing: border-box !important;overflow-wrap: break-word !important;">三、Nginx 动静分离</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">1. 动静分离是什么</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">Nginx动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">2. 动静分离原理图</h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.4568121104185218" data-type="png" data-w="1123" src="/upload/abc0015a88da7ec75c903f69e928ec12.png" style="margin-right: auto;margin-left: auto;outline: 0px;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">3. Nginx动静分离应该注意的地方</h3> <ul data-tool="mdnice编辑器" class="list-paddingleft-2" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;outline: 0px;max-width: 100%;overflow-wrap: break-word !important;"> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> WEB项目开发时要注意,将静态资源尽量放在一个static文件夹 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 将static静态资源文件夹放到Nginx可以取到的位置 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 页面要建立全局变量路径,方便修改路径 </section></li> <li style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 5px;margin-bottom: 5px;outline: 0px;max-width: 100%;line-height: 26px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 修改nginx.conf的location, 匹配静态资源请求 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;outline: 0px;font-weight: bold;font-size: 20px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">4. Nginx动静分离步骤</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">4.1 准备一个静态资源button.css</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;outline: 0px;max-width: 100%;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">body {<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> margin: 10px 20px;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> text-align: center;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> font-family: Arial, sans-serif;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> background-color: red;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">}<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">4.2 在/var/local下新建一个static文件夹用来存放静态资源button.css</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="0.25471698113207547" data-type="png" data-w="212" src="/upload/174e05b6c74538b84d68757c0488e204.png" style="margin-right: auto;margin-left: auto;outline: 0px;display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;width: 212px !important;visibility: visible !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">4.3 在tomcat-8080/webapps/ROOT下的index.html里面引入button.css</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;outline: 0px;max-width: 100%;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><html><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <head><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <link rel=<span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"stylesheet"</span> <span style="outline: 0px;max-width: 100%;color: rgb(230, 192, 123);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">type</span>=<span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"text/css"</span> href=<span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"http://www.static.com/button.css"</span> /><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <meta charset=<span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"utf-8"</span>><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <meta http-equiv=<span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"X-UA-Compatible"</span> content=<span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"IE=edge,chrome=1"</span>><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <meta name=<span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"renderer"</span> content=<span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"webkit"</span>><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <meta name=<span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"viewport"</span> content=<span style="outline: 0px;max-width: 100%;color: rgb(152, 195, 121);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"</span>><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <title><span style="outline: 0px;max-width: 100%;color: rgb(230, 192, 123);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">test</span></title><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </head><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <body><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> 欢迎来到8080端口tomcat<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </body><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></html><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;outline: 0px;max-width: 100%;min-height: 1em;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">4.4 在nginx的nginx.conf中server节点新增静态资源分离的配置</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;outline: 0px;max-width: 100%;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><code style="padding: 15px 16px 16px;outline: 0px;max-width: 100%;overflow-x: auto;color: rgb(171, 178, 191);display: -webkit-box;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;font-size: 12px;background: rgb(40, 44, 52);border-radius: 5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">server {<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> listen 80; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#监听80端口</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> server_name www.dbspread.com; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#域名</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#rewrite规则</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> index index.jsp index.html index.htm;<br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> root /usr/<span style="outline: 0px;max-width: 100%;color: rgb(230, 192, 123);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">local</span>/nginx/html; <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#定义服务器的默认网站根目录位置</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(92, 99, 112);font-style: italic;line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;">#重定向</span><br style="outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="outline: 0px;max-width: 100%;color: rgb(198, 120, 221);line-height: 26px;box-sizing: border-box !important;overflow-wrap: break-word !important;"