Solon Cloud 微服務開發套件清單與快速概覽

Solon Cloud 是一系列的接口標準和配置規範,是微服務模式架構的一站式解決方案。Solon Cloud 爲常見的分佈式系統模式提供了一種簡單且方便的編程模式,幫助開發人員構建有彈性的、可靠的、協調的應用程序。Solon Cloud 構建於 Solon 之上,可使開發者很容易入手並快速應用於生產中。Solon Cloud 主要由四部份組成:接口定義、配置規範、通用客戶端,以及實現相關接口定義的各種插件。

Solon Cloud 非常容易實現與自研框架進行對接。只要實現相關接口定義,按規範配置的一個插件,即是一個 Solon Cloud 插件。

Solon Cloud 項目源碼:https://gitee.com/noear/solon

一、Solon Cloud 套件

(1)接口定義及配置規範清單

接口定義及配置規範,可爲不同的框架適配與使用提供了統一的模式

功能名稱 Solon Cloud 接口定義 配置規範(具體暫略)
服務註冊與發現 Solon Cloud Discovery CloudDiscoveryService solon.cloud.@@.discovery
服務間調用方式 RPC or REST API or Event - -
服務網關 Solon Gateway - -
斷路器 Solon Cloud Breaker CloudBreakerService solon.cloud.@@.breaker
分佈式配置 Solon Cloud Config CloudConfigService solon.cloud.@@.config
服務跟蹤 Solon Cloud Tracing CloudTraceService solon.cloud.@@.trace
事件總線 Solon Cloud Event CloudEventService solon.cloud.@@.event
分佈式任務 Solon Cloud Job CloudJobService solon.cloud.@@.job
分佈式ID Solon Cloud Id CloudIdService solon.cloud.@@.id
分佈式文件 Solon Cloud File CloudFileService solon.cloud.@@.file
分佈式名單 Solon Cloud List CloudListService solon.cloud.@@.list
分佈式鎖 Solon Cloud Lock CloudLockService solon.cloud.@@.lock
分佈式日誌 Solon Cloud Logging CloudLogService solon.cloud.@@.log

(2)通用客戶端

通用客戶端,提供了所有不同框架的統一使用界面,同時提供了自由手動操控的機制。

//手動獲取配置(不管背後是哪個配置框架,都是如此)
 Config val1 = CloudClient.config().pull(Solon.cfg().appGroup(), "demo.ds");
 
 //手動生成ID
 long val2 = CloudClient.id().generate();
 
 //手動發佈事件(不管背後是哪個消息隊列,都是如此)
 CloudClient.event().publish(new Event("demo.user.login","1"));
 
 //等...

二、快速概覽

(1)hello world

一個普通的 rest api,輸出 hello world

public class DemoApp {
    public static void main(String[] args) {
        Solon.start(DemoApp.class, args, app->{
          app.get("/", c -> c.output("Hello world!"));
        });
    }
}

(2)使用配置服務

通過本地配置導入需要的分佈式配置

solon.cloud.water:
  server: water  
  config:
    load: "test.properties" #默認加載一個配置

或者,使用 @CloudConfig 註解生成Bean

@Configuration
public class Config {
    @Bean
    public DataSource ds(@CloudConfig("demo.ds") HikariDataSource ds){
        return ds;
    }
}

(3)使用註冊與發現服務實現RPC調用

服務端

//
// 1.所有 remoting = true 的組件,即爲 rpc 服務;
// 2.以 uri 的形式提供資源描述,以同時支持 rest api 和 rpc 兩種模式
//
@Mapping("/rpc/")
@Component(remoting = true)
public class HelloServiceImpl implements HelloService{

    @Override
    public String hello(String name) {
        return null;
    }
}

客戶端

@Controller
public class HelloController {
    //注入Rpc服務代理(會自動通過發現服務獲取服務集羣)
    @NamiClient(name = "hellorpc", path = "/rpc/")
    HelloService helloService;
    
    public String hello(String name){
        return helloService.hello(name);
    }
}

(4)使用Slf4j日誌接口,轉發到分佈式日誌記錄器

Solon Cloud Log 強調語義標籤(或固化的元信息)。通過語議標籤,對日誌進行固定索引,進而實現更快的查詢效果。

@Slf4j
public class LogController {
    @Mapping("/")
    public String hello(String name){
        //將元信息固化爲 tag0 ... tag4;利於做日誌索引
        TagsMDC.tag0("user_"+name); //相當於 MDC.put("tag0", "user_"+name);
        
        log.info("有用戶來了");
        
        return name;
    }
}

注:也可以改用 logback 做日誌服務,只需要排除掉 solon.logging.impl 框架卻可

(5)使用分佈式事件進行業務水平擴展

Solon Cloud Event 的兩個特性說明:

  1. 自守護模式,即失敗後不斷延時重發確保最終成功。此特性可支持SAGA分佈式事務模型。
  2. 多通道模式,即不同消息隊列並存。此特性可按業務做不同安排,例如:業務消息用 RabbitMQ,IoT消息用 Mqtt。

例,發佈事件

public class EventController {
    public void onUserRegistered(long user_id) {
        //用戶註冊完成後,發佈一個事件
        //
        CloudClient.event().publish(
                new Event("user.registered", String.format("{\"user_id\":%d}", user_id)));
    }
}

訂閱與消費事件

@CloudEvent("user.registered")
public class EventListen implements CloudEventHandler {
    @Override
    public boolean handler(Event event) throws Throwable {
        //用戶註冊完成後,送個金幣...
        //
        return true;
    }
}

(6)使用分佈式名單做IP限制

public class ListController {
    public void hello(Context ctx){
        String ip = IpUtils.getIP(ctx);
        
        if(CloudClient.list().inListOfIp("safelist", ip) == false){
            return;
        }
        
        //業務處理...
    }
}

(7)使用融斷器進行限流控制

添加配置(此配置可通過配置服務,動態更新)

solon.cloud.local:
  breaker:
    main: 100 #qps = 100

通過註解,添加埋點

//此處的註解埋點,名稱與配置的斷路器名稱須一一對應
@CloudBreaker("main")
public class BreakerController {
    @Mapping("/breaker")
    public void breaker(){
        
    }
}

(8)使用跟蹤服務獲取並傳播TraceId

通過MDC傳遞給 slf4j MDC

String traceId = CloudClient.trace().getTraceId();

MDC.put(CloudClient.trace().HEADER_TRACE_ID_NAME(), traceId);

通過Http Header 傳給後Http節點

HttpUtils.url("http://x.x.x.x")
  .headerAdd(CloudClient.trace().HEADER_TRACE_ID_NAME(), traceId).get();

等......(Solon Cloud Log 默認支持 CloudClient.trace() 接口)

(9)使用分佈式ID,生成有序不重複ID

long log_id = CloudClient.id().generate();

(10)使用分佈式鎖,對流量或資源進行控制

if(CloudClient.lock().lock("user_"+user_id, 3)){
    //對一個用戶嘗試3秒的鎖;3秒內不充行重複提交
}else{
    //請求太頻繁了...
}

(11)使用分佈式文件服務

//使用分佈式文件,存儲用戶擴展信息
CloudClient.file().putText("solon/user_"+user_id, "{name:noear}")

三、附:完整的配置

application.yml

solon.app:
  group: demo       #配置服務使用的默認組
  name: helloapp    #發現服務使用的應用名

solon.cloud.water:
  server: water   #water服務地址
  config:
    load: "test.properties" #默認加載一個配置
  discovery:
    enable: true  #設爲 false 時,solon.cloud.local.discovery 會生效(一般用於本地調試)

solon.cloud.local:
  discovery:
    service:
      hellorpc:
        - "http://localhost:7112"  #本地服務配置
  breaker:
    main: 100

pom.xml

<parent>
    <groupId>org.noear</groupId>
    <artifactId>solon-parent</artifactId>
    <version>1.3.32</version>
</parent>

<dependencies>
    <!-- RPC 框架 -->
    <dependency>
        <groupId>org.noear</groupId>
        <artifactId>solon-rpc</artifactId>
    </dependency>

    <!-- 配置服務、註冊與發現服務、日誌服務、鎖服務、名單服務、跟蹤服務... -->
    <dependency>
        <groupId>org.noear</groupId>
        <artifactId>water-solon-plugin</artifactId>
    </dependency>

    <!-- 融斷服務 -->
    <dependency>
        <groupId>org.noear</groupId>
        <artifactId>guava-solon-plugin</artifactId>
    </dependency>

    <!-- 文件服務 -->
    <dependency>
        <groupId>org.noear</groupId>
        <artifactId>aliyun-oss-solon-plugin</artifactId>
    </dependency>

    <!-- ID服務 -->
    <dependency>
        <groupId>org.noear</groupId>
        <artifactId>snowflake-id-solon-plugin</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.49</version>
    </dependency>

    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>3.3.1</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

<build>
    <finalName>${project.artifactId}</finalName>

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.7.0</version>
            <configuration>
                <compilerArgument>-parameters</compilerArgument>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
                <finalName>${project.artifactId}</finalName>
                <appendAssemblyId>false</appendAssemblyId>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>demo.DemoApp</mainClass>
                    </manifest>
                </archive>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>

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