Nacos 企業級落地實踐

前言

在高速發展的時候,公司規模越來越大,老師人數越來越多,這時候公司不能鋪太多人去做運營與服務,必須提高每個人效,這就需要技術驅動。因此掌門教育轉變成一家技術驅動型的公司,如果被迫成爲一家靠資金驅動的公司就活不下去了。

——張翼(掌門教育創始人兼CEO)

掌門教育自2014年正式轉型在線教育以來,秉承“讓教育共享智能,讓學習高效快樂”的宗旨和願景,經歷雲計算、大數據、人工智能、 AR / VR / MR 以及現今最火的 5G ,一直堅持用科技賦能教育。掌門教育的業務近幾年得到了快速發展,特別是今年的疫情,使在線教育成爲了新的風口,也給掌門教育新的機遇。

隨着業務規模進一步擴大,流量進一步暴增,微服務數目進一步增長,使老的微服務體系所採用的註冊中心 Eureka 不堪重負,同時 Spring Cloud 體系已經演進到第二代,第一代的 Eureka 註冊中心已經不大適合現在的業務邏輯和規模,同時它目前被 Spring Cloud 官方置於維護模式,將不再向前發展。如何選擇一個更爲優秀和適用的註冊中心,這個課題就擺在了掌門人的面前。經過對 Alibaba Nacos 、HashiCorp Consul 等開源註冊中心做了深入的調研和比較,最終選定 Alibaba Nacos 做微服務體系 Solar 中的新註冊中心。

背景故事

掌門教育微服務面臨的挑戰

第一次生產事故

2020 年疫情爆發後的幾個月後,掌門教育的微服務實例數比去年猛增 40% ,基礎架構部樂觀的認爲註冊中心 Eureka 服務器可以抗住該數量級的實例數規模, Eureka 服務器在阿里雲 PROD 環境上執行三臺 8C16G 普通型機器三角結構型對等部署,運行了好幾年都一直很穩定,但災難還是在2020年3月某天晚上降臨,當天晚上大概 9 點 30 分左右,其中兩臺 Eureka 服務器無徵兆的 CPU 佔用迅速上升到100%,同時大量業務服務掉線,告警系統被觸發,釘釘機器人告警和郵件告警鋪天蓋地而來。基礎架構部和運維部緊急重啓 Eureka 服務器,但沒多久,CPU 依舊沒抗住,而且更加來勢兇猛,打開的文件描述符數瞬間達到 8000+ ,TCP 連接達到 1萬+ ,業務服務和 Eureka 服務器的通信產生大面積的 TCP CLOSE_WAIT 事件,且伴有大量 Broken pipe 異常。

org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe

運維人員嘗試把機器升級成增強型 8C16G ,折騰一番後,於 23:00 左右恢復正常。

第二次生產事故

微服務實例數依舊在增長, Eureka 服務器平穩運行了大概半個月後,災難又一次降臨,CPU 再次飆升到100%,過程就不表述了。處理方式,把機器升級成增強型 16C32G,並把 Eureka 服務器的版本升級到 Spring Cloud Hoxton 版,並優化了它的一些配置參數,爾後事件再也沒出現。

掌門教育新微服務演進思考

雖然 Eureka 服務器目前運行平穩,但我們依舊擔心此類事故在未來會再次發生,於是痛定思痛,經過深入的調研和比較一段時間後,通過由基礎架構部牽頭,各大業務線負責人和架構師參與的專項註冊中心架構評審會上,CTO 拍板,做出決議:選擇落地 Alibaba Nacos 作爲掌門教育的新註冊中心。

Talk is cheap,show me the solution。基礎架構部說幹就幹,Nacos 部署到 FAT 環境後,打頭陣的是測試組的同學,對 Nacos 做全方位的功能和性能測試,畢竟 Nacos 是阿里巴巴拳頭開源產品,迭代了2年多,在不少互聯網型和傳統型公司都已經落地,我們選擇了穩定的 1.2.1 版本,得出結論是功能穩定,性能上佳,關於功能和性能方面的相關數據,具體參考後續:《掌門教育微服務體系 Solar | 阿里巴巴 Nacos 企業級落地下篇》。

但是,如何遷移 Eureka 上的業務服務到 Nacos 上?業務服務實例數目衆多,遷移工作量巨大,需要全公司業務部門配合,同時 Eureka 對註冊的業務服務名大小寫不敏感,而 Nacos 對註冊的業務服務名大小寫敏感,那麼對於業務服務名不規範的業務部門需要改造。而對於基礎架構部來說, Nacos Eureka Sync 方案如同一座大山橫亙在我們面前,是首先需要邁過去的坎,縱觀整個過程,該方案選型還是折騰了一番,具體參考後續:《掌門教育微服務體系 Solar | 阿里巴巴 Nacos 企業級落地中篇》。

阿里巴巴 Nacos 企業級落地的優化代碼,在不久的將來會通過開源的方式回饋給業界。

官方介紹

Nacos 簡介

阿里巴巴中間件部門開發的新一代集服務註冊發現中心和配置中心爲一體的中間件。它是構建以“服務”爲中心的現代應用架構 (例如微服務範式、雲原生範式) 的服務基礎設施,支持幾乎所有主流類型的“服務”的發現、配置和管理,更敏捷和容易地構建、交付和管理微服務平臺。

Spring Cloud Alibaba 簡介

阿里巴巴中間件部門開發的 Spring Cloud 增強套件,致力於提供微服務開發的一站式解決方案。此項目包含開發分佈式應用微服務的必需組件,方便開發者通過 Spring Cloud 編程模型輕鬆使用這些組件來開發分佈式應用服務。依託 Spring Cloud Alibaba ,您只需要添加一些註解和少量配置,就可以將 Spring Cloud 應用接入阿里微服務解決方案,通過阿里中間件來迅速搭建分佈式應用系統。

摘自官網 Spring Cloud Alibaba Introduction:

https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/introduction.adoc

關於 Nacos 和 Spring Cloud Alibaba 如何使用,它的技術實現原理怎樣等,官方文檔或者民間博客、公衆號文章等可以提供非常詳盡且有價值的材料,這些不在本文的討論範圍內,就不一一贅述。筆者嘗試結合掌門教育現有的技術棧以及中間件一體化的戰略,並着眼於強大的 Nacos 和 Spring Cloud Alibaba 技術生態圈展開闡釋。

Nacos 開發篇

Nacos Server 落地

Nacos Server

  • Nacos Server 環境和域名

    掌門的應用環境分爲 4 套,DEV | FAT | UAT | PROD 分別對應開發、測試、準生產環境、生產環境,因此 Nacos Server 也分爲 4 套獨立環境。除了 DEV 環境是單機部署外,其他是集羣方式部署。對外均以域名方式訪問,包括 SDK 方式連接 Nacos Server 和訪問 Nacos Server Dashboard 控制檯頁面。

  • Nacos Server 環境隔離和調用隔離

    Nacos Server 可以創建不同的命名空間,做到同一個應用環境的基礎上更細粒度的劃分,隔離服務註冊和發現。在某些場景下,開發本地有需要連接測試環境的 Nacos Server ,但其他測試服務不能調用到開發本地,這時候可以將 NacosDiscoveryProperties 的 enabled 屬性設置爲 false 。

  • Nacos Server 集成 Ldap

    Nacos Server Dashboard 集成公司的 Ldap 服務,並在用戶首次登錄時記錄用戶信息。

Nacos Server 界面

  • Nacos 界面權限

    Nacos Server Dashboard 用戶首次登陸時,默認分配普通用戶(即非 ROLE_ADMIN )角色,對查詢以外的按鈕均無操作權限,以免出現誤操作導致服務非正常上下線。

  • Nacos 界面顯示服務概覽

    Nacos Server Dashboard 頁面增加服務總數及實例總數的統計,該信息每 5 秒刷新一次。

Nacos 監控

Nacos Server 監控
  • 標準監控

    基於公司現有的 Prometheus 、 Grafana 、 AlertManager 從系統層監控 Nacos。

  • 高級監控

    根據 Nacos 監控手冊,結合 Prometheus 和 Grafana 監控 Nacos 指標。

  • Nacos Eureka Sync Etcd 監控

    從如下界面可以監控到,業務服務列表是否在同步服務的集羣上呈現一致性 Hash 均衡分佈。

Nacos 日誌

  • 日誌合併及 JSON 格式化

    將 Nacos 多模塊的日誌統一按 info 、 warn、error 級別合併,定義 schema 字段標記不同模塊,按 JSON 格式滾動輸出到文件,供 ELK 採集展示。

Nacos 告警

Nacos Server 告警
  • 業務服務上下線的告警

    業務服務上下線的告警 業務服務灰度藍綠的告警
  • Nacos Eureka Sync 告警

    待同步的業務服務列表服務增加的告警 待同步的業務服務列表服務刪除的告警
  • 服務名大寫告警

    釘釘機器人上的告警 掌控 APP 上的告警
  • 業務服務同步完畢告警

    釘釘機器人上的告警

Nacos Client 落地

Solar Nacos SDK 環境初始化

應用接入 Solar Nacos SDK 在啓動時需要初始化完成 Nacos Server 的連接配置,即 spring.cloud.nacos.discovery.server-addr 參數的賦值。不同環境下連接的 Nacos Server ,因此需要讀取機器所在的 env 環境參數,來選擇相對應的 Nacos Server 地址。

初始化邏輯代碼如下:

public class NacosClientConfigApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
    private static final Logger logger = LoggerFactory.getLogger(NacosClientConfigApplicationContextInitializer.class);

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        try {
            Properties props = new Properties();

            String path = isOSWindows() ? CommonConstant.SERVER_PROPERTIES_WINDOWS : CommonConstant.SERVER_PROPERTIES_LINUX;
            File file = new File(path);
            if (file.exists() && file.canRead()) {
                FileInputStream fis = new FileInputStream(file);
                if (fis != null) {
                    try {
                        props.load(new InputStreamReader(fis, Charset.defaultCharset()));
                    } finally {
                        fis.close();
                    }
                }
            }

            String env = System.getProperty("env");
            if (!isBlank(env)) {
                env = env.trim().toLowerCase();
            } else {
                env = System.getenv("ENV");
                if (!isBlank(env)) {
                    env = env.trim().toLowerCase();
                } else {
                    env = props.getProperty("env");
                    if (!isBlank(env)) {
                        env = env.trim();
                    } else {
                        env = NacosEnv.DEV.getCode();
                    }
                }
            }

            String serverAddr = NacosEnv.getValueByCode(env);
            Map<String, Object> nacosClientPropertySource = new HashMap<>();
            nacosClientPropertySource.put(CommonConstant.NACOS_DISCOVERY_SERVER_ADDR, serverAddr);

            applicationContext.getEnvironment().getPropertySources().addLast(new MapPropertySource("solarNacosClientPropertySource", nacosClientPropertySource));
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

    private boolean isOSWindows() {
        String osName = System.getProperty("os.name");
        return !isBlank(osName) && osName.startsWith("Windows");
    }

    private boolean isBlank(String str) {
        return Strings.nullToEmpty(str).trim().isEmpty();
    }
}

Solar Nacos 藍綠灰度發佈和子環境隔離

在 Nacos 和 Eureka 雙註冊中心過渡狀態下, Solar SDK 支持跨註冊中心調用的藍綠灰度發佈和子環境功能。下面的圖片,只以 Eureka 爲例:

我們只需要把 Eureka SDK 換到 Nacos SDK 即可,實現如下功能:

  • Solar 藍綠灰度發佈
    • 版本匹配灰度發佈
    • 版本權重灰度發佈
  • Solar 多區域路由
    • 區域匹配灰度路由
    • 區域權重灰度路由
  • Solar 子環境隔離
    • 環境隔離
    • 環境路由
  • Solar 版本號和區域值,子環境號策略
    • DEV 環境,Git 插件自動創建灰度版本號
    • DevOps 環境設置

Solar 藍綠灰度發佈架構圖

Solar 基於版本維度的藍綠灰度發佈架構圖:

Solar 子環境隔離架構圖:

更多功能參考:

掌門1對1微服務體系Solar第1彈:全鏈路灰度藍綠髮布智能化實踐,掌門教育已經實現通過灰度藍綠髮布方式,實現對流量的精確制導和調撥。

Nepxion Discovery 開源社區:

https://github.com/Nepxion/Discovery

Solar Nacos 集成 Sentinel

Solar Nacos 集成灰度藍綠埋點到 Skywalking

Solar Nacos 集成 Sentinel 埋點到 Skywalking

  • 微服務上的 Sentinel 埋點

  • 網關上的 Sentinel 埋點

Solar Nacos 集成 DevOps 發佈平臺

  • 集成攜程 VI Cornerstone 實現服務拉入拉出

    Solar Nacos SDK 的服務,在應用發佈時需要做服務的拉入拉出,目的是爲了發佈時流量無損。掌門使用 VI Cornerstone 實現拉入拉出功能。具體實現是在初始化 NacosDiscoveryProperties 對象時設置 instance.enabled 屬性值爲 false,在服務完全初始化後,通過發佈系統調用 Solar Nacos SDK 的 API 接口再修改爲 true 來被外部發現並提供服務。

    public class NacosApplicationContextInitializer implements EnvironmentPostProcessor {
        @Override
        public void postProcessEnvironment(ConfigurableEnvironment configurableEnvironment, SpringApplication springApplication) {
            Boolean bootstrapEnabled = configurableEnvironment.getProperty("devops.enabled", Boolean.class, false);
            if (bootstrapEnabled) {
                Properties properties = new Properties();
                properties.put("spring.cloud.nacos.discovery.instanceEnabled", "false");
                PropertiesPropertySource propertiesPropertySource = new PropertiesPropertySource("devopsEnabledNacosDiscoveryProperties", properties);
                MutablePropertySources mutablePropertySources = configurableEnvironment.getPropertySources();
                mutablePropertySources.addFirst(propertiesPropertySource);
            }
        }
    }
    

    spring.factories 配置文件:

    org.springframework.boot.env.EnvironmentPostProcessor=\
    com.ctrip.framework.cs.spring.NacosApplicationContextInitializer
    

Solar Nacos SDK 接入

Solar 版本定義
  • Solar 2.3.x & 1.3.x,基於 Nacos SDK
  • Solar 2.2.x & 1.2.x,基於 Eureka SDK
Solar 版本關係
  • Solar 版本與 Spring Boot 技術棧的關係

    框架版本 Spring Cloud版本 Spring Boot版本 Spring Cloud Alibaba版本
    2.x.x Greenwich 2.1.x.RELEASE 2.1.x.RELEASE
    1.x.x Edgware 1.5.x.RELEASE 1.5.x.RELEASE
  • Solar 版本與註冊中心的關係

    框架版本 支持的註冊中心 支持的Cornerstone(VI)版本
    1.0.x ~ 1.2.x Eureka <= 0.2.4
    >= 1.3.x Nacos >= 1.0.0
    2.0.x ~ 2.2.x Eureka <= 0.2.4
    >= 2.3.x Nacos >= 1.0.0
Solar SDK 接入:
  • 設置 Parent

    <parent>
        <groupId>com.zhangmen</groupId>
        <artifactId>solar-parent</artifactId>
        <version>${solar.version}</version>
    </parent>
    
  • 添加到 pom.xml

    只需引入一個 Jar 包,對接成本極低,只做基本組件封裝,非常輕量級。

    微服務

    <dependency>
        <groupId>com.zhangmen</groupId>
        <artifactId>solar-framework-starter-service</artifactId>
        <version>${solar.version}</version>
    </dependency>
    

    網關

    <dependency>
        <groupId>com.zhangmen</groupId>
        <artifactId>solar-framework-starter-zuul</artifactId>
        <version>${solar.version}</version>
    </dependency>
    
  • 入口類添加註解

    @EnableSolarService , @EnableSolarZuul 封裝了標準 Spring Boot / Spring Cloud / Apollo 等大量註解,降低業務的使用成本。

    微服務

    @EnableSolarService
    public class DemoApplication {
        public static void main(String[] args) {
            new SpringApplicationBuilder(DemoApplication.class).run(args);
        }
    }
    

    網關

    @EnableSolarZuul
    public class DemoApplication {
        public static void main(String[] args) {
            new SpringApplicationBuilder(DemoApplication.class).run(args);
        }
    }
    

Solar Nacos SDK 和 Solar Eureka SDK 升級和回滾

升級和回滾方案非常簡單,此方式同時適用於網關和服務,見下圖:

作者介紹

吳毅挺 ,掌門技術副總裁,負責技術中臺和少兒技術團隊。曾就職於百度、eBay 、攜程,曾任攜程高級研發總監,負責從零打造攜程私有云、容器雲、桌面雲和 PaaS 平臺。

任浩軍 ,掌門基礎架構部負責人。曾就職於平安銀行、萬達、惠普,曾負責平安銀行平臺架構部PaaS 平臺 Halo 基礎服務框架研發。10 多年開源經歷,Github ID:@HaojunRen,Nepxion 開源社區創始人,Nacos Group Member,Spring Cloud Alibaba & Nacos & Sentinel& OpenTracing Committer。

本文轉載自公衆號阿里巴巴中間件(ID:Aliware_2018)。

原文鏈接

https://mp.weixin.qq.com/s?__biz=MzU4NzU0MDIzOQ==&mid=2247490123&idx=1&sn=10d7cd89bf43f07152513718c08dd80c&chksm=fdeb282bca9ca13d2ffb2128c2b5e1acfa5743c0cf835e266835cd5e0233bef5adbca896c8bd&scene=27#wechat_redirect

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章