最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

自定義starter引發(fā)的線上事故記錄復盤

 更新時間:2023年05月24日 11:47:28   作者:linyb極客之路  
這篇文章主要為大家介紹了自定義starter引發(fā)的線上事故記錄復盤,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

本文素材來源于業(yè)務部門技術(shù)負責人某次線上事故復盤分享。故事的背景是這樣,該業(yè)務部門招了一個技術(shù)挺不錯的小伙子小張,由于小張技術(shù)能力在該部門比較突出,在入職不久后,他便成為這個部門某個項目組的team leader,同時也擁有review 該項目的權(quán)利。(注: 該項目為微服務項目),在某次小張review項目的時候,他發(fā)現(xiàn)好幾個項目,發(fā)現(xiàn)代碼有很多重復,于是他就動了把這些重復代碼封裝成starter的念頭,然后也是因為這次的封裝,帶來一次線上事故。下面就以代碼示例的形式,模擬這次事故

代碼示例

注: 本文僅模擬出現(xiàn)事故的代碼片段,不涉及業(yè)務

1、模擬小張的封裝的starter

@Slf4j
public class HelloSevice {
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    public HelloSevice(ThreadPoolTaskExecutor threadPoolTaskExecutor){
        this.threadPoolTaskExecutor = threadPoolTaskExecutor;
    }
    public String sayHello(String username){
        threadPoolTaskExecutor.execute(()->{
            log.info("hello: {} ",username);
        });
        return " hello : " + username;
    }
}
@Configuration
public class HelloServiceAutoConfiguration {
    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(2);
        threadPoolTaskExecutor.setMaxPoolSize(4);
        threadPoolTaskExecutor.setQueueCapacity(1);
        threadPoolTaskExecutor.setThreadFactory(new ThreadFactory() {
            private AtomicInteger atomicInteger = new AtomicInteger();
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("hello-pool-" + atomicInteger.getAndIncrement());
                return thread;
            }
        });
        return threadPoolTaskExecutor;
    }
    @Bean
    public HelloSevice helloSevice(ThreadPoolTaskExecutor threadPoolTaskExecutor){
        return new HelloSevice(threadPoolTaskExecutor);
    }
}

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.github.lybgeek.thirdparty.autoconfigure.HelloServiceAutoConfiguration

 2、模擬有引用小張封裝的starter的微服務項目

因為這些微服務中有一些耗時的任務,因此使用了spring的異步。示例如下

@Configuration
public class ThreadPoolConfig {
    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(2);
        threadPoolTaskExecutor.setMaxPoolSize(5);
        threadPoolTaskExecutor.setQueueCapacity(10);
        threadPoolTaskExecutor.setThreadFactory(new ThreadFactory() {
            private AtomicInteger atomicInteger = new AtomicInteger();
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("echo-pool-" + atomicInteger.getAndIncrement());
                return thread;
            }
        });
        threadPoolTaskExecutor.setRejectedExecutionHandler((r, executor) -> System.err.println("記錄日志。。。。"));
        return threadPoolTaskExecutor;
    }
}
@Service
@Slf4j
public class EchoService {
    @Async("threadPoolTaskExecutor")
    public void echo(String content){
        log.info("echo -> {} ",content);
        try {
            //模擬耗時操作
            TimeUnit.MINUTES.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 3、和本文有關(guān)系的配置內(nèi)容

spring:
  main:
    allow-bean-definition-overriding: true

 4、模擬調(diào)用耗時業(yè)務代碼塊示例

@Component
public class BeanCommandRunner implements CommandLineRunner {
    @Autowired
    private EchoService echoService;
    @Override
    public void run(String... args) throws Exception {
        for (int i = 0; i < 6; i++) {
            echoService.echo("content:" + i);
        }
    }
}

相關(guān)的代碼如上述內(nèi)容

大家可以思考一下上面的示例有沒有什么問題

我們啟動一下程序,觀察一下控制臺

報了一個線程池拒絕異常,而且通過這個異常信息,我們發(fā)現(xiàn)這個線程池走是小張封裝線程池,而非業(yè)務自己定義的線程池。這明顯是不正常的,正常的邏輯是業(yè)務代碼優(yōu)先級需比公共代碼優(yōu)先高才合理

那如何解決呢?

僅需利用springboot的條件注解即可,在小張封裝的starter下做如下改動

@Bean
    @ConditionalOnMissingBean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(2);
        threadPoolTaskExecutor.setMaxPoolSize(4);
        threadPoolTaskExecutor.setQueueCapacity(1);
        threadPoolTaskExecutor.setThreadFactory(new ThreadFactory() {
            private AtomicInteger atomicInteger = new AtomicInteger();
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("hello-pool-" + atomicInteger.getAndIncrement());
                return thread;
            }
        });
        return threadPoolTaskExecutor;
    }

修改后,我們在啟動一下程序,觀察控制臺

此時走就是業(yè)務自定義的線程池了

為什么加了一個 @ConditionalOnMissingBean就可以了

這就得從springboot的自動裝配說起了,springboot的自動裝配類繼承了org.springframework.context.annotation.DeferredImportSelector,這個接口具有懶加載的功能,當項目啟動后,先加載業(yè)務自定義的bean,再來加載starter的bean,當我們項目中沒有配置

spring:
  main:
    allow-bean-definition-overriding: true

時,項目啟動就會直接報類似如下異常

當時他們業(yè)務項目因為他們feign沒有指定contextId,導致報了上述的異常,業(yè)務開發(fā)為了省事就直接把
allow-bean-definition-overriding設置成true,這也為后續(xù)小張自定義的starter引發(fā)的事故埋下了很好的根基。那我們再切回主線,當spring發(fā)現(xiàn)有兩個一樣的bean,且發(fā)現(xiàn)allow-bean-definition-overriding為true,后面加載的bean會把前面加載的bean覆蓋掉,這也是為啥小張starter的bean會生效。

當我們在starter上的bean上加載 @ConditionalOnMissingBean后,因為業(yè)務項目的bean已經(jīng)存在了,starter的bean就不會加載進spring容器了。

我們從技術(shù)維度說明了解決方案,我們再從非技術(shù)的角度上復盤一下這次事故

復盤

不知道會不會有朋友說,你說那么多,不就加一個@ConditionalOnMissingBean就能解決這個問題,下次注意就好了啊。但據(jù)業(yè)務技術(shù)人反饋當時他們排查了挺久,因為他們業(yè)務項目平時沒啥并發(fā)量,所以小張那個問題就被掩蓋住了,而有次他們業(yè)務搞了一個營銷活動,因為并發(fā)上去了,才把問題暴露出來。這側(cè)面也說明項目壓測的重要性,不能因為平時沒啥并發(fā),就掉以輕心

不懂大家的公司是否也有這樣的情況,在我們這邊,底下成員代碼只能merge request,只有team leader review后,再將代碼合并到主干,因為team leader擁有的權(quán)限比較大,他寫的代碼,只要他愿意,直接就能合并到主干了。這次也是因為小張直接將他寫的代碼推到主干發(fā)布,釀成事故。后面我們這邊提出了一個方法,就是team leader的代碼要由更高級的leader進行走查,但是這個方法我是感覺也不是很好,因為有不少項目組的team leader的老板基本上已經(jīng)脫離一線,不敲代碼了,也不懂能不能行。

其次因為小張入職不久,對業(yè)務其實沒有完全吃透,因為看到重復的代碼,出于技術(shù)潔癖,就想去改,出發(fā)點是好的,但有句話技術(shù)是為業(yè)務服務,業(yè)務都沒搞懂,就去動,有時候會帶來意想不到的風險

總結(jié)

對自己的不熟悉的項目或者開發(fā)公共組件,深思熟慮再動手是很重要的

以上就是自定義starter引發(fā)的線上事故記錄復盤的詳細內(nèi)容,更多關(guān)于自定義starter線上事故的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java實現(xiàn)文件拷貝的七種方式

    java實現(xiàn)文件拷貝的七種方式

    這篇文章主要介紹了java實現(xiàn)文件拷貝的七種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • SpringBoo WebFlux+MongoDB實現(xiàn)非阻塞API過程

    SpringBoo WebFlux+MongoDB實現(xiàn)非阻塞API過程

    本文介紹了如何使用SpringBootWebFlux和MongoDB實現(xiàn)非阻塞API,通過響應式編程提高系統(tǒng)的吞吐量和響應性能,適用于高并發(fā)場景
    2025-12-12
  • Java獲取手機號碼歸屬地的實現(xiàn)

    Java獲取手機號碼歸屬地的實現(xiàn)

    這篇文章主要介紹了Java獲取手機號碼歸屬地的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • SpringBoot 二維碼生成base64并上傳OSS的實現(xiàn)示例

    SpringBoot 二維碼生成base64并上傳OSS的實現(xiàn)示例

    本文主要介紹了SpringBoot 二維碼生成base64并上傳OSS的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-05-05
  • Java的JSON格式轉(zhuǎn)換庫GSON的初步使用筆記

    Java的JSON格式轉(zhuǎn)換庫GSON的初步使用筆記

    GSON是Google開發(fā)并在在GitHub上開源的Java對象與JSON互轉(zhuǎn)功能類庫,在Android開發(fā)者中也大受歡迎,這里我們就來看一下Java的JSON格式轉(zhuǎn)換庫GSON的初步使用筆記:
    2016-06-06
  • SpringCloud的Hystrix簡單介紹

    SpringCloud的Hystrix簡單介紹

    這篇文章主要介紹了SpringCloud的Hystrix簡單介紹,SpringCloud Hystrix是Netflix開源的一款容錯框架,具備服務降級,服務熔斷,依賴隔離,監(jiān)控(Hystrix Dashboard)等功能,同樣具有自我保護能力,需要的朋友可以參考下
    2023-07-07
  • 解決Tomcat修改get提交請求亂碼問題

    解決Tomcat修改get提交請求亂碼問題

    這篇文章主要介紹了Tomcat修改get提交請求亂碼問題的解決方案,需要的朋友參考下
    2017-04-04
  • Mybatis模糊查詢之三種定義參數(shù)方法和聚合查詢、主鍵回填實現(xiàn)方法

    Mybatis模糊查詢之三種定義參數(shù)方法和聚合查詢、主鍵回填實現(xiàn)方法

    這篇文章主要介紹了Mybatis模糊查詢之三種定義參數(shù)方法和聚合查詢、主鍵回填實現(xiàn)方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03
  • 如何為Spring Cloud Gateway加上全局過濾器

    如何為Spring Cloud Gateway加上全局過濾器

    這篇文章主要介紹了如何為Spring Cloud Gateway加上全局過濾器,幫助大家更好得理解和學習使用Gateway,感興趣的朋友可以了解下
    2021-03-03
  • 監(jiān)控Spring Boot 項目運行情況操作方法

    監(jiān)控Spring Boot 項目運行情況操作方法

    在實際開發(fā)中,經(jīng)常會遇到想要獲取到服務器應用的運行情況的場景,在微服務架構(gòu)下對于每個應用運行情況的監(jiān)控是保證系統(tǒng)高可用的關(guān)鍵,本文給大家介紹如何實現(xiàn)在Spring Boot的jar包中對系統(tǒng)的運行情況進行監(jiān)控操作,感興趣的朋友跟隨小編一起看看吧
    2024-08-08

最新評論

新郑市| 新巴尔虎右旗| 苗栗市| 台前县| 宁海县| 邮箱| 固原市| 祁连县| 湖南省| 即墨市| 阳原县| 巴里| 福鼎市| 凭祥市| 株洲县| 宣威市| 江油市| 合阳县| 大石桥市| 保德县| 丹凤县| 赤峰市| 余庆县| 汶上县| 巴中市| 成武县| 乃东县| 嘉善县| 西林县| 阿克苏市| 方山县| 龙岩市| 许昌市| 淮安市| 黄陵县| 格尔木市| 纳雍县| 禹城市| 谷城县| 韶关市| 石首市|