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 的兩個特性說明:
- 自守護模式,即失敗後不斷延時重發確保最終成功。此特性可支持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}")
三、附:完整的配置
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>