Browse Source

Add Sw-Fw-Less v1.0 (#5046)

* add sw-fw-less

* fix mysql exception during travis test

* fix for travis

* fix for travis

* fix for travis

* fix for travis

* fix for travis

* fix for travis

* fix for travis

* fix for travis

* fix for travis

* remove useless files

* update readme & remove useless file

* modify for review

* modify for review

* retry travis

* modify for review

* modify for review

* modify for review

* modify for review
罗晓俊 6 years ago
parent
commit
a8413664af

+ 1 - 1
.travis.yml

@@ -102,7 +102,7 @@ env:
     - "TESTLANG=Perl"
     - 'TESTDIR="PHP/php"'
     - 'TESTDIR="PHP/cakephp PHP/codeigniter PHP/fat-free PHP/fuel PHP/kumbiaphp PHP/phpixie PHP/slim PHP/symfony PHP/yii2 PHP/zend"'
-    - 'TESTDIR="PHP/amp PHP/hamlet PHP/laravel PHP/lumen PHP/hhvm PHP/peachpie PHP/swoole PHP/workerman PHP/phalcon PHP/ubiquity PHP/hyperf"'
+    - 'TESTDIR="PHP/amp PHP/hamlet PHP/laravel PHP/lumen PHP/hhvm PHP/peachpie PHP/swoole PHP/workerman PHP/phalcon PHP/ubiquity PHP/hyperf PHP/sw-fw-less"'
     - 'TESTDIR="Python/aiohttp Python/api_hour Python/blacksheep Python/bottle Python/cherrypy Python/django Python/eve Python/falcon Python/fastapi Python/flask"'
     - 'TESTDIR="Python/hug Python/japronto Python/klein Python/morepath Python/pyramid Python/quart Python/responder Python/sanic Python/spyne Python/starlette"'
     - 'TESTDIR="Python/tornado Python/turbogears Python/uvicorn Python/uwsgi Python/vibora Python/web2py Python/webware Python/weppy Python/wsgi"'

+ 8 - 0
frameworks/PHP/sw-fw-less/.env

@@ -0,0 +1,8 @@
+## MySQL
+MYSQL_DSN="mysql:dbname=hello_world;host=tfb-database;port=3306"
+MYSQL_USERNAME=benchmarkdbuser
+MYSQL_PASSWD=benchmarkdbpass
+MYSQL_POOL_SIZE=10
+MYSQL_SWITCH=1
+MYSQL_POOL_CHANGE_EVENT=0
+MYSQL_REPORT_POOL_CHANGE=0

+ 6 - 0
frameworks/PHP/sw-fw-less/.gitignore

@@ -0,0 +1,6 @@
+/vendor/
+/.idea
+/.idea/
+/runtime
+/runtime/
+/composer.lock

+ 51 - 0
frameworks/PHP/sw-fw-less/README.md

@@ -0,0 +1,51 @@
+# [Sw-Fw-Less](https://github.com/luoxiaojun1992/sw-fw-less) Benchmarking Test
+
+This is the [Sw-Fw-Less](https://github.com/luoxiaojun1992/sw-fw-less) portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+
+* [JSON test source](app/services/TestService.php)
+
+### Plaintext Test
+
+* [Plaintext test source](app/services/TestService.php)
+
+### Data-Store/Database Mapping Test
+
+* [DB test controller](app/services/TestService.php)
+* [DB test model](app/models/World.php)
+
+### Fortunes Test
+* [Fortunes test controller](app/services/TestService.php)
+* [Fortunes test model](app/models/Fortune.php)
+
+
+## Infrastructure Software Versions
+The tests were run with:
+* [PHP 7.1](https://www.php.net/)
+* [Swoole v4.4.0](https://www.swoole.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost:9501/json
+
+### Plaintext Test
+
+http://localhost:9501/plaintext
+
+### Data-Store/Database Mapping Test
+
+http://localhost:9501/db
+
+### Variable Query Test
+
+http://localhost:9501/queries/2
+
+### Data Updates Test
+
+http://localhost:9501/updates/2
+
+### Fortunes Test
+
+http://localhost:9501/fortunes

+ 10 - 0
frameworks/PHP/sw-fw-less/app/models/Fortune.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace App\models;
+
+use SwFwLess\models\AbstractMysqlModel;
+
+class Fortune extends AbstractMysqlModel
+{
+    protected static $table = 'Fortune';
+}

+ 10 - 0
frameworks/PHP/sw-fw-less/app/models/World.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace App\models;
+
+use SwFwLess\models\AbstractMysqlModel;
+
+class World extends AbstractMysqlModel
+{
+    protected static $table = 'World';
+}

+ 121 - 0
frameworks/PHP/sw-fw-less/app/services/TestService.php

@@ -0,0 +1,121 @@
+<?php
+
+namespace App\services;
+
+use App\models\Fortune;
+use App\models\World;
+use SwFwLess\components\http\Response;
+use SwFwLess\services\BaseService;
+
+class TestService extends BaseService
+{
+    public function json()
+    {
+        return ['message' => 'Hello, World!'];
+    }
+
+    public function db()
+    {
+        $world = World::select()->cols(['*'])->where('`id` = :id')
+            ->bindValue(':id', random_int(1, 10000))
+            ->first();
+
+        return $world ? $world->toArray() : [];
+    }
+
+    public function queries($queries = 1)
+    {
+        $queries = $this->clamp($queries);
+
+        $rows = [];
+        while ($queries--) {
+            $row = World::select()->cols(['*'])->where('`id` = :id')
+                ->bindValue(':id', random_int(1, 10000))
+                ->first();
+            $rows[] = $row ? $row->toArray() : [];
+        }
+
+        return $rows;
+    }
+
+    public function fortunes()
+    {
+        $rows = Fortune::select()->cols(['*'])->get();
+
+        $insert = new Fortune();
+        $insert->id = 0;
+        $insert->message = 'Additional fortune added at request time.';
+
+        $rows[] = $insert;
+
+        usort($rows, function ($left, $right) {
+            return strcmp($left->message, $right->message);
+        });
+
+        return Response::output($this->renderFortunes($rows), 200, ['Content-Type' => 'text/html;charset=utf-8']);
+    }
+
+    private function renderFortunes($fortunes)
+    {
+        $html = <<<EOF
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body>
+<table>
+	<tr><th>id</th><th>message</th></tr>
+
+	%s
+</table>
+</body>
+</html>
+EOF;
+
+        $fortuneRows = '';
+        foreach ($fortunes as $fortune) {
+            $fortuneRows .= '	<tr><td>' . htmlspecialchars($fortune->id) .
+                '</td><td>' . htmlspecialchars($fortune->message) . '</td></tr>' . PHP_EOL;
+        }
+
+        return sprintf($html, $fortuneRows);
+    }
+
+    public function updates($queries = 1)
+    {
+        $queries = $this->clamp($queries);
+
+        $rows = [];
+
+        while ($queries--) {
+            $row = World::select()->cols(['*'])->where('`id` = :id')
+                ->bindValue(':id', random_int(1, 10000))
+                ->first();
+            if ($row) {
+                $row->randomNumber = random_int(1, 10000);
+                $row->save();
+
+                $rows[] = $row->toArray();
+            } else {
+                $rows[] = [];
+            }
+        }
+
+        return $rows;
+    }
+
+    public function plaintext()
+    {
+        return Response::output('Hello, World!', 200, ['Content-Type' => 'text/plain']);
+    }
+
+    private function clamp($value): int
+    {
+        if (! is_numeric($value) || $value < 1) {
+            return 1;
+        }
+        if ($value > 500) {
+            return 500;
+        }
+        return (int)$value;
+    }
+}

+ 30 - 0
frameworks/PHP/sw-fw-less/benchmark_config.json

@@ -0,0 +1,30 @@
+{
+    "framework": "sw-fw-less",
+    "tests": [
+        {
+            "default": {
+                "json_url": "/json",
+                "db_url": "/db",
+                "query_url": "/queries/",
+                "fortune_url": "/fortunes",
+                "update_url": "/updates/",
+                "plaintext_url": "/plaintext",
+                "port": 9501,
+                "approach": "Realistic",
+                "classification": "Micro",
+                "database": "MySQL",
+                "framework": "Sw-Fw-Less",
+                "language": "PHP",
+                "flavor": "None",
+                "orm": "Full",
+                "platform": "swoole",
+                "webserver": "None",
+                "os": "Linux",
+                "database_os": "Linux",
+                "display_name": "Sw-Fw-Less",
+                "notes": "",
+                "versus": "swoole"
+            }
+        }
+    ]
+}

+ 44 - 0
frameworks/PHP/sw-fw-less/composer.json

@@ -0,0 +1,44 @@
+{
+    "name": "luoxiaojun/sw-fw-less-app",
+    "description": "Swoole Http Server App",
+    "type": "project",
+    "keywords": [
+        "swoole",
+        "framework",
+        "coroutine",
+        "php",
+        "app"
+    ],
+    "require": {
+        "php": ">=7.1",
+        "ext-json": "*",
+        "ext-pdo": "*",
+        "ext-swoole": ">=4.4.0",
+        "luoxiaojun/sw-fw-less": "dev-master"
+    },
+    "suggest": {
+        "ext-redis": "*"
+    },
+    "license": "apache-2.0",
+    "authors": [
+        {
+            "name": "luoxiaojun",
+            "email": "[email protected]"
+        }
+    ],
+    "autoload": {
+        "psr-4": {"App\\": "app/"}
+    },
+    "scripts": {
+        "post-root-package-install": [
+            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
+        ]
+    },
+    "config": {
+        "sort-packages": true,
+        "optimize-autoloader": true,
+        "preferred-install": "dist"
+    },
+    "minimum-stability": "dev",
+    "prefer-stable": true
+}

+ 88 - 0
frameworks/PHP/sw-fw-less/config/app.php

@@ -0,0 +1,88 @@
+<?php
+
+return [
+    //Cors
+    'cors' => [
+        'origin' => env('CORS_ORIGIN', ''),
+        'switch' => envInt('CORS_SWITCH', 0),
+    ],
+
+    //Timezone
+    'timezone' => env('TIMEZONE', null),
+
+    //Monitor
+    'monitor' => [
+        'switch' => envInt('MONITOR_SWITCH', 0),
+    ],
+
+    //Throttle
+    'throttle' => [
+        'metric' => function(\SwFwLess\components\http\Request $request){
+            return $request->getRoute();
+        },
+        'period' => envInt('THROTTLE_PERIOD', 60),
+        'throttle' => envInt('THROTTLE_THROTTLE', 10000),
+    ],
+
+    //RedLock
+    'red_lock' => [
+        'connection' => env('RED_LOCK_CONNECTION', 'red_lock'),
+    ],
+
+    //RateLimit
+    'rate_limit' => [
+        'connection' => env('RATE_LIMIT_CONNECTION', 'rate_limit'),
+    ],
+
+    //Cache
+    'cache' => [
+        'connection' => env('CACHE_CONNECTION', 'cache'), //redis connection
+        'update_lock_ttl' => envInt('CACHE_UPDATE_LOCK_TTL', 10),
+    ],
+
+    //Hot Reload
+    'hot_reload' => [
+        'switch' => envInt('HOT_RELOAD_SWITCH', 0),
+        'watch_dirs' => [
+            __DIR__ . '/',
+            __DIR__ . '/../app/',
+            __DIR__ . '/../vendor/',
+            __DIR__ . '/../',
+        ],
+        'excluded_dirs' => [],
+        'watch_suffixes' => ['.php', '.env'],
+        'driver' => env('HOT_RELOAD_DRIVER', \Kwf\FileWatcher\Watcher::class), //HuangYi\Watcher\Watcher::class is another choice
+    ],
+
+    //Error handler
+    'error_handler' => [
+        'err_formatter' => function (\Throwable $e) {
+            return nl2br($e->getMessage() . PHP_EOL . $e->getTraceAsString());
+        },
+    ],
+
+    //Ip Restriction
+    'ip_restriction' => [
+        'ips' => env('IP_RESTRICTION_IPS'),
+        'api_prefix' => env('IP_RESTRICTION_API_PREFIX'),
+    ],
+
+    //Scheduler
+    'scheduler' => [
+//        [
+//            'schedule' => '* * * * *',
+//            'jobs' => function () {
+//                echo 'Every minute', PHP_EOL;
+//            },
+//        ],
+//        [
+//            'schedule' => '*/2 * * * *',
+//            'jobs' => function () {
+//                echo 'Every two minutes', PHP_EOL;
+//            },
+//        ],
+    ],
+
+    //You can turn off the switch to improve the performance
+    'route_di_switch' => envBool('ROUTE_DI_SWITCH', false),
+];

+ 6 - 0
frameworks/PHP/sw-fw-less/config/coroutine.php

@@ -0,0 +1,6 @@
+<?php
+
+return [
+    'enable_preemptive_scheduler' => envInt('COROUTINE_PREEMPTIVE_SCHEDULER', 0),
+    'hook_flags' => SWOOLE_HOOK_ALL,
+];

+ 40 - 0
frameworks/PHP/sw-fw-less/config/events.php

@@ -0,0 +1,40 @@
+<?php
+
+return [
+    \SwFwLess\components\redis\RedisPool::EVENT_REDIS_POOL_CHANGE => [
+        function (\Cake\Event\Event $event) {
+            $count = $event->getData('count');
+
+            if (\SwFwLess\components\Config::get('redis.report_pool_change')) {
+                \SwFwLess\components\swoole\counter\Counter::incr('monitor:pool:redis', $count);
+            }
+        },
+    ],
+    \SwFwLess\components\mysql\MysqlPool::EVENT_MYSQL_POOL_CHANGE => [
+        function (\Cake\Event\Event $event) {
+            $count = $event->getData('count');
+
+            if (\SwFwLess\components\Config::get('mysql.report_pool_change')) {
+                \SwFwLess\components\swoole\counter\Counter::incr('monitor:pool:mysql', $count);
+            }
+        },
+    ],
+    \SwFwLess\components\amqp\ConnectionPool::EVENT_AMQP_POOL_CHANGE => [
+        function (\Cake\Event\Event $event) {
+            $count = $event->getData('count');
+
+            if (\SwFwLess\components\Config::get('amqp.report_pool_change')) {
+                \SwFwLess\components\swoole\counter\Counter::incr('monitor:pool:amqp', $count);
+            }
+        },
+    ],
+    \SwFwLess\components\hbase\HbasePool::EVENT_HBASE_POOL_CHANGE => [
+        function (\Cake\Event\Event $event) {
+            $count = $event->getData('count');
+
+            if (\SwFwLess\components\Config::get('hbase.report_pool_change')) {
+                \SwFwLess\components\swoole\counter\Counter::incr('monitor:pool:hbase', $count);
+            }
+        },
+    ],
+];

+ 11 - 0
frameworks/PHP/sw-fw-less/config/log.php

@@ -0,0 +1,11 @@
+<?php
+
+return [
+    'path' => env('LOG_PATH', __DIR__ . '/../runtime/logs/app-{date}.log'),
+    'level' => envInt('LOG_LEVEL', \Monolog\Logger::DEBUG),
+    'pool_size' => envInt('LOG_POOL_SIZE', 100),
+    'buffer_max_size' => envInt('LOG_BUFFER_MAX_SIZE', 10),
+    'name' => env('LOG_NAME', 'sw-fw-less'),
+    'reserve_days' => envInt('LOG_RESERVE_DAYS', 3),
+    'switch' => envInt('LOG_SWITCH', 0),
+];

+ 18 - 0
frameworks/PHP/sw-fw-less/config/middleware.php

@@ -0,0 +1,18 @@
+<?php
+
+return [
+    'middleware' => [
+//        \SwFwLess\components\zipkin\Middleware::class,
+//        \SwFwLess\components\chaos\Middleware::class,
+//        \SwFwLess\middlewares\Cors::class,
+//        \SwFwLess\components\auth\Middleware::class,
+//        \SwFwLess\middlewares\IpRestriction::class,
+    ],
+    'routeMiddleware' => [
+//        \SwFwLess\components\ratelimit\Middleware::class,
+    ],
+    'aliases' => [
+        'cors' => \SwFwLess\middlewares\Cors::class,
+        'auth' => \SwFwLess\components\auth\Middleware::class,
+    ],
+];

+ 23 - 0
frameworks/PHP/sw-fw-less/config/mysql.php

@@ -0,0 +1,23 @@
+<?php
+
+return [
+    'default' => env('MYSQL_DEFAULT', 'default'),
+    'connections' => [
+        env('MYSQL_DEFAULT', 'default') => [
+            'dsn' => env('MYSQL_DSN', 'mysql:dbname=sw_test;host=127.0.0.1'),
+            'username' => env('MYSQL_USERNAME', 'root'),
+            'passwd' => env('MYSQL_PASSWD', null),
+            'options' => [
+                \PDO::ATTR_CASE => \PDO::CASE_NATURAL,
+                \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
+                \PDO::ATTR_ORACLE_NULLS => \PDO::NULL_NATURAL,
+                \PDO::ATTR_STRINGIFY_FETCHES => false,
+                \PDO::ATTR_EMULATE_PREPARES => false,
+            ],
+            'pool_size' => envInt('MYSQL_POOL_SIZE', 5),
+        ],
+    ],
+    'switch' => envInt('MYSQL_SWITCH', 0),
+    'pool_change_event' => envInt('MYSQL_POOL_CHANGE_EVENT', 0),
+    'report_pool_change' => envInt('MYSQL_REPORT_POOL_CHANGE', 0),
+];

+ 30 - 0
frameworks/PHP/sw-fw-less/config/providers.php

@@ -0,0 +1,30 @@
+<?php
+
+return [
+    //Common Providers
+    \SwFwLess\components\swoole\counter\CounterProvider::class,
+//    \SwFwLess\components\redis\RedisProvider::class,
+
+    //App Providers
+    \SwFwLess\components\swoole\SwooleProvider::class,
+//    \SwFwLess\components\chaos\ChaosProvider::class,
+
+    //Worker Providers
+    \SwFwLess\components\datetime\DatetimeProvider::class,
+    \SwFwLess\components\event\EventProvider::class,
+    \SwFwLess\components\log\LogProvider::class,
+//    \SwFwLess\components\ratelimit\RatelimitProvider::class,
+//    \SwFwLess\components\cache\CacheProvider::class,
+    \SwFwLess\components\mysql\MysqlProvider::class,
+//    \SwFwLess\components\es\EsProvider::class,
+//    \SwFwLess\components\storage\StorageProvider::class,
+//    \SwFwLess\components\amqp\AmqpProvider::class,
+//    \SwFwLess\components\hbase\HbaseProvider::class,
+    \SwFwLess\components\di\ContainerProvider::class,
+//    \SwFwLess\components\auth\jwt\JwtProvider::class,
+
+    //Request Providers
+
+    //Shutdown Providers
+    \SwFwLess\components\swoole\coresource\CoroutineResProvider::class,
+];

+ 15 - 0
frameworks/PHP/sw-fw-less/config/router.php

@@ -0,0 +1,15 @@
+<?php
+
+use App\services\TestService;
+
+return [
+    'single' => [
+        ['GET', '/json', [TestService::class, 'json']],
+        ['GET', '/db', [TestService::class, 'db']],
+        ['GET', '/queries/[{queries}]', [TestService::class, 'queries']],
+        ['GET', '/fortunes', [TestService::class, 'fortunes']],
+        ['GET', '/updates/[{queries}]', [TestService::class, 'updates']],
+        ['GET', '/plaintext', [TestService::class, 'plaintext']],
+    ],
+    'group' => [],
+];

+ 23 - 0
frameworks/PHP/sw-fw-less/config/server.php

@@ -0,0 +1,23 @@
+<?php
+
+$serverConfig = [
+    'host' => env('SERVER_HOST', '0.0.0.0'),
+    'port' => envInt('SERVER_PORT', 9501),
+    'worker_num' => envInt('SERVER_WORKER_NUM', swoole_cpu_num() * 2),
+    'daemonize' => envBool('SERVER_DAEMONIZE', false),
+    'backlog' => envInt('SERVER_BACKLOG', 128),
+    'max_request' => envInt('SERVER_MAX_REQUEST', 0),
+    'dispatch_mode' => envInt('SERVER_DISPATCH_MODE', 2),
+    'open_http2_protocol' => envBool('SERVER_OPEN_HTTP2', false),
+    'task_worker_num' => envInt('SERVER_TASK_WORKER_NUM', 0),
+    'task_enable_coroutine' => envBool('SERVER_TASK_ENABLE_COROUTINE', false),
+    'open_tcp_nodelay' => envBool('SERVER_OPEN_TCP_NODELAY', true),
+    'max_coroutine' => envInt('SERVER_MAX_COROUTINE', 1000000),
+    'socket_buffer_size' => envInt('SERVER_SOCKET_BUFFER_SIZE', 2 * 1024 * 1024),
+];
+
+if (!empty($pidFile = env('SERVER_PID_FILE'))) {
+    $serverConfig['pid_file'] = $pidFile;
+}
+
+return $serverConfig;

+ 12 - 0
frameworks/PHP/sw-fw-less/start.php

@@ -0,0 +1,12 @@
+<?php
+
+!defined('APP_BASE_PATH') && define('APP_BASE_PATH', __DIR__ . '/');
+
+if (extension_loaded('jsonnet')) {
+    !defined('CONFIG_FORMAT') && define('CONFIG_FORMAT', 'array,jsonnet');
+}
+
+require_once __DIR__ . '/vendor/autoload.php';
+
+//This app supports hot reload and shutdown triggered by SIGTERM
+(new \SwFwLess\bootstrap\App())->run();

+ 59 - 0
frameworks/PHP/sw-fw-less/sw-fw-less.dockerfile

@@ -0,0 +1,59 @@
+FROM php:7.1
+
+MAINTAINER luoxiaojun1992 <[email protected]>
+
+# Version
+ENV SWOOLE_VERSION v4.4.0
+
+# Libs
+RUN apt-get update -yqq \
+    && apt-get install -yqq \
+        curl wget git zip unzip less vim procps lsof tcpdump htop openssl \
+        libz-dev \
+        libssl-dev \
+        libnghttp2-dev \
+        libpcre3-dev \
+        libjpeg-dev \
+        libpng-dev \
+        libfreetype6-dev
+
+# Composer
+RUN curl -sS https://getcomposer.org/installer | php \
+    && mv composer.phar /usr/local/bin/composer \
+    && composer self-update --clean-backups
+
+# PDO extension
+RUN docker-php-ext-install pdo_mysql > /dev/null
+
+# Bcmath extension required by amqp composer package
+RUN docker-php-ext-install bcmath > /dev/null
+
+# Sockets extension
+RUN docker-php-ext-install sockets > /dev/null
+
+# Swoole extension
+RUN wget -q https://github.com/swoole/swoole-src/archive/${SWOOLE_VERSION}.tar.gz -O swoole.tar.gz \
+    && mkdir -p swoole \
+    && tar -xf swoole.tar.gz -C swoole --strip-components=1 \
+    && rm swoole.tar.gz \
+    && ( \
+        cd swoole \
+        && phpize \
+        && ./configure --enable-mysqlnd --quiet \
+        && make -j$(nproc) > /dev/null \
+        && make install > /dev/null \
+    ) \
+    && rm -r swoole \
+    && docker-php-ext-enable swoole > /dev/null
+
+ADD . /var/www/sw-fw-less
+
+WORKDIR /var/www/sw-fw-less
+
+RUN composer install --no-dev \
+    && composer dump-autoload -o \
+    && composer clearcache
+
+EXPOSE 9501
+
+ENTRYPOINT ["php", "/var/www/sw-fw-less/start.php"]