Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 3.0.0 #2

Merged
merged 20 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading