.NET7更新后Orleans也随着更新了一个大版本,但是感觉微软官方的文档并不是很好,这里写个小demo来演示简单的集群管理(本次使用redis,官方文档甚至都没有提过redis),可以参考Orleans 中的群集管理
创建项目
创建文件夹
mkdir Client
mkdir Server
mkdir Grain
mkdir IGrain
mkdir Model
初始化代码
cd Server
dotnet new webapi -minimal
cd ../Client
dotnet new console
cd ../Grain
dotnet new classlib
cd ../IGrain
dotnet new classlib
cd ../Model
dotnet new classlib
添加项目引用
cd ../Server
dotnet add reference ../Grain/Grain.csproj
cd ../Client
dotnet add reference ../IGrain/IGrain.csproj
cd ../IGrain
dotnet add reference ../Model/Model.csproj
cd ../Grain
dotnet add reference ../IGrain/IGrain.csproj
添加包引用
cd ../Server
dotnet add package Microsoft.Orleans.Server
dotnet add package Orleans.Clustering.Redis
dotnet add package Orleans.Persistence.Redis
cd ../Client
dotnet add package Microsoft.Extensions.Hosting
dotnet add package Microsoft.Extensions.Configuration.CommandLine
dotnet add package Microsoft.Extensions.Configuration.EnvironmentVariables
dotnet add package Microsoft.Orleans.Client
dotnet add package Orleans.Clustering.Redis
cd ../Model
dotnet add package Microsoft.Orleans.Sdk
cd ../IGrain
dotnet add package Microsoft.Orleans.Sdk
cd ../Grain
dotnet add package Microsoft.Orleans.Sdk
添加代码
Model:
//File:Message
namespace Model;
[GenerateSerializer]
public class Message
{
[Id(0)]
public string Ip { get; set; }
}
IGrain:
//File:IMessageHandler.cs
using Model;
namespace IGrain;
public interface IMessageHandler : IGrainWithIntegerKey
{
ValueTask<string> Send(Message message);
}
Grain:
//File:MessageHandler.cs
using IGrain;
using Model;
namespace Grain;
public class MessageHandler : IMessageHandler
{
public ValueTask<string> Send(Message message)
{
Console.WriteLine($"[DateTime] {DateTime.Now} [Message:Ip] {message.Ip}");
return ValueTask.FromResult("ok");
}
}
Server:
//File:Program.cs
using Orleans.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseOrleans((ctx, orleansBuilder) =>
{
var redisAddress = builder.Configuration["redisHost"];
orleansBuilder.UseRedisClustering(options => options.ConnectionString = redisAddress);
orleansBuilder.AddRedisGrainStorage("votes", options => options.ConnectionString = redisAddress);
});
var app = builder.Build();
app.Run();
Client:
//File:Program.cs
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using IGrain;
using System.Net;
var config = new ServiceCollection()
.AddSingleton<IConfiguration>(serviceProvider =>
{
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddEnvironmentVariables();
if (args != null)
{
configurationBuilder.AddCommandLine(args);
}
return configurationBuilder.Build();
})
.BuildServiceProvider().GetService<IConfiguration>();
Thread.Sleep(5000);//docker直接跑的话,有可能Server没跑起来Client就已经准备去连接了
try
{
IHost host = await StartClientAsync(config["redisHost"] ?? "127.0.0.1:6379");
IClusterClient client = host.Services.GetRequiredService<IClusterClient>();
//下面做一些事情
await DoClientWorkAsync(client);
while (true)
{
await Task.Delay(5000);
await DoClientWorkAsync(client);
}
await host.StopAsync();
return 0;
}
catch (Exception e)
{
Console.WriteLine($$"""
Exception while trying to run client: {{e.Message}}
Make sure the silo the client is trying to connect to is running.
Press any key to exit.
""");
return 1;
}
static async Task<IHost> StartClientAsync(string redisHost)
{
var redisAddress = redisHost;
var builder = new HostBuilder()
.UseOrleansClient(client =>
{
client.UseRedisClustering(options => options.ConnectionString = redisAddress);
})
.ConfigureLogging(logging => logging.AddConsole());
var host = builder.Build();
await host.StartAsync();
Console.WriteLine("Client successfully connected to silo host \n");
return host;
}
static async Task DoClientWorkAsync(IClusterClient client)
{
var friend = client.GetGrain<IMessageHandler>(0);
var result = await friend.Send(new Model.Message
{
Ip = Dns.GetHostName()
});
}
项目发布
publish
在根目录创建publish.bat
dotnet publish Server -o server_publish
dotnet publish Client -o client_publish
执行./publish
dockerfile
dockerfile_client:
FROM mcr.microsoft.com/dotnet/aspnet:7.0
COPY client_publish /app
WORKDIR /app
EXPOSE 80/tcp
ENTRYPOINT ["dotnet", "Client.dll"]
dockerfile_server
FROM mcr.microsoft.com/dotnet/aspnet:7.0
COPY server_publish /app
WORKDIR /app
EXPOSE 80/tcp
ENTRYPOINT ["dotnet", "Server.dll"]
docker-compose
version: '3'
services:
redis:
image: redis:latest
server:
build:
context: ./
dockerfile: ./dockerfile_server
depends_on:
- redis
environment:
- redisHost=redis:6379
client:
build:
context: ./
dockerfile: ./dockerfile_client
depends_on:
- server
environment:
- redisHost=redis:6379
执行docker compose up --scale client=3 --scale server=2
效果展示
我们关闭server2后,发现他会自动选举别的server
标签:Orleans,..,简单,cd,add,client,使用,dotnet From: https://www.cnblogs.com/zhsun999/p/17237984.htmlpower byzhsun999