實戰:Java web應用性能分析之【異步日志:性能優化的金鑰匙】

概敘

實戰:Java web應用性能分析之【Arthas性能分析trace監控后端性能】-CSDN博客

在優化方面,可以采取以下步驟:

  1. ?性能分析工具?:使用Arthas或Async Profiler進行實時診斷,定位耗時的方法調用。這可以幫助精確找到瓶頸所在,而不是僅依靠日志推測?。
  2. ?優化JSON處理?:檢查請求體和響應體的數據大小,優化DTO結構,移除不必要的字段。同時,可以切換為更高效的序列化庫,比如替換默認的Jackson為Fastjson,或者調整Jackson的配置以提升性能?。
  3. ?連接池預熱?:在應用啟動時主動初始化數據庫連接,避免首次請求時建立連接的耗時。這在之前的回答中已經提供了MyBatis的預熱方法,用戶可以參考實施?。
  4. ?JVM預熱?:通過模擬請求觸發JIT編譯。
  5. ?緩存預熱?:啟動時加載高頻數據到緩存。
  6. ?懶加載優化?:將部分初始化移到啟動階段。
  7. ?異步日志記錄?:確保日志記錄是異步的,避免同步寫日志阻塞請求處理。使用Logback或Log4j2的異步Appender配置,將日志寫入隊列后由后臺線程處理?。
  8. ?事務優化?:檢查Service方法的事務配置,確保@Transactional注解的范圍合理,避免在事務中包含非數據庫操作。對于只讀操作,可以設置readOnly=true以提升性能?。
  9. ?精簡攔截器邏輯?:審查所有Filter和Interceptor的實現,移除不必要的操作,特別是避免在Filter中進行復雜的計算或同步IO操作。確保這些組件的邏輯盡可能高效?。

關鍵優化點總結

  1. ?緩存預熱?:啟動時主動加載高頻數據,避免首次查詢穿透數據庫。
  2. ?連接池預熱?:初始化時建立最小空閑連接,減少首次SQL延遲。
  3. ?JVM預熱?:通過模擬請求觸發JIT編譯,加速熱點方法。
  4. ?批量操作?:合并單次插入為批量操作,減少事務開銷。
  5. ?DTO轉換優化?:用MapStruct生成編譯期代碼,替代反射拷貝。

本文主要介紹了Log4j2框架的核心原理、實踐應用以及一些實用的小Tips,力圖揭示Log4j2這一強大日志記錄工具在現代分布式服務架構運維中的關鍵作用。

一、 背景

2024年4月的一個寧靜的夜晚,正當大家忙完一天的工作準備休息時,應急群里“咚咚咚”開始報警,提示我們余利寶業務的贖回接口成功率下降。

通過Monitor監控發現,該接口的耗時已經超過了網關配置的超時閾值(2s),我們臨時調整超時閾值止血后,就在排查問題的根因。具體排查過程不是我這篇文章的重點,故忽略,但最終我們發現最近上線新加的相鄰兩行的日志中,時間相差近1.5s,難道這就是問題的根源嗎?

后來,我們去掉了這兩行日志后緊急發布,事實證明我們的思路是對的。

緊急發布后,該接口的耗時由之前的2s左右,優化到了600ms左右。后來我們分析發現:該接口在打印日志時,由于要實現日志脫敏,故在Logger.info入口處實現了脫敏功能,但是大日志脫敏比較耗時,從而導致該接口的同步調用耗時激增到1.5s左右(后面我們會說如何解決這個問題)。我的天吶,一行日志竟是性能優化的金鑰匙!!!

但這里有一個問題,我們是去掉了日志的打印,侵入了業務,同時該應用還是用的log4j的日志框架,log4j原生框架是不支持日志異步化的,因此要從根本上業務無侵入的解決因日志而導致的性能問題,需要熟悉log4j2的框架原理。

二、原理

2.1 Log4j2的優勢

  1. 性能:?Log4j2使用基于Lambda的異步記錄器,顯著提高了日志記錄的速度,減少了日志操作對應用性能的影響。相比之下,Logback雖然也支持異步記錄,但實現上不如Log4j2高效。通過減少對象創建、高效的字符串處理和池化技術,Log4j2在高并發場景下表現更佳。

  2. 配置靈活性:?支持多種配置方式,包括XML、JSON、YAML、properties文件,甚至編程式配置,提供更大的靈活性。動態重新配置能力,允許在不重啟應用的情況下修改日志配置。

  3. 插件架構:?Log4j2采用插件架構,幾乎所有組件(如Appenders、Layouts、Filters)都是可插拔的,易于擴展和自定義。內置豐富的插件庫,開箱即用,簡化集成過程。

  4. 內存和資源管理:?更高效的內存管理,減少內存泄漏的風險,尤其是在大量日志輸出時。支持垃圾回收友好的設計,比如基于Disrupter的RingBuffer等數據結構減少GC壓力。

  5. 可靠性:?強大的故障恢復機制,如重試和備用Appenders,確保日志能夠被記錄下來,即使主要的日志輸出目的地不可用。

  6. 先進的特性:

    • 支持條件日志記錄(Conditionals),可以根據運行時條件決定是否記錄日志。

    • 自動重新加載配置文件變化,無需重啟應用。

    • 支持JMX監控和管理日志系統狀態。

  1. 與SLF4J的集成:雖然這不是特有優勢,但Log4j2提供了與SLF4J(Simple Logging Facade for Java)的良好集成,使得從其他日志框架遷移更加平滑。

總的來說,Log4j2的設計更現代化,強調高性能、易用性和靈活性,特別是在大規模分布式系統和高性能應用中表現突出。而Logback和Log4j 1.x雖有各自的優點,但在這些方面逐漸顯得力不從心。至于Java Util Logging (JUL),它是Java標準庫的一部分,但功能相對基礎,配置和擴展性不如Log4j2和Logback靈活。

2.2 Log4j2的結構

Log4j2的結構主要包括以下幾個核心組件:

  1. Logger:?這是開發者直接使用的接口,用于記錄不同級別的日志信息(如DEBUG, INFO, ERROR等)。每個Logger都有一個名稱,并且支持繼承性,形成一個名為Logger Hierarchy的樹狀結構,根Logger的名稱為"root"。

  2. LoggerContext:?是日志系統的上下文環境,管理著一組Logger實例以及它們的配置。每個應用程序通常只有一個LoggerContext,但它支持多個上下文以實現更細粒度的控制。

  3. Configuration:?每個LoggerContext都關聯一個有效的Configuration,定義了日志的輸出目的地(Appenders)、日志的過濾規則(Filters)、日志的格式化方式(Layouts)等。Configuration可以通過配置文件(如XML、JSON、properties)或編程方式動態加載。

  4. Appender:?負責將日志事件發送到指定的目標,如控制臺(Console)、文件(File)、數據庫、網絡Socket等。

  5. Layout:?定義了日志信息的格式化方式,如模式字符串(Pattern String)決定了日期、時間、日志級別、線程名、日志信息等內容的排列和格式。

  6. Filter:?可以在日志事件從Logger傳遞到Appender的過程中進行過濾,根據特定條件決定日志是否被輸出。

  7. Lookup:?提供動態值解析機制,如${ctx:variable}可以在日志中插入上下文變量的值。

那么,Log4j2的日志是怎么將日志輸出到文件/數據庫/控制臺等地方的?

2.3 Log4j2日志輸出流程

關鍵步驟源碼分析:

1. 1.1主要是針對日志級別Level和指定的全局Filter組件進行過濾

圖片


?

圖片

圖片

2. ReliabilityStrategy是Log4j2的日志可靠性策略實現,目前主要有以下四種:

  • AwaitCompletionReliabilityStrategy:?等待日志接收完成策略。這種策略主要是在應用關閉時,盡可能要等應用日志接收完成后再結束Appender的生命周期(這種策略只是說盡可能所有日志等待調用Appender.append方法完成,但在異步日志場景下,Appender.append其實是落了ringbuffer或者其他隊列里,實際上未持久化。因此該策略是盡可能保證接收完成而非處理完成)

  • AwaitUnconditionallyReliabilityStrategy:?無條件等待策略。這種策略會在rootLogger關閉時無條件等待一段時間,具體等待時間可以配置log4j2.component.properties文件的log4j.waitMillisBeforeStopOldConfig屬性。

  • DefaultReliabilityStrategy:?默認策略。該策略不做任何等待。

  • LockingReliabilityStrategy:?鎖等待策略。該策略當正在寫入日志時,則會等待;否則即會停止等待。

  1. 1.2.1.3.1append操作是將日志寫入到對應的目的地,如kafka、本地文件、郵件等。這里如果是異步日志,則會將日志追加到異步隊列里,進而提高日志記錄的性能。

  2. 1.2.1.3.1.1調用Layout encode日志,是根據log4j2.xml中配置的Layout對日志進行格式化輸出。

那么如果有一些個性化的日志輸出需求,log4j2能否幫我們實現?

2.4 如何實現日志脫敏

上面提到了log4j2的各種組件以及日志輸出流程,log4j2的強大很大程度上得益于其清晰且高度解耦的架構設計。例如其具有很強的擴展性,log4j2的很多組件都可以自己定制插件,如:Appender、Filter、Layout等。那么這里我結合我們實際業務中一個很常見的case去分析如何定制一個組件。

首先,作為一家強監管的金融公司,日志脫敏涉及數據保護和隱私安全等問題,非常重要。過去我們很多業務系統在實現業務脫敏時,很容易想到在打日志的入口統一封裝一個格式化方法,造成日志輸出在無形中把異步日志輸出變成了同步輸出(日志脫敏的耗時往往比日志集中持久化到磁盤耗時要高)。那么如何優雅的實現日志脫敏的功能,既能實現其功能又可以保證日志的性能,是log4j2插件化的一個很重要的應用場景。前面我們提到日志輸出流程中會使用Layout encode日志,而PatternConverter是Layout非常重要的組成部分。其通過定義一系列的占位符(如%d、%m、 %t等)幫助我們自定義格式輸出日志對象,同時PatternConverter支持以高度可定制的插件集成到Log4j2框架中,因此我們可以借助其去定制脫敏組件。話不多說,我們直接上日志脫敏PatternConverter插件源碼:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//import java.util.Arrays;
import org.apache.logging.log4j.core.LogEvent;import org.apache.logging.log4j.core.config.plugins.Plugin;import org.apache.logging.log4j.core.pattern.ConverterKeys;import org.apache.logging.log4j.core.pattern.LogEventPatternConverter;import org.apache.logging.log4j.message.FormattedMessage;import org.apache.logging.log4j.message.Message;import org.apache.logging.log4j.message.MessageFormatMessage;import org.apache.logging.log4j.message.ParameterizedMessage;import org.apache.logging.log4j.message.StringFormattedMessage;import org.apache.logging.log4j.util.PerformanceSensitive;
/** * @author baichun * @version ShieldMessagePatternConverter.java, v 0.1 2024年04月09日 21:13 baichun */@Plugin(        name = "ShieldPatternConverter",        category = "Converter")@ConverterKeys({"shield", "sd", "shieldMessage", "sm"})@PerformanceSensitive({"allocation"})public final class ShieldMessagePatternConverter extends LogEventPatternConverter {    private final String[] options;
    private ShieldMessagePatternConverter(String[] options) {        super("Shield", "shield");        this.options = options == null ? null : (String[])Arrays.copyOf(options, options.length);    }
    //必須要有newInstance方法,log4j2會調用該方法進行初始化    public static ShieldMessagePatternConverter newInstance(String[] options) {        return new ShieldMessagePatternConverter(options);    }    @Override    public void format(LogEvent logEvent, StringBuilder output) {        Message message = logEvent.getMessage();        String format = message.getFormat();
        if (isFormatMessage(message)) {            //在這里格式化脫敏日志            String msgInfo = ShieldUtils.format(format, message.getParameters());
            output.append(msgInfo);        } else {            output.append(message.getFormattedMessage());        }    }
    private boolean isFormatMessage(Message message) {        return message instanceof ParameterizedMessage || message instanceof StringFormattedMessage                || message instanceof FormattedMessage || message instanceof MessageFormatMessage;    }}

定義好組件后,log4j2即能夠自動掃描識別到,不需要其他定義和配置。接下來看看如何使用。ConverterKeys這個注解指定了在log4j2.xml中應如何使用該插件。

以下是log4j2.xml應用示例:

        <RollingFile name="TEST_APPENDER" fileName="test.log"                     filePattern="test.log.%d{yyyy-MM-dd}"                     append="true">            <!-- %sm即為脫敏組件 -->            <PatternLayout pattern="%d %sm%n" charset="UTF-8"/>            <TimeBasedTriggeringPolicy/>            <DefaultRolloverStrategy/>        </RollingFile>

2.5 Log4j2的異步日志

2.5.1 異步日志原理概述

前面提到了Log4j2的高可擴展性,同時Log4j2的性能也是極高的,下面是Log4j2官方的benchmark數據,僅供參考:

Log4j2之所以性能如此之高,其中一個很重要的原因就是其基于Disrupter的環形緩沖區的無鎖化結構Ringbuffer設計。Disruptor是英國外匯交易公司LMAX開發的一個高性能隊列,基于Disruptor開發的系統單線程能支撐每秒600萬訂單。目前,包括Apache Strom、Log4j2在內的很多知名項目都應用了Disruptor來獲取高性能。關于Disruptor的原理,這里不再贅述,大家可以自行查閱:https://lmax-exchange.github.io/disruptor/#_what_is_the_disruptor

Disrupter組件構成:

圖片

Disrupter性能測試結果

2.5.2 如何使用異步日志

log4j2開啟異步日志的方法主要有以下兩種方式:

  • 全局異步日志

1. 通過JVM啟動參數來全局啟用異步日志功能。在啟動應用程序時,向JVM傳遞以下系統屬性:

     -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

    2. 在類路徑(classpath)中添加一個名為log4j2.component.properties的文件,并包含以下內容(這個文件會在Log4j2初始化時被讀取):

      Log4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
      這兩種方式下,所有Logger都會自動使用異步處理。
      • 混合異步日志
        在log4j2.xml配置文件中,可以手動指定特定的Logger使用異步處理,通過將 <Root>或<Logger>元素替換為<AsyncRoot>或<AsyncLogger>。例如:

      <Configuration status="WARN">    <Appenders>        ... <!-- your appenders here -->    </Appenders>    <Loggers>        <AsyncRoot level="info" includeLocation="false">            <AppenderRef ref="yourAppenderName"/>        </AsyncRoot>        <!-- 或者為特定logger配置 -->        <AsyncLogger name="com.example.MyClass" level="debug">            <AppenderRef ref="yourAppenderName"/>        </AsyncLogger>    </Loggers></Configuration>

      2.5.3 異步日志的潛在問題及解決方案

      • 潛在問題:

      1. 日志丟失問題:如果機器發生意外重啟、發布、掉電導致的jvm進程停止,停留在隊列的未來得及輸出到目的地的LogEvent可能會丟失

      2. 日志順序問題:由于日志事件是在不同的線程中異步處理的,因此日志條目可能不會嚴格按照它們產生的順序出現在日志文件中,這對于需要嚴格按時間順序追蹤日志的應用可能是個問題。

      3. 其他問題:如增加資源損耗、配置復雜度和調試復雜度等問題

      • 解決方案:

      1. 對于日志丟失問題:

      • 原生Log4j2有完整的生命周期管理,并監聽了jvm關閉的事件。當jvm關閉時,Log4j2會監聽Disrupter隊列中的RingbufferLogEvent數量,直到日志打印完(或超時)才釋放關閉Log4j2,jvm才得以正常關閉。但是自然災害或者機房掉電等不可抗力因素,無法避免丟失問題。

      • 我們基于Log4j2定制的AsyncAbleRollingFileAppender,其中有獨立的Disrupter,且不在Log4j2生命周期管理當中,存在日志丟失風險。可以采用類似方案解決:

           try {            LoggerContextFactory factory = LogManager.getFactory();            if (!(factory instanceof Log4jContextFactory)) {                return;            }            Log4jContextFactory log4jContextFactory = (Log4jContextFactory) factory;            ShutdownCallbackRegistry registry = log4jContextFactory.getShutdownCallbackRegistry();            if (!(registry instanceof DefaultShutdownCallbackRegistry)) {                return;            }            DefaultShutdownCallbackRegistry defaultShutdownCallbackRegistry = (DefaultShutdownCallbackRegistry) registry;            Field hooksField = DefaultShutdownCallbackRegistry.class.getDeclaredField("hooks");            hooksField.setAccessible(true);            Collection<Cancellable> hooks = (Collection<Cancellable>) hooksField.get(defaultShutdownCallbackRegistry);            Collection<Cancellable> newHooks = new CopyOnWriteArrayList<>();            //將對Appender的隊列消費監聽和卸載放在首要位置,避免log4j2關閉后再卸載Appender            newHooks.add(new Log4j2Cancellable(() -> {               //負責監聽AsyncAbleRollingFileAppender的隊列消費情況,并在消費完成后關閉AsyncAbleRollingFileAppender                new AppenderUnInstaller(register).run();            }));            newHooks.addAll(hooks);            hooksField.set(defaultShutdownCallbackRegistry, newHooks);        } catch (NoSuchFieldException e) {            // This catch statement is intentionally empty        } catch (IllegalAccessException e) {            // This catch statement is intentionally empty        }
      • AsyncAbleRollingFileAppender使用獨立的disrupter,且RingBufferLogEvent未及時清理對象,容易導致內存泄漏,異步日志場景請慎用。

      1. 對于日志順序性問題:

      • 異步線程池大小設置為1,但是會影響日志打印的速度(現在的普遍做法)。

      • 延遲打印

      三、效果

      4月份的這一問題發生后,我們從原理出發,對理財的核心應用做了升級和優化,整體服務耗時上取得了不錯的性能優化效果。

      應用rpc耗時:

      應用網關耗時:

      但與此同時,我們也發現升級后,應用的fgc次數更多了,經過heapdump分析后,發現AsyncAbleRollingFileAppender內部實現的RingBufferLogEvent執行后,不會釋放引用的LogEvent,導致Disrupter一直持有已打印的LogEvent的引用關系,進而導致了內存泄漏。后來,我們采取主動釋放對象引用(RingBufferLogEvent.setLogEvent(null))優化的方案,發布以后前后fgc對比如下:

      GC優化前:

      GC優化后:

      四、建議

      日志作為診斷問題、監控系統健康狀況與優化服務效能不可或缺的一環,其重要性不言而喻。熟練掌握并有效利用如Log4j2這樣的高性能日志框架以及注意一些打印日志的策略(如動靜分離、合理分割、合理設置日志級別等),對于開發者而言至關重要:

      • 動靜分離 :在一些大日志輸出場景中,即使是異步日志也會給系統帶來性能風險。因此建議合理識別大日志中的動態數據和靜態數據。靜態數據定時輸出,動態數據關聯唯一靜態標識輸出,在降低性能風險的同時又滿足監控分析的需要;

      • 合理分割 :日志文件需要合理分割,并設置合理的保留策略,及時釋放磁盤空間。

      • 合理設置日志級別 :避免日志濫用,尤其是debug日志,既有利于日志定位問題的速度,又能提高性能。

      本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
      如若轉載,請注明出處:http://www.pswp.cn/bicheng/84735.shtml
      繁體地址,請注明出處:http://hk.pswp.cn/bicheng/84735.shtml
      英文地址,請注明出處:http://en.pswp.cn/bicheng/84735.shtml

      如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

      相關文章

      Puppeteer API

      ??親愛的技術愛好者們,熱烈歡迎來到 Kant2048 的博客!我是 Thomas Kant,很開心能在CSDN上與你們相遇~?? 本博客的精華專欄: 【自動化測試】

      【機器學習】Teacher-Student框架

      Teacher-Student Setup是一個經典的機器學習框架&#xff0c;包含兩個核心角色&#xff1a; 教師模型 (Teacher Model)&#xff1a; 通常是一個更大、更強、已經訓練好&#xff08;或正在訓練&#xff09;的模型。它對問題有很好的理解&#xff0c;性能優秀。它的作用是為學生提…

      華為云Flexus+DeepSeek征文|體驗華為云ModelArts快速搭建Dify-LLM應用開發平臺并創建聯網大模型

      華為云FlexusDeepSeek征文&#xff5c;體驗華為云ModelArts快速搭建Dify-LLM應用開發平臺并創建聯網大模型 什么是華為云ModelArts 華為云ModelArts ModelArts是華為云提供的全流程AI開發平臺&#xff0c;覆蓋從數據準備到模型部署的全生命周期管理&#xff0c;幫助企業和開發…

      Web API 路徑設計哪家強

      本文檔主要比較一下各家API的URL路徑設計&#xff0c;通過學習各家API的URL路徑設計&#xff0c;加深對 REST API 的理解&#xff0c;幫助我們設計出更符合 REST 風格的 API。 Google API 文檔地址&#xff1a;https://developers.google.com/apis-explorer/#p/ YouTube Dat…

      微信小程序中的計算屬性庫-miniprogram-computed

      miniprogram-computed 是一個用于微信小程序的擴展庫&#xff0c;它提供了計算屬性&#xff08;computed&#xff09;和監聽器&#xff08;watch&#xff09;的功能&#xff0c;類似于 Vue.js 中的計算屬性和監聽器。以下是使用 miniprogram-computed 的詳細步驟&#xff1a; …

      【CSS-7】深入解析CSS偽類:從基礎到高級應用

      CSS偽類是前端開發中不可或缺的強大工具&#xff0c;它們允許我們根據文檔樹之外的信息或簡單選擇器無法表達的狀態來樣式化元素。本文將全面探討CSS偽類的各種類型、使用場景和最佳實踐。 1. 偽類基礎概念 1.1 什么是偽類&#xff1f; 偽類&#xff08;Pseudo-class&#x…

      藍橋杯國賽訓練 day4

      目錄 再創新高 藍橋大使 表演賽 次數差 再創新高 import java.math.*; import java.util.*;public class Main {static Scanner sc new Scanner(System.in);public static void main(String[] args) {int t 1; // tsc.nextInt();for(int i0;i<t;i) {solve();}} p…

      java 高并發設計

      文章目錄 目錄 文章目錄 前言 一、通用設計 一、動靜分離 二、數據庫獨立部署 三、問題 1.高并發通用設計方法 2.高并發系統的拆分順序 二、計算資源高并發 三、網絡資源高并發 超高性能場景&#xff08;10萬 QPS&#xff09; 中小規模場景&#xff08;5萬 QPS以下&a…

      docker compose搭建elk 8.6.2

      環境搭建 選用版本是比較新的版本 (ELK) 8.6.2 &#xff0c;elk的環境做的還是比較好的又windows和Linux多個版本&#xff0c;并且開箱即用。本地直接下載官方軟件也是可以的。最近在學習docker compose&#xff0c;就使用這個環境搭建一下。 前置條件 安裝好docker和 docke…

      Springboot3+的id字符串轉化問題

      以下是純后端實現 Long/BigInteger ID 轉為 JSON 字符串 的詳細配置方案&#xff0c;基于 Spring Boot 3 和 SpringDoc (OpenAPI) 最新實踐 ? 1. 添加依賴 確保你的 pom.xml&#xff08;或 Gradle&#xff09;中包含&#xff1a; <dependency><groupId>com.fast…

      C#學習第30天: 匹配模式

      模式匹配&#xff08;Pattern Matching&#xff09;是 C# 中一個強大且靈活的特性&#xff0c;允許開發者以更直觀的方式檢查數據結構&#xff0c;并根據特定模式執行操作。 隨著 C# 語言版本的發展&#xff0c;模式匹配的功能越來越豐富&#xff0c;為處理復雜數據提供了極大…

      SQL進階之旅 Day 29:NoSQL結合使用策略

      【SQL進階之旅 Day 29】NoSQL結合使用策略 文章簡述 隨著數據量的激增和業務場景的復雜化&#xff0c;傳統關系型數據庫在某些場景下已難以滿足高性能、高擴展性和靈活數據結構的需求。NoSQL&#xff08;非關系型數據庫&#xff09;以其高可擴展性、靈活的數據模型和分布式架構…

      PostgreSQL 對 IPv6 的支持情況

      PostgreSQL 對 IPv6 的支持情況 PostgreSQL 全面支持 IPv6 網絡協議&#xff0c;包括連接、存儲和操作 IPv6 地址。以下是詳細說明&#xff1a; 一、網絡連接支持 1. 監聽 IPv6 連接 在 postgresql.conf 中配置&#xff1a; listen_addresses 0.0.0.0,:: # 監聽所有IPv4…

      模板字符串使用點擊事件【VUE3】

      項目場景&#xff1a; 提示&#xff1a;這里簡述項目相關背景&#xff1a; 項目中使用模板字符串的時候很多&#xff0c;有些時候需要再模板字符串中使用點擊事件&#xff0c;那么在模板字符串中可以使用點擊事件么&#xff1f;如果這個點擊事件需要傳參呢&#xff1f; 答案…

      AI——DeepSeek+LangChain+streamlit 實現智能汽車維修服務

      效果圖 分析流程 代碼實現 廢話少說&#xff0c;直接上代碼 from langchain_core.language_models.llms import BaseLLM from langchain_core.outputs import Generation, LLMResult from pydantic.v1 import Field, validator from typing import Any, Dict, List, Optional…

      《C++ 繼承》

      目錄 繼承的定義 繼承類模板 派生類和基類之前的轉換 隱藏 派生類的默認成員函數 不能被繼承的類 繼承中的友元和靜態成員 繼承模型 繼承的定義 繼承的本質是一種復用。規定Person類為基類&#xff0c;Student類為派生類 。 繼承方式分為public繼承&#xff0c;prote…

      金蝶K3 ERP 跨網段訪問服務器卡頓問題排查和解決方法

      我一朋友公司反應&#xff0c;公司網絡卡頓&#xff0c;測試掉包嚴重&#xff0c;抓包wireshark測試&#xff0c;發現arp包有大量mac欺騙&#xff0c;因為公司有幾百臺電腦&#xff0c;所以建議更換了三層交換機&#xff0c;劃分了vlan&#xff0c;這樣有效的避免了網絡風暴等&…

      無需安裝!在線數據庫工具 :實戰 SQL 語句經典案例

      在數字化時代&#xff0c;SQL&#xff08;結構化查詢語言&#xff09;已成為數據從業者、開發人員乃至業務分析人員必備的核心技能。無論是處理日常數據報表&#xff0c;還是應對復雜的業務邏輯&#xff0c;SQL 都能高效實現數據的查詢、操作與分析。本文將通過經典的 SQL 練習…

      如何在網頁里填寫 PDF下拉框

      對于PDF 開發者或網頁開發者來說&#xff0c;讓用戶在網站上填寫 PDF 下拉框&#xff08;Combo Box&#xff09;是一個棘手的問題。因為 PDF 并不是一種原生的 Web 格式&#xff0c;瀏覽器通常不允許用戶與 PDF 下拉框進行交互。 那么&#xff0c;如何讓用戶在 HTML 中填寫 PD…

      .Net 優秀框架 ABP全面詳解

      文章目錄 第一部分&#xff1a;ABP框架概述與核心架構1.1 ABP框架簡介1.2 ABP框架架構解析1.2.1 表現層(Presentation Layer)1.2.2 分布式服務層(Distributed Service Layer)1.2.3 應用層(Application Layer)1.2.4 領域層(Domain Layer)1.2.5 基礎設施層(Infrastructure Layer)…