主頁 > 軟體設計 > SpringCloudAlibaba的學習筆記

SpringCloudAlibaba的學習筆記

2021-02-18 10:21:59 軟體設計

SpringCloudAlibaba學習

Nacos學習

Naming Configuration 前兩個字母, Service

是什么?

  • 一個更易于構建云原生應用的動態服務發現,配置管理和服務管理中心
  • Dynamic Naming and Configuration Service
  • Nacos就是注冊中心+配置中心的組合 Eureka+Config+Bus

能干嗎?

  • 替代Eureka做服務注冊中心
  • 替代Config做服務配置中心

去哪下?

  • https://github.com/alibaba/Nacos
  • https://nacos.io/zh-cn/docs/

各種注冊中心比較

服務注冊與發現框架CAP模型控制臺管理社區活躍度
EurekaAP支持
ZookeeperCP不支持
ConsulCP支持
NacosAPyeshigh

安裝并允許Nacos

  • 本地Jdk 8 + Maven環境
  • 從官網去下載 https://github.com/alibaba/Nacos
  • 在windows環境下,解壓安裝包,直接允許bin目錄下的 startup.cmd
  • 運行成功之后直接訪問 http://localhost:8848/nacos 就可以看到

基于Nacos的服務提供者

  • 新建一個專案,由于這個是一個微服務,所以我們可以創建一個父專案來進行統一的版本管理
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu</groupId>
    <artifactId>cloud2021</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>cloudalibaba-provider-payment9001</module>
        <module>cloudalibaba-provider-payment9002</module>
        <module>cloudalibaba-consumer-nacos-order83</module>
        <module>cloudalibaba-config-nacos-client3377</module>
    </modules>
    <!--統一管理jar包和版本-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>8.0.18</mysql.version>
        <druid.verison>1.1.16</druid.verison>
        <mybatis.spring.boot.verison>1.3.0</mybatis.spring.boot.verison>
    </properties>
    <!--子模塊繼承之后,提供作用:鎖定版本+子module不用寫groupId和version-->
    <dependencyManagement>
        <dependencies>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud alibaba 2.1.0.RELEASE-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- MySql -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <!-- Druid -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.verison}</version>
            </dependency>
            <!-- mybatis-springboot整合 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.verison}</version>
            </dependency>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <!-- log4j -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  • 需要匯入nacos的包,宣告一下可以被發現
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
    </dependencies>
  • 需要寫組態檔,宣告這是一個需要被管理的服務,需要被哪個地址進行管理,需要被管理哪些東西
server:
  port: 9001

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'
  • 主啟動類也要使用注解宣告一下,這個服務可以作為一個客戶端被Nacos發現
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain9001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9001.class, args);
    }
}
  • 業務類我們可以寫一個方法進行測驗,將本機的埠暴露出去
@RestController
public class PaymentController
{
    @Value("${server.port}")
    private String serverPort;

    @GetMapping(value = "/payment/nacos/{id}")
    public String getPayment(@PathVariable("id") Integer id)
    {
        return "nacos registry, serverPort: "+ serverPort+"\t id"+id;
    }
}
  • 啟動這個服務提供者,發現nacos控制臺可以看到,安裝同樣的方式,我們再來一個9002的服務提供者,它們的服務名字都一樣,但是埠卻不一樣,也就是說這是兩個埠,這兩個埠都可以提供同一個服務,
  • 接下來是服務消費者
    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
  • 組態檔
server:
  port: 83
spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
service-url:
  nacos-user-service: http://nacos-payment-provider
  • 這個主啟動類和提供者差不多
@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain83 {
    public static void main(String[] args) {
        SpringApplication.run(OrderNacosMain83.class, args);
    }
}
  • 在服務呼叫者這里,我們可以使用一個模板進行呼叫,這個模板去呼叫提供者的方法,首先它們應該知道提供者的服務名稱,然后還有它們的埠,自己需要準備引數,這些我們都可以獲取到,我們還需要得到回傳值,
  • 由于提供者有很多個,我們需要確定到底使用的是哪一個,這也是一個問題,這個時候需要使用到負載均衡策略,
@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
  • 往容器中注入的這個Bean上面又宣告了LoadBalanced注解,這表明我們的RestTemplate使用了一種負載均衡策略
  • 然后我們在消費者端就可以輪流呼叫提供者提供的服務了
@RestController
@Slf4j
public class OrderNacosController {
    @Resource
    private RestTemplate restTemplate;

    @Value("${service-url.nacos-user-service}")
    private String serverURL;

    @GetMapping(value = "/consumer/payment/nacos/{id}")
    public String paymentInfo(@PathVariable("id") Long id) {
        return restTemplate.getForObject(serverURL + "/payment/nacos/" + id, String.class);
    }
}
  • Nacos 其實是可以支持CP或者AP的,這兩者之間可以相互切換
    • C是所有節點在同一時間看到的資料是一致的,而A的定義是所有的請求都會收到回應
    • 如果不需要存盤服務級別的資訊且服務實體是通過nacos-client注冊,并能夠保持心跳上報,那么就可以選擇AP默認當前主流的服務如SPring Cloud和Dubbo服務,都適合用于AP模式,AP模式為了服務的可能性而減弱了一致性,因此AP模式下只支持注冊臨時實體
    • 如果需要在服務級別撰寫或存盤配置資訊,那么CP是必須的, k8s和DNS服務則適用于CP模式
    • CP模式下支持注冊持久化實體,此時則是以Raft協議為集群運行模式該模式下注冊實體之前需先注冊服務,如果服務不存在,則會回傳錯誤
    • curl -X PUT ‘$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP’

Nacos作為服務配置中心

我們可以在Nacos上搭建自己的組態檔,在自己的服務中宣告自己想要使用哪個即可

  • 依賴引入
    <dependencies>
        <!--nacos-config-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--web + actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--一般基礎配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
  • 組態檔需要配置兩個
    • 為什么需要兩個呢?
    • Nacos 和SpringCloud-config一樣,在專案初始化時,需要先去配置中心進行配置拉取,然后才能保證專案的正常啟動
    • 組態檔的加載存在優先順序, bootstrap優先級高于application
  • 在遠程配置的組態檔的命名格式都需要遵循一定的規則,要不然時無法獲取到的
server:
  port: 3377

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #服務注冊中心地址
      config:
        server-addr: localhost:8848 #配置中心地址
        file-extension: yaml #指定yaml格式的配置
 
# application.yaml
spring:
  profiles:
    active: dev

# ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
# nacos-config-client-dev.yml
  • 主啟動類無變化
@EnableDiscoveryClient
@SpringBootApplication
public class NacosConfigClientMain3377 {
    public static void main(String[] args) {
        SpringApplication.run(NacosConfigClientMain3377.class, args);
    }
}
  • 然后我們暴露一個埠,就可以看到在遠程組態檔上面的資訊,并且我們也可以設定自動重繪,這樣當遠程修改的時候,我們這個埠可以立即看到
@RestController
@RefreshScope
public class ConfigClientController {
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/config/info")
    public String getConfigInfo() {
        return configInfo;
    }
}
  • 主要有以下一些方面可以可以更換組態檔,
    • spring.application.name 專案的名稱
    • spring.profile.active 專案的環境,一般有dev test等
    • spring.cloud.nacos.config.file-extension 專案的擴展檔案名
    • 此外,還有group,namespace等
server:
  port: 3377

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #服務注冊中心地址
      config:
        server-addr: localhost:8848 #配置中心地址
        file-extension: yaml #指定yaml格式的配
        group: TEST_GROUP
        namespace: 76fce2f9-7d68-4729-a7d5-b6861295483d
# ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
# nacos-config-client-dev.yml
  • 以上的這些資訊可以唯一確定一個組態檔

Nacos持久化配置

這樣一個微服務專案的組態檔一般都比較重要,如果萬一掛掉了呢,所以我們需要非常謹慎的去處理配置資訊,Nacos默認自帶的嵌入式資料庫,derby,

  • 我們也可以使用MySQL對組態檔進行持久化
  • 在config組態檔下有sql腳本,專門建立組態檔的資料表資訊,
  • 修改application.properties ,咋i最后面加上一些資訊
spring.datasource.platform=mysql

db.num=1
db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=123456
  • 下次就可以去mysql資料庫里面找回應的訊息了,
  • 如果要做持久化,我們僅僅需要一個mysql可能還不夠,我們還需要高可用,把Nacos做一個集群,一個掛了另外一個可以頂上,它們共同使用一個mysql或者一個mysql的集群,
  • 我們模擬一下使用場景, 1個Nginx,+3個Nacos注冊中心 + 1個Mysql
  • 我們先確定3臺Nacos機器的不同服務埠號
  • 然后修改cluster.conf, 上面列出這個集群中所有的Nacos機器,
  • 再撰寫 Nacos的啟動腳本 startup.sh ,使我們可以以不同的埠啟動
  • 修改內容有些亂七八糟的,這里就不想再羅列出來了,等會兒說一個更加合適的方法
  • 另外我們的nginx也需要進行配置一下,然后暴露出來一個埠,監聽集群里面的埠,然后負載均衡的分配給這些埠里面某一個確定的埠
upstream cluster{                                                        
 
    server 127.0.0.1:3333;
    server 127.0.0.1:4444;
    server 127.0.0.1:5555;
}
server{
                          
    listen 1111;
    server_name localhost;
    location /{
         proxy_pass http://cluster;
                                                        
    }
  • 啟動nginx和我們的集群里面的埠即可
  • 我們在客戶端修改一下服務器的ip,修改為我們nginx暴露出來的埠即可
  • 或者我們復制三個nacos,然后它們的cluster.xml 都是一樣的,然后再把各自的埠修改一下,全部啟動即可

Sentinel學習

Sentinel 主要提供 流量控制,熔斷降級,系統負載保護,
可以理解為和Hystrix 的功能一致,但是這個比較優秀的是它可以 進行配置,
我們都知道,一般都是約定大于配置,配置大于編碼,這就是它比較優秀的地方,可以再很多場景下面進行詳細的配置

  • 服務使用中的各種問題:
    • 服務雪崩
    • 服務降級
    • 服務熔斷
    • 服務限流
  • Sentinel分為兩個部分
    • 核心庫,不依賴任何框架庫,能夠運行于所有Java運行環境,同時對Dubbo、 SpringCloudd等框架也有比較好的支持
    • 控制臺,基于SpringBoot開發,打包后可以直接運行,不需要web服務器
    • 我們去官網上面下載jar包,就可以使用java命令進行運行了,不過運行時需要注意,確保jdk8,8080埠不能被占用,然后就可以訪問了
  • 假設現在nacos和sentinel都已經啟動了,現在我們每創建一個微服務里面的介面都需要被監控到,
  • 需要做如下配置,我們現在創建一個8401埠的服務,看一下具體情況,

pom

    <dependencies>
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

組態檔

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719  #默認8719,假如被占用了會自動從8719開始依次+1掃描,直至找到未被占用的埠

management:
  endpoints:
    web:
      exposure:
        include: '*'

主啟動類

@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401 {
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class, args);
    }
}

然后我們建立一個測驗的介面類進行測驗

@Slf4j
@RestController
public class FlowLimitController {
    @GetMapping("/testA")
    public String testA() {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB() {
        return "------testB";
    }

    @GetMapping("/testD")
    public String testD() {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("testD 測驗");
        return "------testD";
    }
}
  • 由于Sentinel采用的懶加載的模式,我們需要被管理的介面除了再組態檔上宣告過以外,還需要自己訪問一次才可以進行管理,這樣也是為了節省資源吧

![image.png](https://img-blog.csdnimg.cn/img_convert/a1700064b92d1d9dc33dee3611457010.png#align=left&display=inline&height=309&margin=[object Object]&name=image.png&originHeight=617&originWidth=854&size=46650&status=done&style=none&width=427)

流控模式的詳細資訊

  • 資源名,也就是相當于我們訪問的介面的名字
  • 針對來源:sentinel可以針對呼叫者進行限流,填寫微服務名字,默認是default,不區分來源
  • 閾值型別 :
    • QPS 每秒鐘請求數量,當呼叫該api的QPS到達閾值的時候就會進行限流
    • 執行緒數:當呼叫該api的執行緒數到達閾值的時候,進行限流
    • 這兩個怎么區分呢, 一個主機可以有很多個執行緒,這些執行緒可以同時呼叫一個api,QPS相當于在外部進行攔截,執行緒數相當于在系統的內部進行攔截
    • 是否集群:現在先不考慮集群
  • 流控模式:
    • 直接:api達到限流條件時,直接限流
    • 關聯:當關聯的資源達到閾值時,會限流自己
    • 鏈路:只記錄指定鏈路上的流量
  • 流控效果
    • 直接:直接失敗,拋出例外
    • 預熱:閾值除以 cold Factor(默認為3),經過預熱時長后才會達到閾值,默認每秒鐘可以接收3個請求,逐步增加,經過預熱時長之后,逐步升至設定的QPS閾值
    • 預熱比較適合的應用場景時在秒殺系統開啟的瞬間,會有很多流量上來,很有可能把系統打死,預熱方式就是為了保護系統,慢慢的把流量放進來,慢慢把閾值增長到設定的閾值
    • 排隊等待:讓請求以均勻1的速度通過,對應的是漏桶演算法,該方式主要用于處理間隔性突發的流量,例如訊息佇列,,在某一秒有大量的請求到來,而接下來幾秒則處于空閑狀態,我們希望系統能夠在接下來的空閑時間逐漸處理這些請求,而不是一下子拒絕掉


![image.png](https://img-blog.csdnimg.cn/img_convert/86fb1faf43292b54c4a0cad630dabab1.png#align=left&display=inline&height=194&margin=[object Object]&name=image.png&originHeight=387&originWidth=848&size=26806&status=done&style=none&width=424)

降級規則

  • 降級策略 RT 平均回應時間,超出閾值,且在時間視窗內通過的請求大于5同時滿足時觸發
  • 例外比例: QPS大于5 且例外比例(秒級統計) 超過閾值,觸發降級,時間視窗結束后關閉降級
  • 例外數,例外數超過閾值(分鐘統計) 觸發降級,時間視窗結束后,關閉降級
  • 我們在學習Hystrix的時候,知道它時是有一個半開的狀態的,半開的狀態系統自動去檢車是否請求有例外,沒有例外就關閉斷路器恢復使用,有例外則繼續打開斷路器不可以用,但是這里是沒有半開這個狀態的

![image.png](https://img-blog.csdnimg.cn/img_convert/f363c93b765bbcdd4e934436564378c5.png#align=left&display=inline&height=382&margin=[object Object]&name=image.png&originHeight=764&originWidth=854&size=61889&status=done&style=none&width=427)

熱點引數限流

  • 熱點,就是我們經常訪問的資料,很多時候我們希望統計某一個熱點資料中訪問頻次最高的資料,并對其訪問進行限制,
  • 熱點引數限流會統計傳入引數中的熱點引數,并根據配置的限流閾值與模式,對包含熱點引數的資源呼叫進行限流,熱點引數限流可以看作是一種特殊的流量控制,僅對包含熱點引數的資源呼叫生效
  • Sentinel利用LRU策略統計最佳最常訪問的熱點引數,結合令牌桶演算法來進行引數級別的流量防控,熱點引數限流支持集群模式
    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2) {
        //int age = 10/0;
        return "------testHotKey";
    }
  1. 我們這樣寫我們的介面,然后配置熱點規則,當第一個引數的QPS超過1的時候就會進行報錯,這個時候如果還是要繼續訪問就會回傳錯誤頁面,這個錯誤頁面看著很不美觀,我們也可以自己設定
    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2) {
        //int age = 10/0;
        return "------testHotKey";
    }

    //兜底方法
    public String deal_testHotKey (String p1, String p2, BlockException exception){
        return "------deal_testHotKey,o(╥﹏╥)o";
    }
  1. 這個時候如果訪問的頻率違背了我們定義的熱點規則,就會按照我們自定義的兜底方法來進行處理
  2. 但是如果我們不違背自己在Sentinel上面定義的熱點規則,那么就什么事情也沒有
  3. 我們定義的熱點規則還可以支持高級配置,在原本的規則基礎上,當引數型別和引數值確定了,再使用另外一套規則,使用不同的限流閾值
  4. 熱點引數需要注意:引數型別必須是基本型別或者String
  5. @SentinelResource(value = “testHotKey”,blockHandler = “deal_testHotKey”) 這個處理的是Sentinel控制臺配置違規的情況,有blockHandler方法配置的兜底方法,但是如果是方法內部運行時例外是無法控制的

系統規則

![image.png](https://img-blog.csdnimg.cn/img_convert/c0c591ca8af2f4e7c4e27521216094aa.png#align=left&display=inline&height=222&margin=[object Object]&name=image.png&originHeight=296&originWidth=835&size=21749&status=done&style=none&width=626)

Sentinel 系統自適應限流從整體維度對應用入口流量進行控制,結合應用的 Load、CPU 使用率、總體平均 RT、入口 QPS 和并發執行緒數等幾個維度的監控指標,通過自適應的流控策略,讓系統的入口流量和系統的負載達到一個平衡,讓系統盡可能跑在最大吞吐量的同時保證系統整體的穩定性,

  • 系統規則是從應用基本的入口流量進行控制,從load ,CPU使用率, 平均RT,入口QPS,和并發執行緒數等幾個維度監控應用指標,讓系統盡可能跑在最大吞吐量的同時保證系統整體的穩定性
  • load是一個結果,如果根據load的情況來調節流量的通過率,那么就始終有延遲,也就意味著通過率的任何調整,都會過一段時間才能看到結果,當前通過率是使load惡化的一個動作,那么也至少要過1s之后才可以觀測到,同理,如果當前通過率調整時讓load好轉的當作,也需要1s之后才能繼續調整,這樣就浪費了系統的處理能力,所以我們看到的曲線,總是會有抖動
  • 總的來說,load不適合我們做及時的調整,,我們應該根據系統能夠處理的請求,和允許進來的請求,來做平衡,而不是根據一個間接的指標來 load 做限流,最終我們追求的目標是,在系統不被拖垮的情況下,提高系統的吞吐率,而不是load一定要低于某個閾值,
  • CPU usage 當系統CPU使用率超過閾值即觸發系統保護 ,比較靈敏
  • 平均RT:當單臺機器上所有入口流量的平均RT達到閾值即觸發系統保護,單位是毫秒
  • 并發執行緒數:所有入口流量的并發執行緒數達到閾值即觸發系統保護
  • 入口QPS:所有入口流量的QPS達到閾值即觸發系統保護

按資源名稱限流和按照Url地址進行限流

@GetMapping("/byResource")
    @SentinelResource(value = "byResource", blockHandler = "handleException")
    public CommonResult byResource() {
        return new CommonResult(200, "按資源名稱限流測驗OK", new Payment(2020, "serial001"));
    }
    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl()
    {
        return new CommonResult(200,"按url限流測驗OK",new Payment(2020,"serial002"));
    }

這兩個方式其實都一樣

自定義限流邏輯處理

原來的限流邏輯有一些缺點:

  1. 系統默認的,沒有體現我們的業務要求
  2. 依照現有的條件我們自定義處理方法和業務方法都在一個類里面,耦合度太高,不太好
  3. 每個業務方法都有一個兜底方法,不太合適
  4. 全域統一的處理方法沒有體現
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "handleException")
    public CommonResult byResource() {
        return new CommonResult(200, "按資源名稱限流測驗OK", new Payment(2020, "serial001"));
    }
public class CustomerBlockHandler {
    public static CommonResult handleException(BlockException e){
        return new CommonResult(2000,"客戶自定義限流處理資訊");
    }
}
  1. 按照上面的方法,我們就可以在一個統一的類里面寫一些靜態的方法,然后所有的兜底都在里面
  2. 需要注意的是,如果原來的方法有引數,那么兜底的方法也一定要有引數

Sentinel整合ribbon+openFeign+fallback

  • 創建兩個服務提供者專案,
  • 然后消費者專案創建,
@RestController
@Slf4j
public class CircleBreakerController {

    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;


    @RequestMapping("/consumer/fallback/{id}")
    //@SentinelResource(value = "fallback") //沒有配置
    //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只負責業務例外
    //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只負責sentinel控制臺配置違規
    @SentinelResource(value = "fallback",
            fallback = "handlerFallback",
            blockHandler = "blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult<Payment> fallback(@PathVariable Long id) {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);

        if (id == 4) {
            throw new IllegalArgumentException("IllegalArgumentException,非法引數例外....");
        } else if (result.getData() == null) {
            throw new NullPointerException("NullPointerException,該ID沒有對應記錄,空指標例外");
        }

        return result;
    }

    //fallback
    public CommonResult handlerFallback(@PathVariable Integer id, Throwable e) {
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(444, "兜底例外handlerFallback,exception內容  " + e.getMessage(), payment);
    }

    //blockHandler
    public CommonResult blockHandler(@PathVariable Integer id, BlockException blockException) {
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(445, "blockHandler-sentinel限流,無此流水: blockException  " + blockException.getMessage(), payment);
    }
}
  • 原理上是 fallback會管理服務內部出現例外的回執,被限流降級而拋出的例外只會進入blockHandler處理邏輯
  • 具體的套路就是我們訪問規則出錯,使用blockHandler里面的方法,訪問內部出錯,使用fallback里面的回執方法,如果一直訪問內部都出錯,那么就用 blockHandler的方法,因為它首先是違反了我們定義的訪問規則,然后再在內部出錯的
  • 我們之前學習過Feign,現在再來回顧一遍,順便將這個專案改造一下

在服務消費者引入feign

				<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

在組態檔上面開啟對feign的支持

#對Feign的支持
feign:
  sentinel:
    enabled: true

遠程呼叫,并宣告降級方法

@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService
{
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Integer id);
}

@Component
public class PaymentFallbackService implements PaymentService {
    @Override
    public CommonResult<Payment> paymentSQL(Integer id) {
        return new CommonResult<>(44444, "服務降級回傳,---PaymentFallbackService", new Payment(id, "errorSerial"));
    }
}

在主啟動類宣告啟用Feign遠程呼叫

@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class OrderNacosMain84 {
    public static void main(String[] args) {
        SpringApplication.run(OrderNacosMain84.class, args);
    }
}
  • 熔斷框架的比較
    | | Sentinel | Hystrix | resilience4j |
    | — | — | — | — |
    | 隔離策略 | 信號量隔離(并發執行緒數限流) | 執行緒池隔離/信號量隔離 | 信號量隔離 |
    | 熔斷降級策略 | 基于回應時間,例外比率,例外數 | 基于例外比率 | 基于例外比率,回應時間 |
    | 實時統計實作 | 滑動視窗 LeapArray | 滑動視窗,基于 RxJava | Ring Bit Buffer |
    | 動態規劃配置 | 支持多種資料源 | 支持多種資料源 | 有限支持 |
    | 擴展性 | 多個擴展點 | 插件的形式 | 的介面形式 |
    | 基于注解的支持 | 支持 | 支持 | 支持 |
    | 限流 | 基于QPS,支持基于呼叫關系的限流 | 有限的支持 | Rate Limiter |
    | 流量整形 | 支持預熱模式,勻速器模式,預熱排隊模式 | 不支持 | 簡單的Rate Limiter模式 |
    | 系統自適應保護 | 支持 | 不支持 | 不支持 |
    | 控制臺 | 提高開箱即用的控制臺,可配置規則,查看秒級監控,機器發現 | 簡單的監控查看 | 不提高控制臺,可對接其他監控系統 |

規則持久化

一旦我們重啟應用,Sentinel規則就會消失,生產環境需要將配置規則進行持久化,
可以將限流配置規則持久化進 Nacos 保存,只要重繪 8401 某個rest地址,sentinel控制臺的流控規則就能看到,只要Nacos里面的配置不洗掉,針對 8401 上 Sentinel上的 流控規則持續有效

  • 我們發現我們指定的規則在外面的服務停止之后再上來就沒有了,針對這種情況,外面可以將外面的配置作為一個組態檔存盤到nacos上面,而nacos外面前面已經學習過,它將資訊存盤到了資料庫里面,所以外面就相當于間接的把配置資訊存盤到了資料庫上面
  • 下次登錄就會發現以前配置過的規則
   			<dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

配檔案,需要宣告外面存盤到了哪個nacos宣告,存盤的格式,名字,組名,規則

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719  #默認8719,假如被占用了會自動從8719開始依次+1掃描,直至找到未被占用的埠
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

management:
  endpoints:
    web:
      exposure:
        include: '*'
      
      
spring:
   cloud:
    sentinel:
    datasource:
     ds1:
      nacos:
        server-addr:localhost:8848
        dataid:${spring.application.name}
        groupid:DEFAULT_GROUP
        data-type:json
            rule-type:flow     

外面配置過一個規則之后,配置的格式大致如此

[
    {
         "resource": "/retaLimit/byUrl",   
         "limitApp": "default",
         "grade":   1,
         "count":   1,
         "strategy": 0,
         "controlBehavior": 0,
         "clusterMode": false    
    }
]
resource: 資源名稱,可以看作是我們的介面什么的
limitApp: 來源應用
grade: 閾值型別,0表示執行緒數,1表示QPS
count: 單機閾值
strategy: 流控模式:0表示直接,1表示關聯,2表示鏈路
controlBehavior: 流控效果,0表示快速失敗,1表示預熱,2表示排隊
clusterMode: 表示是否集群

分布式事務問題

Seata是一款開源的分布式事務解決方案,致力于提供高性能和簡單易用的分布式事務服務,Seata將為用戶提供了AT,TCC,SAGA和XA事務模式

AT模式

  • 前提是基于本地ACID事務的關系型資料庫,Java應用,通過JDBC訪問資料庫
  • 通過兩個階段提交協議:
    • 一階段:業務資料和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源
    • 二階段,提交異步化,回滾通過一階段的回滾日志進行反向補償
  • 寫隔離:
    • 一階段本地事務提交之前,需要確保先拿到全域鎖,
    • 拿不到全域鎖就無法提交本地事務,
    • 拿全域鎖的嘗試被限制在一定范圍內,超過范圍將放棄,并回滾本地事務,釋放本地鎖,
  • 例子 一階段:
    • 決議SQL,得到SQL的型別,表,條件等相關資訊,
    • 查詢前鏡像:根據決議得到的條件資訊,生成查詢陳述句,定位資料,得到要更新這一行的資料的鏡像
    • 執行業務SQL,更新這條記錄,
    • 查詢后鏡像,根據前鏡像的結果,通過主鍵定位資料,得到之后的鏡像,
    • 插入回滾日志,把前后鏡像資料以及業務SQL相關的資訊組成一潭訓滾日志記錄,插入到UNDO_LOG表中,
    • 提交之前,向TC注冊分支,去申請要修改記錄的全域鎖,
    • 本地事務提交,業務資料的更新和前面步驟中生成的UNDO_LOG 一并提交
    • 將本地事務提交的結果上報給TC
  • 二階段-回滾
    • 收到TC的分支回滾請求,開啟一個本地事務,執行如下操作
    • 通過XID和BranchID查找相應的UNDO_LOG 記錄
    • 資料校驗:拿UNDO_LOG中的后鏡像與當前資料進行比較,如果有不同,說明資料被當前全域事務之外的動作做了修改,這種情況需要根據配置策略來做處理
    • 根據UNDO_LOG 中的前鏡像和業務SQL的相關資訊生成執行回滾的陳述句
    • 然后提交本地事務,并把本地事務的執行結果上報給TC
  • 二階段-提交
    • 收到TC的分支提交請求,把請求放入一個異步任務的佇列中,馬上回傳提交成功的結果給TC,
    • 異步任務階段的分支提交請求將異步和批量的洗掉相應UNDO_LOG記錄

TCC模式

上一步AT模式的全域事務整體式兩階段提交,全域事務時由若干分支事務組成,分支事務 要滿足兩階段提交的模型要求,即每個分支事務都具備自己的兩個階段

  1. 一階段 prepare行為 : 在本地事務中,一并提交業務資料更新和相應回滾日志記錄
  2. 二階段 commit 或 rollback行為 : commit行為,馬上成功結束,自動異步批量清理回滾日志
  3. 二階段 rollback : 通過回滾日志,自動生成補償操作,完成資料回滾

分布式事務的處理程序: ID+三組件模型

  • 全域唯一的事務ID
  • TC: Transaction Coordinator 事務協調器,維護全域事務的運行狀態,負責協調并驅動全域事務的提交或回滾
  • TM:Transaction Manager 控制全域事務的邊界,負責開啟一個全域事務,并最終發起全域提交或全域回滾的決議
  • RM:Resource Manager 控制分支事務,負責分支注冊,狀態匯報,并接收事務協調器的指令,驅動分支(本地)事務dd1提交和回滾

處理程序

  1. TM向TC申請開啟一個全域事務,全域事務創建成功,并生成一個全域唯一的XID
  2. XID在微服務呼叫鏈路的背景關系中傳播
  3. RM向TC注冊分支事務,將其納入XID對應全域事務的管轄,
  4. TM向TC發起針對XID的全域提交或回滾決議
  5. TC調度XID管轄的全部分支事務完成提交或回滾請求

這個太新了,我決定放棄!!!以后再來
























轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/260551.html

標籤:其他

上一篇:Chain of Responsibility 職責鏈模式

下一篇:/etc/apt/source.list

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more