为简单起见,我有一个上游只有1个服务器的例子:
Elixir.
和位置代理
upstream EarthML_IdentityService {
server localhost:25303 ;
}
map $upstream_addr $EarthML_IdentityServiceuniquepath {
default "7ab713ad-9ca5-4b08-8d32-84ec2e69370a/131365180085121149";
127.0.0.1:25303 "7ab713ad-9ca5-4b08-8d32-84ec2e69370a/131365180085121149";
}
但如果我删除了地图的location ~* ^/(subscriptions/.*/)?(resourcegroups/.*/)?providers/(EarthML.Identity) {
rewrite ^ /$EarthML_IdentityServiceuniquepath$uri break;
proxy_pass http://earthml_identityservice;
server_name_in_redirect on;
port_in_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Path $request_uri;
proxy_connect_timeout 3s;
proxy_set_header X-Forwarded-PathBase /;
proxy_cache_bypass $http_upgrade;
add_header X-Upstream $upstream_addr;
}
条目,那么它就会停止工作。我在标头中添加了default
,以确保add_header X-Upstream $upstream_addr;
确实设置为X-Upstream
答案 0 :(得分:0)
提供上下文的提升。我在Microsoft ServiceFabric中设置了微服务框架。
我正在使用所有服务的nginx infront进行路由的公共映射以纠正服务。
在最新版本中添加了一项新功能UseServiceFabricIntegration
,在设置服务监听和服务时允许服务结构为所有服务网址添加前缀suffix
在3节点设置中,这意味着服务A
将以3个不同的后缀为前缀,每个节点一个。此集成还sets up检查与此服务通信时后缀应匹配,否则返回410 GONE。
我试图在nginx中创建一个上游配置,如果主节点无法响应,它可能会将请求重新路由到其他两个节点之一。 (这里的节点是我在每个节点上运行nginx loadbalancer,直到现在我使用了没有上游的配置,节点1上的所有nginx请求也会映射到节点1上的服务。)
我想改变这种行为,为下一个版本做好准备,我希望能够在单独的节点上运行nginx并映射到不同节点上的服务,并且如上所述也可以在服务错误的情况下重新路由节点
主要的问题是,在nginx中使用上游服务器无法解决这个问题,因为原始问题被问到了这些不同的后缀。
我改为放弃了为aspnet核心构建的服务结构集成实现,并推出了自己的。
在nginx配置中我添加了:
sb.AppendLine($"{tabs}proxy_set_header X-ServiceFabric-Key {uniquekey};");
其中uniquekey
是根据服务名称和服务清单版本$"\"{ServiceName.AbsoluteUri.Substring("fabric:/".Length)}/{ServiceVersion}\""
我添加了自己的startupfilter来检查是否添加了此密钥:
if(context.Request.Headers.TryGetValue("X-ServiceFabric-Key", out StringValues serviceFabricKey))
{
if (!serviceFabricKey.FirstOrDefault().Equals(this.serviceFabricKey))
{
context.Response.StatusCode = StatusCodes.Status410Gone;
return;
}
}
因为我还使用http通信进行服务之间的一些内部通信,所以我添加了一个快速示例来执行get请求:
public class HttpCommunicationServicePartitionClient : ServicePartitionClient<HttpCommunicationClient>
{
private readonly FabricClient fabricClient;
private readonly Uri application;
public HttpCommunicationServicePartitionClient(
FabricClient fabricClient, Uri application, Uri serviceUri, ServicePartitionKey partitionKey = null, TargetReplicaSelector targetReplicaSelector = TargetReplicaSelector.Default, string listenerName = null, OperationRetrySettings retrySettings = null)
: base(new HttpCommunicationClientFactory(new ServicePartitionResolver(() => fabricClient)), serviceUri, partitionKey, targetReplicaSelector, listenerName, retrySettings)
{
this.fabricClient = fabricClient;
this.application = application;
}
public string BearerToken { get; set; }
public Task<HttpResponseMessage> GetAsync(string pathAndQuery)
{
return InvokeWithRetryAsync(async (client) =>
{
if (!string.IsNullOrEmpty(BearerToken))
{
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", BearerToken);
}
var services = await fabricClient.QueryManager.GetServiceListAsync(application, ServiceUri).ConfigureAwait(false);
var service = services.FirstOrDefault();
var key = $"{ServiceUri.AbsoluteUri.Substring("fabric:/".Length)}/{service.ServiceManifestVersion}";
client.DefaultRequestHeaders.Add("X-ServiceFabric-Key", key);
HttpResponseMessage response = await client.GetAsync(new Uri(client.BaseAddress, pathAndQuery));
return response;
});
}
}