Загрузка данных


import random
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

class Request:
    def __init__(self, req_id, arrival_time, req_type, service_time):
        self.id = req_id
        self.arrival_time = arrival_time
        self.req_type = req_type
        self.service_time = service_time
        self.start_service = 0.0
        self.end_service = 0.0

def simulate_storage(lam, mu_up, mu_down, n_servers, upload_prob, sim_time, warmup, seed=42):
    random.seed(seed)

    req_id = 0
    queue = []
    servers = [None] * n_servers
    completed = []
    events = []

    next_arrival = random.expovariate(lam)
    events.append((next_arrival, 'arrival', None))

    while events:
        events.sort(key=lambda x: x[0])
        current_time, ev_type, ev_data = events.pop(0)

        if current_time > sim_time:
            break

        if ev_type == 'arrival':
            if random.random() < upload_prob:
                req_type = 'upload'
                svc = random.expovariate(mu_up)
            else:
                req_type = 'download'
                svc = random.expovariate(mu_down)

            req = Request(req_id, current_time, req_type, svc)
            req_id += 1

            free_server = None
            for i, s in enumerate(servers):
                if s is None or s[0] <= current_time:
                    free_server = i
                    break

            if free_server is not None:
                req.start_service = current_time
                req.end_service = current_time + svc
                servers[free_server] = (req.end_service, req)
                events.append((req.end_service, 'departure', (free_server, req)))
            else:
                queue.append(req)

            next_arr = current_time + random.expovariate(lam)
            if next_arr < sim_time:
                events.append((next_arr, 'arrival', None))

        elif ev_type == 'departure':
            server_idx, req = ev_data

            if current_time > warmup:
                completed.append(req)

            if queue:
                next_req = queue.pop(0)
                next_req.start_service = current_time
                next_req.end_service = current_time + next_req.service_time
                servers[server_idx] = (next_req.end_service, next_req)
                events.append((next_req.end_service, 'departure', (server_idx, next_req)))
            else:
                servers[server_idx] = None

    if not completed:
        return None

    wait_times = [r.start_service - r.arrival_time for r in completed]
    service_times = [r.service_time for r in completed]
    resp_times = [r.end_service - r.arrival_time for r in completed]

    rho = lam / (n_servers * (upload_prob * mu_up + (1 - upload_prob) * mu_down))

    return {
        'lam': lam,
        'mean_wait': np.mean(wait_times),
        'mean_service': np.mean(service_times),
        'mean_response': np.mean(resp_times),
        'mean_queue': np.mean(wait_times) * lam,
        'rho': min(rho, 0.999)
    }

MU_UPLOAD = 0.5
MU_DOWNLOAD = 2.0
UPLOAD_PROB = 0.35
SIM_TIME = 5000
WARMUP = 500
N_RUNS = 5

LAMBDAS = [0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4]
SERVER_COUNTS = [1, 2, 3, 4]

results = {}
ci = {}

for c in SERVER_COUNTS:
    results[c] = []
    ci[c] = []
    for lam in LAMBDAS:
        runs = []
        for run in range(N_RUNS):
            res = simulate_storage(lam, MU_UPLOAD, MU_DOWNLOAD, c, UPLOAD_PROB, SIM_TIME, WARMUP, seed=run*100)
            if res:
                runs.append(res)

        if runs:
            resp_vals = [r['mean_response'] for r in runs]
            wait_vals = [r['mean_wait'] for r in runs]

            mean_resp = np.mean(resp_vals)
            mean_wait = np.mean(wait_vals)

            if len(runs) > 1:
                interval_resp = stats.t.interval(0.95, df=len(runs)-1, loc=mean_resp, scale=stats.sem(resp_vals))
                interval_wait = stats.t.interval(0.95, df=len(runs)-1, loc=mean_wait, scale=stats.sem(wait_vals))
            else:
                interval_resp = (mean_resp, mean_resp)
                interval_wait = (mean_wait, mean_wait)

            avg = {
                'lam': lam,
                'mean_wait': mean_wait,
                'mean_service': np.mean([r['mean_service'] for r in runs]),
                'mean_response': mean_resp,
                'mean_queue': np.mean([r['mean_queue'] for r in runs]),
                'rho': np.mean([r['rho'] for r in runs]),
                'ci_resp_lo': interval_resp[0],
                'ci_resp_hi': interval_resp[1],
                'ci_wait_lo': interval_wait[0],
                'ci_wait_hi': interval_wait[1]
            }
            results[c].append(avg)

print("-" * 75)
print(" СВОДНАЯ ТАБЛИЦА РЕЗУЛЬТАТОВ (2 сервера)")
print("-" * 75)
print(f"{'лямбда':<8} {'Ожидание':<10} {'Обслуж.':<10} {'Ответ':<10} {'Очередь':<9} {'Загрузка':<8} {'95% ДИ ответа'}")
print("-" * 75)
for r in results[2]:
    print(f"{r['lam']:<8.1f} {r['mean_wait']:<10.3f} {r['mean_service']:<10.3f} "
          f"{r['mean_response']:<10.3f} {r['mean_queue']:<9.2f} {r['rho']:<8.1%} "
          f"[{r['ci_resp_lo']:.3f}, {r['ci_resp_hi']:.3f}]")
print("-" * 75)

print("\n" + "-" * 55)
print(" СРАВНЕНИЕ ЧИСЛА СЕРВЕРОВ при λ = 1.0")
print("-" * 55)
print(f"{'Серверов':<10} {'Ожидание':<12} {'Ответ':<12} {'Очередь':<10} {'Загрузка'}")
print("-" * 55)
for c in SERVER_COUNTS:
    for r in results[c]:
        if abs(r['lam'] - 1.0) < 0.01:
            print(f"{c:<10} {r['mean_wait']:<12.3f} {r['mean_response']:<12.3f} {r['mean_queue']:<10.2f} {r['rho']:.1%}")
print("-" * 55)

print("\n[Анализ точек деградации (>80% нагрузки)]")
for c in SERVER_COUNTS:
    degraded = False
    for r in results[c]:
        if r['rho'] > 0.8:
            print(f" Серверов: {c} -> деградация при лямбда = {r['lam']:.1f} (Загрузка: {r['rho']:.1%})")
            degraded = True
            break
    if not degraded:
        print(f" Серверов: {c} -> система стабильна на всех протестированных частотах")

fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle("Имитационная модель облачного хранилища", fontsize=14)

colors = ['blue', 'green', 'orange', 'red']
labels = ['1 сервер', '2 сервера', '3 сервера', '4 сервера']

ax1 = axes[0, 0]
ax1.set_title("Время ответа vs Интенсивность")
for i, c in enumerate(SERVER_COUNTS):
    x = [r['lam'] for r in results[c]]
    y = [r['mean_response'] for r in results[c]]
    ax1.plot(x, y, marker='o', color=colors[i], label=labels[i])
ax1.set_xlabel("Интенсивность запросов λ (зап/сек)")
ax1.set_ylabel("Среднее время ответа (сек)")
ax1.legend()
ax1.grid(True)

ax2 = axes[0, 1]
ax2.set_title("Время ожидания в очереди")
for i, c in enumerate(SERVER_COUNTS):
    x = [r['lam'] for r in results[c]]
    y = [r['mean_wait'] for r in results[c]]
    ax2.plot(x, y, marker='o', color=colors[i], label=labels[i])
ax2.set_xlabel("Интенсивность запросов λ (зап/сек)")
ax2.set_ylabel("Среднее время ожидания (сек)")
ax2.legend()
ax2.grid(True)

ax3 = axes[1, 0]
ax3.set_title("Длина очереди")
for i, c in enumerate(SERVER_COUNTS):
    x = [r['lam'] for r in results[c]]
    y = [r['mean_queue'] for r in results[c]]
    ax3.plot(x, y, marker='o', color=colors[i], label=labels[i])
ax3.set_xlabel("Интенсивность запросов λ (зап/сек)")
ax3.set_ylabel("Средняя длина очереди (запросов)")
ax3.legend()
ax3.grid(True)

ax4 = axes[1, 1]
ax4.set_title("Загрузка серверов")
for i, c in enumerate(SERVER_COUNTS):
    x = [r['lam'] for r in results[c]]
    y = [r['rho'] * 100 for r in results[c]]
    ax4.plot(x, y, marker='o', color=colors[i], label=labels[i])
ax4.axhline(y=80, color='red', linestyle='--', label='Порог деградации (80%)')
ax4.set_xlabel("Интенсивность запросов λ (зап/сек)")
ax4.set_ylabel("Загрузка серверов (%)")
ax4.legend()
ax4.grid(True)

plt.tight_layout()
plt.savefig("graphs.png", dpi=150)
plt.show()
print("\nГрафики сохранены в graphs.png")