Solon Cloud 是一系列的介面標準和配置規範。Solon Cloud 為常見的分散式系統模式提供了一種簡單且方便的程式設計模式,幫助開發人員構建有彈性的、可靠的、協調的應用程式。Solon Cloud 構建於 Solon 之上,可使開發者很容易入手並快速應用於生產中。Solon Cloud 主要由三部份組成:介面定義與配置規範、實現相關介面定義的各種外掛,以及通用客戶端。
Solon Cloud 非常容易實現與自研框架進行對接。只要實現相關介面定義,按規範配置的一個外掛,即是一個 Solon Cloud 外掛。
Solon Cloud 專案原始碼:https://gitee.com/noear/solon
Solon Cloud 示例原始碼:https://gitee.com/noear/solon_cloud_demo
特點1:身材苗條
最小的 Solon Cloud 開發單位只有4m(含 okhttp、mysql、redis、memcaced、HikariCP 等客戶端或驅動)
特點2:速度更快
本機helloworld測試,Qps可達12萬之多。可參考:《helloworld_wrk_test》
特點3:程式碼自由
所有的能力可以用註解,也可以純手寫。按需而定,自由隨心。
建議
讓自己的單體應用,能多例項部署。就是分散式的良好開始......然後改用配置服務,然後增加事件驅動,按需拆分......慢慢來。
一、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)現有適配外掛清單
外掛 | 說明 |
---|---|
外部框架適配:: | 說明 |
org.noear:consul-solon-plugin | consul 適配外掛(支援Solon cloud 配置服務、註冊與發現服務) |
org.noear:nacos-solon-plugin | nacos 適配外掛(支援Solon cloud 配置服務、註冊與發現服務) |
org.noear:zookeeper-solon-plugin | zookeeper 適配外掛(支援Solon cloud 配置服務、註冊與發現服務) |
org.noear:water-solon-plugin | water 適配外掛(支援Solon cloud 配置服務、註冊與發現服務、事件匯流排服務、日誌服務、跟蹤服務、鎖服務) |
org.noear:rabbitmq-solon-plugin | rabbitmq 適配外掛(支援Solon cloud 事件匯流排服務) |
org.noear:rocketmq-solon-plugin | rocketmq 適配外掛(支援Solon cloud 事件匯流排服務) |
org.noear:mqtt-solon-plugin | mqtt 適配外掛(支援Solon cloud 事件匯流排服務) |
org.noear:kafka-solon-plugin | kafka 適配外掛(支援Solon cloud 事件匯流排服務) |
org.noear:guava-solon-plugin | guava 適配外掛(支援Solon cloud 融斷服務) |
org.noear:sentinel-solon-plugin | sentinel 適配外掛(支援Solon cloud 融斷服務) |
org.noear:semaphore-solon-plugin | semaphore 適配外掛(支援Solon cloud 融斷服務) |
org.noear:aliyun-oss-solon-plugin | aliyun-oss 適配外掛(支援Solon cloud 分散式檔案服務) |
org.noear:aws-s3-solon-plugin | aws-s3 適配外掛(支援Solon cloud 分散式檔案服務) |
org.noear:snowflake-id-solon-plugin | snowflake 演算法適配外掛(支援Solon cloud 分散式ID服務) |
(3)通用客戶端
通用客戶端,提供了所有不同框架的統一使用介面,同時提供了自由手動操控的機制。
//手動獲取配置(不管背後是哪個配置框架,都是如此)
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 的兩個特性說明:
- 自守護模式,即失敗後不斷延時重發確保最終成功。此特性可支援SAGA分散式事務模型。
- 多通道模式,即不同訊息佇列並存。此特性可按業務做不同安排,例如:業務訊息用 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}")
(12)使用閘道器,為同一套介面提供不同的輸出
//閘道器1
@Mapping("/api/rest/**")
@Component
public class ApiGateway extends Gateway {
@Override
protected void register() {
//設定預設render
before(c -> c.attrSet("@render", "@json"));
//新增服務
add("user", UserServiceImpl.class, true);
}
}
//閘道器2
@Mapping("/api/rpc/**")
@Component
public class RpcGateway extends Gateway {
@Override
protected void register() {
//設定預設render
before(c -> c.attrSet("@render", "@type_json"));
//新增服務(不帶mapping的函式;需要 remoting = true,才會載入出來)
add("user", UserServiceImpl.class, true);
}
}
三、附:完整的配置
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 (以下配置打包只有4.7m)
<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>
<!-- 配置服務、註冊與發現服務、日誌服務、鎖服務、名單服務、跟蹤服務... (含 okhttp,redis,memcaced,HikariCP 等...) -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>water-solon-plugin</artifactId>
</dependency>
<!-- 融斷服務 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>sentinel-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>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>