Как распределить вычисления в ASP.NET и docker?

Рейтинг: 1Ответов: 0Опубликовано: 03.03.2025

Я пытаюсь создать на ASP.NET распределенную систему, которая вычисляет простое число в определенном диапазоне с помощью вероятностного алгоритма. У меня есть центральный узел и 3 рабочих узла, центральный узел должен распределить диапазоны для рабочих узлов, а они будут производить вычисления. Но я не до конца понимаю, как это все запустить на докере. У меня есть контейнер, который включает в себя 4 образа (узлы). Но при запуске не отображается порт. И возможно надо было создать 4 контейнера вместо 4 образов. Приложил скриншоты и код.

Dockerfile:

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["DistributedSystems_Lab1.csproj", ""]
RUN dotnet restore "./DistributedSystems_Lab1.csproj"
COPY . .
RUN dotnet publish "DistributedSystems_Lab1.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "DistributedSystems_Lab1.dll"]

Docker-compose.yml:

version: '3.8'

services:
  master:
    image: my_app:latest
    ports:
      - "8080:8080"
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure

  worker:
    image: my_app:latest
    deploy:
      replicas: 3
      restart_policy:
        condition: on-failure

PrimalityTest.cs:

namespace DistributedSystems_Lab1
{
    using System.Numerics;
    public static class PrimalityTest
    {
        public static bool IsPrime(BigInteger number, int k = 5)
        {
            if (number < 2) return false;
            if (number == 2 || number == 3) return true;
            if (number % 2 == 0) return false;

            BigInteger d = number - 1;
            int r = 0;
            while (d % 2 == 0)
            {
                d /= 2;
                r++;
            }

            Random rand = new();
            for (int i = 0; i < k; i++)
            {
                BigInteger a = RandomBigInteger(2, number - 2, rand);
                BigInteger x = BigInteger.ModPow(a, d, number);
                if (x == 1 || x == number - 1) continue;

                for (int j = 0; j < r - 1; j++)
                {
                    x = BigInteger.ModPow(x, 2, number);
                    if (x == number - 1) break;
                }

                if (x != number - 1) return false;
            }

            return true;
        }

        private static BigInteger RandomBigInteger(BigInteger min, BigInteger max, Random rand)
        {
            byte[] bytes = new byte[max.ToByteArray().Length];
            BigInteger result;
            do
            {
                rand.NextBytes(bytes);
                result = new BigInteger(bytes);
            } while (result < min || result > max);

            return result;
        }
    }
}

PrimeCheckRequest.cs:

namespace DistributedSystems_Lab1
{
    public class PrimeCheckRequest()
    {
        public string Start { get; set; }
        public string End { get; set; }
    }
}

PrimeCheckResponse.cs:

namespace DistributedSystems_Lab1
{
    public class PrimeCheckResponse
    {
        public List<string> Primes { get; set; } = new();
    }
}

PrimeController.cs:

namespace DistributedSystems_Lab1
{
    using Microsoft.AspNetCore.Mvc;
    using System.Collections.Generic;
    using System.Numerics;

    [ApiController]
    [Route("api/[controller]")]
    public class PrimeController : ControllerBase
    {
        [HttpPost("check")]
        public ActionResult<PrimeCheckResponse> CheckPrimes([FromBody] PrimeCheckRequest request)
        {
            BigInteger start = BigInteger.Parse(request.Start);
            BigInteger end = BigInteger.Parse(request.End);
            List<string> primes = new();

            for (BigInteger i = start; i <= end; i++)
            {
                if (PrimalityTest.IsPrime(i))
                {
                    primes.Add(i.ToString());
                }
            }

            return new PrimeCheckResponse { Primes = primes };
        }
    }

}

Program.cs:

using DistributedSystems_Lab1;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using System.Net.Http.Json;
using System.Numerics;
using System.Text.Json;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// Определяем роль: мастер или воркер
string role = Environment.GetEnvironmentVariable("ROLE") ?? "worker";

if (role == "master")
{
    // Маршрут для отправки задач воркерам
    app.MapPost("/api/master/start", async (HttpContext context) =>
    {
        var request = await context.Request.ReadFromJsonAsync<PrimeCheckRequest>();
        if (request == null) return Results.BadRequest("Invalid request");

        BigInteger start = BigInteger.Parse(request.Start);
        BigInteger end = BigInteger.Parse(request.End);
        int workerCount = 3;
        BigInteger step = (end - start) / workerCount;
        List<Task<List<string>>> tasks = new();

        // Распределяем диапазоны между воркерами
        for (int i = 0; i < workerCount; i++)
        {
            BigInteger subStart = start + i * step;
            BigInteger subEnd = (i == workerCount - 1) ? end : subStart + step;
            tasks.Add(SendToWorker(subStart, subEnd));
        }

        // Собираем результаты
        var results = await Task.WhenAll(tasks);
        var primes = results.SelectMany(x => x).ToList();

        return Results.Json(new PrimeCheckResponse { Primes = primes });
    });
}
else
{
    // Воркер выполняет проверку чисел
    app.MapPost("/api/worker/check", async (HttpContext context) =>
    {
        var request = await context.Request.ReadFromJsonAsync<PrimeCheckRequest>();
        if (request == null) return Results.BadRequest("Invalid request");

        BigInteger start = BigInteger.Parse(request.Start);
        BigInteger end = BigInteger.Parse(request.End);
        List<string> primes = new();

        for (BigInteger i = start; i <= end; i++)
        {
            if (PrimalityTest.IsPrime(i)) primes.Add(i.ToString());
        }

        return Results.Json(new PrimeCheckResponse { Primes = primes });
    });
}

app.Run();

// Функция отправки задач воркерам
static async Task<List<string>> SendToWorker(BigInteger start, BigInteger end)
{
    using var client = new HttpClient();
    var workerUrls = new[] { "http://worker1:80", "http://worker2:80", "http://worker3:80" };
    var randomWorker = workerUrls[new Random().Next(workerUrls.Length)];

    var response = await client.PostAsJsonAsync($"{randomWorker}/api/worker/check", new PrimeCheckRequest
    {
        Start = start.ToString(),
        End = end.ToString()
    });

    var result = await response.Content.ReadFromJsonAsync<PrimeCheckResponse>();
    return result?.Primes ?? new List<string>();
}

введите сюда описание изображения

введите сюда описание изображения

введите сюда описание изображения

введите сюда описание изображения

Ответы

Ответов пока нет.