Skip to content

Commit

Permalink
Merge pull request #2 from denisyukphp/3.0.x
Browse files Browse the repository at this point in the history
  • Loading branch information
Aleksandr Denisyuk authored Jun 28, 2024
2 parents f21bcdc + 8808bce commit 1f7c3b1
Show file tree
Hide file tree
Showing 82 changed files with 2,063 additions and 1,807 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@
/psalm-baseline.xml export-ignore
/psalm.xml export-ignore
/tests/ export-ignore
/.Dockerfile export-ignore
/.Makefile export-ignore
24 changes: 4 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,68 +24,55 @@ jobs:
parallel-lint:
name: 'ParallelLint'
runs-on: 'ubuntu-latest'

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
php-version: '8.2'
coverage: none

- name: Install dependencies
uses: ramsey/composer-install@v2

- name: Run ParallelLint
run: composer parallel-lint -- --no-progress --ignore-fails

psalm:
name: 'Psalm'
runs-on: 'ubuntu-latest'

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
php-version: '8.2'
coverage: none

- name: Install dependencies
uses: ramsey/composer-install@v2

- name: Run Psalm
run: composer psalm -- --no-progress --no-cache --output-format=github

php-cs-fixer:
name: 'PHPCsFixer'
runs-on: 'ubuntu-latest'

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
php-version: '8.2'
coverage: none

- name: Install dependencies
uses: ramsey/composer-install@v2

- name: Run PHPCsFixer
run: composer php-cs-fixer:diff -- --no-interaction --using-cache=no

phpunit:
name: 'PHPUnit'
needs: ['parallel-lint', 'psalm', 'php-cs-fixer']
runs-on: ${{ matrix.operating-system }}

strategy:
fail-fast: false
matrix:
Expand All @@ -94,24 +81,21 @@ jobs:
- 'windows-latest'
php-version:
- '8.1'
- '8.2'
composer-dependency:
- 'lowest'
- 'highest'

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
coverage: none

- name: Install dependencies
uses: ramsey/composer-install@v2
with:
dependency-versions: ${{ matrix.composer-dependency }}

- name: Run PHPUnit
run: composer phpunit -- --no-interaction --do-not-cache-result
2 changes: 2 additions & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
->setRules([
'@Symfony' => true,
'@Symfony:risky' => true,
'phpdoc_separation' => false,
'phpdoc_to_comment' => false,
])
->setFinder($finder)
;
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM php:8.2-cli

RUN \
apt-get update ; \
apt-get install -y unzip ; \
pecl install pcov ; \
docker-php-ext-enable pcov ;

COPY --from=composer:2.4 /usr/bin/composer /usr/local/bin/composer

WORKDIR /usr/local/packages/throttler/
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2022 Orangesoft
Copyright (c) 2021 Orangesoft

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
init:
docker build -t throttler:8.2 ./

exec:
docker run --name throttler --rm --interactive --tty --volume ${PWD}:/usr/local/packages/throttler/ throttler:8.2 /bin/bash
79 changes: 50 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,59 @@ This package requires PHP 8.1 or later.

## Quick usage

Configure Throttler as below:
Configure `Orangesoft\Throttler\WeightedRoundRobinThrottler::class` as below and set weight for each node if you are using weighted strategy:

```php
<?php

use Orangesoft\Throttler\Counter\InMemoryCounter;
use Orangesoft\Throttler\Collection\NodeInterface;
use Orangesoft\Throttler\Collection\Node;
use Orangesoft\Throttler\Collection\Collection;
use Orangesoft\Throttler\Strategy\WeightedRoundRobinStrategy;
use Orangesoft\Throttler\Strategy\InMemoryCounter;
use Orangesoft\Throttler\Throttler;

$throttler = new Throttler(
new WeightedRoundRobinStrategy(
new InMemoryCounter(start: 0),
)
use Orangesoft\Throttler\WeightedRoundRobinThrottler;

$throttler = new WeightedRoundRobinThrottler(
new InMemoryCounter(),
);

$collection = new Collection([
new Node('node1', 5),
new Node('node2', 1),
new Node('node3', 1),
$collection = new InMemoryCollection([
new Node('192.168.0.1', 5),
new Node('192.168.0.2', 1),
new Node('192.168.0.3', 1),
]);

while (true) {
/** @var Node $node */
/** @var NodeInterface $node */
$node = $throttler->pick($collection);

// ...
}
```

Set weight for Node as the second argument in constructor if you are using weighted-strategies.
As a result, the throttler will go through all the nodes and return the appropriate one according to the chosen strategy as shown below:

```text
+---------+-------------+
| request | node |
+---------+-------------+
| 1 | 192.168.0.1 |
| 2 | 192.168.0.1 |
| 3 | 192.168.0.1 |
| 4 | 192.168.0.1 |
| 5 | 192.168.0.1 |
| 6 | 192.168.0.2 |
| 7 | 192.168.0.3 |
| n | etc. |
+---------+-------------+
```

The following throttlers are available:

- [Orangesoft\Throttler\RandomThrottler](./src/RandomThrottler.php)
- [Orangesoft\Throttler\WeightedRandomThrottler](./src/WeightedRandomThrottler.php)
- [Orangesoft\Throttler\FrequencyRandomThrottler](./src/FrequencyRandomThrottler.php)
- [Orangesoft\Throttler\RoundRobinThrottler](./src/RoundRobinThrottler.php)
- [Orangesoft\Throttler\WeightedRoundRobinThrottler](./src/WeightedRoundRobinThrottler.php)
- [Orangesoft\Throttler\SmoothWeightedRoundRobinThrottler](./src/SmoothWeightedRoundRobinThrottler.php)

## Benchmarks

Expand All @@ -61,25 +82,25 @@ Run `composer phpbench` to check out benchmarks:
+-------------------------------+------+-----+----------+----------+----------+---------+
| benchmark | revs | its | mean | best | worst | stdev |
+-------------------------------+------+-----+----------+----------+----------+---------+
| FrequencyRandomBench | 1000 | 5 | 6.074μs | 5.924μs | 6.242μs | 0.139μs |
| RandomBench | 1000 | 5 | 4.002μs | 3.880μs | 4.097μs | 0.073μs |
| RoundRobinBench | 1000 | 5 | 4.060μs | 3.888μs | 4.363μs | 0.171μs |
| SmoothWeightedRoundRobinBench | 1000 | 5 | 6.888μs | 6.707μs | 7.102μs | 0.130μs |
| WeightedRandomBench | 1000 | 5 | 11.660μs | 11.533μs | 11.797μs | 0.094μs |
| FrequencyRandomBench | 1000 | 5 | 6.074μs | 5.924μs | 6.242μs | 0.139μs |
| RoundRobinBench | 1000 | 5 | 4.060μs | 3.888μs | 4.363μs | 0.171μs |
| WeightedRoundRobinBench | 1000 | 5 | 10.778μs | 10.655μs | 10.919μs | 0.115μs |
| SmoothWeightedRoundRobinBench | 1000 | 5 | 6.888μs | 6.707μs | 7.102μs | 0.130μs |
+-------------------------------+------+-----+----------+----------+----------+---------+
```

The report is based on measuring the speed. Check `best` column to find out which strategy is the fastest. You can see that the fastest strategies are Random and RoundRobin.
The report is based on measuring the speed. Check `best` column to find out which strategy is the fastest.

## Documentation

- [Configure Throttler](docs/index.md#configure-throttler)
- [Available strategies](docs/index.md#available-strategies)
- [Sort nodes](docs/index.md#sort-nodes)
- [Keep counter](docs/index.md#keep-counter)
- [Serialize strategies](docs/index.md#serialize-strategies)
- [Dynamically change strategy](docs/index.md#dynamically-change-strategy)
- [Balance cluster](docs/index.md#balance-cluster)
- [Available strategies](./docs/index.md#available-strategies)
- [Keep states](./docs/index.md#keep-states)
- [Custom counter](./docs/index.md#custom-counter)
- [Custom strategy](./docs/index.md#custom-strategy)
- [Multiple throttler](./docs/index.md#multiple-throttler)
- [Balance cluster](./docs/index.md#balance-cluster)
- [Guzzle middleware](./docs/index.md#guzzle-middleware)

Read more about usage on [Orangesoft Tech](https://orangesoft.co/blog/how-to-make-proxy-balancing-in-guzzle).
Read more about load balancing on [Sam Rose's blog](https://samwho.dev/load-balancing/).
22 changes: 9 additions & 13 deletions benchmarks/FrequencyRandomBench.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,33 @@

namespace Orangesoft\Throttler\Benchmarks;

use Orangesoft\Throttler\Collection\Collection;
use Orangesoft\Throttler\Collection\CollectionInterface;
use Orangesoft\Throttler\Collection\InMemoryCollection;
use Orangesoft\Throttler\Collection\Node;
use Orangesoft\Throttler\Strategy\FrequencyRandomStrategy;
use Orangesoft\Throttler\Throttler;
use Orangesoft\Throttler\FrequencyRandomThrottler;
use Orangesoft\Throttler\ThrottlerInterface;

class FrequencyRandomBench
final class FrequencyRandomBench
{
private CollectionInterface $collection;
private ThrottlerInterface $throttler;

public function __construct()
{
$this->collection = new Collection([
new Node('node1'),
new Node('node2'),
new Node('node3'),
$this->collection = new InMemoryCollection([
new Node('192.168.0.1'),
new Node('192.168.0.2'),
new Node('192.168.0.3'),
]);

$this->throttler = new Throttler(
new FrequencyRandomStrategy(),
);
$this->throttler = new FrequencyRandomThrottler();
}

/**
* @Revs(1000)
*
* @Iterations(5)
*/
public function benchFrequencyRandom(): void
public function benchFrequencyRandomAlgorithm(): void
{
$this->throttler->pick($this->collection);
}
Expand Down
22 changes: 9 additions & 13 deletions benchmarks/RandomBench.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,33 @@

namespace Orangesoft\Throttler\Benchmarks;

use Orangesoft\Throttler\Collection\Collection;
use Orangesoft\Throttler\Collection\CollectionInterface;
use Orangesoft\Throttler\Collection\InMemoryCollection;
use Orangesoft\Throttler\Collection\Node;
use Orangesoft\Throttler\Strategy\RandomStrategy;
use Orangesoft\Throttler\Throttler;
use Orangesoft\Throttler\RandomThrottler;
use Orangesoft\Throttler\ThrottlerInterface;

class RandomBench
final class RandomBench
{
private CollectionInterface $collection;
private ThrottlerInterface $throttler;

public function __construct()
{
$this->collection = new Collection([
new Node('node1'),
new Node('node2'),
new Node('node3'),
$this->collection = new InMemoryCollection([
new Node('192.168.0.1'),
new Node('192.168.0.2'),
new Node('192.168.0.3'),
]);

$this->throttler = new Throttler(
new RandomStrategy(),
);
$this->throttler = new RandomThrottler();
}

/**
* @Revs(1000)
*
* @Iterations(5)
*/
public function benchRandom(): void
public function benchRandomAlgorithm(): void
{
$this->throttler->pick($this->collection);
}
Expand Down
26 changes: 10 additions & 16 deletions benchmarks/RoundRobinBench.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,34 @@

namespace Orangesoft\Throttler\Benchmarks;

use Orangesoft\Throttler\Collection\Collection;
use Orangesoft\Throttler\Collection\CollectionInterface;
use Orangesoft\Throttler\Collection\InMemoryCollection;
use Orangesoft\Throttler\Collection\Node;
use Orangesoft\Throttler\Strategy\InMemoryCounter;
use Orangesoft\Throttler\Strategy\RoundRobinStrategy;
use Orangesoft\Throttler\Throttler;
use Orangesoft\Throttler\Counter\InMemoryCounter;
use Orangesoft\Throttler\RoundRobinThrottler;
use Orangesoft\Throttler\ThrottlerInterface;

class RoundRobinBench
final class RoundRobinBench
{
private CollectionInterface $collection;
private ThrottlerInterface $throttler;

public function __construct()
{
$this->collection = new Collection([
new Node('node1'),
new Node('node2'),
new Node('node3'),
$this->collection = new InMemoryCollection([
new Node('192.168.0.1'),
new Node('192.168.0.2'),
new Node('192.168.0.3'),
]);

$this->throttler = new Throttler(
new RoundRobinStrategy(
new InMemoryCounter(start: 0),
)
);
$this->throttler = new RoundRobinThrottler(new InMemoryCounter());
}

/**
* @Revs(1000)
*
* @Iterations(5)
*/
public function benchRoundRobin(): void
public function benchRoundRobinAlgorithm(): void
{
$this->throttler->pick($this->collection);
}
Expand Down
Loading

0 comments on commit 1f7c3b1

Please sign in to comment.