ボックスの内容
- 春の雲OpenFeignソースの解析
- 春の雲リボンソースの解析
- 春クラウドアリババセンチネルソース決意
- 春の雲Gatwayソースの解析
- 春クラウドアリババナコスソースの解析
コードの準備
依存関係
+------------+ +------------+
| | | |
| | | |
| | | |
| | | |
| consumer +------------> | provider |
| | RestTemplate | |
| | | |
| | | |
| | | |
+------------+ +------------+
复制代码
ポンポン依存
ナコス発見ができるサービス、内部参照参加spring-cloud-ribbon
依存に関連し
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
复制代码
クライアントを呼び出し
ここで最もシンプルで私たちRestTemplate
の使用を開始するための呼び出しRibbon
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
// Controller 使用restTemplate 调用服务提供方接口
ResponseEntity<String> forEntity = restTemplate.getForEntity("http://provider/req", String.class);
复制代码
ソース決意
コール・インターセプターを作成します。
すべての取得1. @LoadBalanced
マークRestTemplate
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
}
复制代码
2.増加LoadBalancerInterceptor
処理ロジックを
- 導入されていない
spring-retry
使用して
@Bean
public LoadBalancerInterceptor ribbonInterceptor() {
return new LoadBalancerInterceptor();
}
复制代码
- 導入
spring-retry
使用
@Bean
@ConditionalOnMissingBean
public RetryLoadBalancerInterceptor ribbonInterceptor() {
return new RetryLoadBalancerInterceptor();
}
复制代码
- LoadBalancerInterceptorのビジネスロジック
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept() {
final URI originalUri = request.getURI();
// http://demo-provider/req 截取 demo-provider 服务名称
String serviceName = originalUri.getHost();
// 默认注入的 RibbonAutoConfiguration.RibbonLoadBalancerClient
return this.loadBalancer.execute(serviceName,
// 创建请求对象
this.requestFactory.createRequest(request, body, execution));
}
}
复制代码
実行インターセプター
3. RibbonLoadBalancerClient実行
//RibbonAutoConfiguration默认注入的RibbonLoadBalancerClient
@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
public LoadBalancerClient loadBalancerClient() {
return new RibbonLoadBalancerClient(springClientFactory());
}
复制代码
4.executeの実行
public class RibbonLoadBalancerClient implements LoadBalancerClient {
public <T> T execute(){
//获取具体的ILoadBalancer实现
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
// 调用ILoadBalancer 实现获取Server
Server server = getServer(loadBalancer, hint);
RibbonServer ribbonServer = new RibbonServer(serviceId, server,
isSecure(server, serviceId),
serverIntrospector(serviceId).getMetadata(server));
//获取状态记录器,保存此次选取的server
RibbonLoadBalancerContext context = this.clientFactory
.getLoadBalancerContext(serviceId);
RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
T returnVal = request.apply(serviceInstance);
statsRecorder.recordStats(returnVal);
return returnVal;
}
}
复制代码
取得ILoadBalancer
5 SpringClientFactory
// bean 工厂生成LoadBalancer 的实现
protected ILoadBalancer getLoadBalancer(String serviceId) {
return this.springClientFactory.getLoadBalancer(serviceId);
}
// 具体生成逻辑看 RibbonClientConfiguration,这个Bean 只有工厂调用的时候才会创建
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
return new ZoneAwareLoadBalancer<>();
}
复制代码
ロードバランサ依存する要素を作成します。6.
名前 | デフォルトの実装 | 効果 |
---|---|---|
IClientConfig | DefaultClientConfigImpl | 以下のようなリボンのクライアント設定パラメータ:タイムアウト設定、圧縮永久歪みなど |
サーバリスト | NacosServerList | 例例テーブルの対象サービス、特定のサービス発見クライアントの実装 |
ServerListFilter | ZonePreferenceServerListFilter | 論理例のリストは、フィルタリング処理サーバリスト |
iRule | ZoneAvoidanceRule | 選択ルールのサーバーの負荷分散 |
IPing | DummyPing | サービスをテストする方法は、達成するために利用可能です |
ServerListUpdater | PollingServerListUpdater | サーバリストの運用更新を達成 |
上記のデフォルトの実装参照 RibbonClientConfiguration. ZoneAwareLoadBalancer
サービスへのアクセスの例
//Server server = getServer(loadBalancer, hint); 4. excute 方法
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
return loadBalancer.chooseServer(hint != null ? hint : "default");
}
复制代码
7. ZoneAwareLoadBalancer
public class ZoneAwareLoadBalancer{
public ZoneAwareLoadBalancer() {
// 调用父类初始化方法。 这里会开启实例维护的定时任务等 (具体解析参考 扩展部分)
super(clientConfig, rule, ping, serverList, filter, serverListUpdater);
}
@Override
public Server chooseServer(Object key) {
// 若是使用的 Nacos 服务发现,则没有 Zone 的概念,直接调用父类的实现
if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
return super.chooseServer(key);
}
// 以下为有 Zone 的概念 例如 Eureka (具体)
...
return server;
}
}
复制代码
- 親クラスを呼び出す
IRule
実装の選択サーバーを
public Server chooseServer(Object key) {
return rule.choose(key);
}
复制代码
8.PredicateBasedRule選択ルール
public abstract class PredicateBasedRule {
@Override
public Server choose(Object key) {
ILoadBalancer lb = getLoadBalancer();
// 获取断言配置
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
if (server.isPresent()) {
return server.get();
} else {
return null;
}
}
}
复制代码
サービスアサーションの9 ZoneAvoidancePredicateリスト
public class ZoneAvoidancePredicate {
@Override
public boolean apply(@Nullable PredicateKey input) {
if (!ENABLED.get()) {
return true;
}
// 还是获取区域配置,如是使用的 Nacos 直接返回true
String serverZone = input.getServer().getZone();
if (serverZone == null) {
// there is no zone information from the server, we do not want to filter
// out this server
return true;
}
// 区域高可用判断
...
}
}
复制代码
拡張:サーバリストのメンテナンス
初期サーバリスト
上記で作成したロードバランサ依存素子6、ServerList
ターゲットサービスインスタンスインスタンステーブル、特定のサービス発見クライアントの実装。私たちは、ナコスの実現を見て
public class NacosServerList extends AbstractServerList<NacosServer> {
@Override
public List<NacosServer> getInitialListOfServers() {
return getServers();
}
@Override
public List<NacosServer> getUpdatedListOfServers() {
return getServers();
}
private List<NacosServer> getServers() {
String group = discoveryProperties.getGroup();
//调用nacos-sdk 查询实例列表
List<Instance> instances = discoveryProperties.namingServiceInstance()
.selectInstances(serviceId, group, true);
// 类型转换
return instancesToServerList(instances);
}
}
复制代码
更新ServerListUpdater
- サーバリストで更新操作を初期化した後
PollingServerListUpdater
public class PollingServerListUpdater implements ServerListUpdater {
@Override
public synchronized void start(final UpdateAction updateAction) {
// 更新任务 交给updateAction 具体实现
final Runnable wrapperRunnable = () -> {
updateAction.doUpdate();
lastUpdated = System.currentTimeMillis();
};
// 开启后台线程定时执行 updateAction
scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
wrapperRunnable,
initialDelayMs,
refreshIntervalMs,
TimeUnit.MILLISECONDS
);
}
}
复制代码
- 達成updateAction
public void doUpdate() {
DynamicServerListLoadBalancer.this.updateListOfServers();
}
复制代码
public class PollingServerListUpdater implements ServerListUpdater {
public void updateListOfServers() {
List<T> servers = new ArrayList();
// 调用NacosServiceList 获取全部服务列表
servers = this.serverListImpl.getUpdatedListOfServers();
// 如果配置实例过滤器在执行过滤
if (this.filter != null) {
servers = this.filter.getFilteredListOfServers((List)servers);
}
// 更新LoadBalancer 服务列表
this.updateAllServerList((List)servers);
}
}
复制代码
拡張:サーバのメンテナンス状況
- ロードバランサは、初期構築がトリガされます
setupPingTask()
public BaseLoadBalancer() {
this.name = DEFAULT_NAME;
this.ping = null;
setRule(DEFAULT_RULE);
// 开启ping 检查任务
setupPingTask();
lbStats = new LoadBalancerStats(DEFAULT_NAME);
}
复制代码
- セットアップピングタスク
void setupPingTask() {
// 是否可以ping, 默认的DummyPing 直接 跳过不执行
if (canSkipPing()) {
return;
}
// 执行PingTask
lbTimer.schedule(new BaseLoadBalancer.PingTask(), 0, pingIntervalSeconds * 1000);
// 开启任务
new BaseLoadBalancer.Pinger(pingStrategy).runPinger();
}
复制代码
- SerialPingStrategyシリアル実行ロジック
// 串行调度执行 Iping 逻辑
private static class SerialPingStrategy implements IPingStrategy {
@Override
public boolean[] pingServers(IPing ping, Server[] servers) {
int numCandidates = servers.length;
boolean[] results = new boolean[numCandidates];
for (int i = 0; i < numCandidates; i++) {
results[i] = false; /* Default answer is DEAD. */
if (ping != null) {
results[i] = ping.isAlive(servers[i]);
}
}
return results;
}
}
复制代码
- URL審判の判定の可用性
public class PingUrl implements IPing {
public boolean isAlive(Server server) {
urlStr = urlStr + server.getId();
urlStr = urlStr + this.getPingAppendString();
boolean isAlive = false;
HttpClient httpClient = new DefaultHttpClient();
HttpUriRequest getRequest = new HttpGet(urlStr);
String content = null;
HttpResponse response = httpClient.execute(getRequest);
content = EntityUtils.toString(response.getEntity());
isAlive = response.getStatusLine().getStatusCode() == 200;
return isAlive;
}
}
复制代码
拡張:RibbonClient遅延ローディングプロセス
以上のことから、リボンの時点で要求が作成するデフォルトになりますLoadBalancer
。この遅延ローディングメカニズムを、サービスが開始の最初の呼び出しつながるサービス待ち時間など、でもタイムアウトヒューズ集積回路ブレーカ(hystrix)で問題を、 。
この問題を解決するために、我々は、飢餓の負荷リボンを設定します
ribbon:
eager-load:
clients:
- provider
复制代码
RibbonApplicationContextInitializer
サービス開始は自動的にリボンクライアントを作成する必要があり、事前に工場を呼び出した後
public class RibbonApplicationContextInitializer
implements ApplicationListener<ApplicationReadyEvent> {
private final List<String> clientNames;
protected void initialize() {
if (clientNames != null) {
for (String clientName : clientNames) {
this.springClientFactory.getContext(clientName);
}
}
}
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
initialize();
}
}
复制代码
次の手順
私は、更新の後ろに、注意を歓迎しRibbon
、Hystrix
、Sentinel
、Nacos
およびソースグラフィックの解像度の他のコンポーネント。
もう一つ注意:上記の映像素材(OmniGraffleは&図億)公共の数字ではできJAVA架构日记
得ます