国产+高潮+在线,国产 av 仑乱内谢,www国产亚洲精品久久,51国产偷自视频区视频,成人午夜精品网站在线观看

PHP+MYSQL求一個高并發(fā)方案

longlong

問題描述

內(nèi)網(wǎng)http接口,高并發(fā),要求響應(yīng)在100ms內(nèi),單機需要支持5000+ QPS。
請求參數(shù)為訂單ID(數(shù)字int類型),業(yè)務(wù)邏輯為判斷本地數(shù)據(jù)庫中訂單是否存在,mysql大概100萬條記錄。
數(shù)據(jù)庫中訂單會隨時增加,每天增加幾百條。

服務(wù)器資源有限,越省資源越好。
php-fpm的框架都試過了,opcache全開最高也就200QPS左右,距離5000QPS相距甚遠(yuǎn)。
求一個高并發(fā)方案,現(xiàn)在打算用webman。redis能不用就不用。


用webman + bitmap完美解決 QPS 11萬+,性能遠(yuǎn)遠(yuǎn)遠(yuǎn)元超預(yù)期,webman神一般的存在,詳情見7樓回復(fù)。

5589 17 53
17個回答

Dalong

是我我就這樣試試:

public function existsxx(Request $request){
if(Redis::exists($request->get(''oid)){
return 1;
}
// 查詢庫
....
}

  • 暫無評論
roczyl

為啥不用redis?

  • 暫無評論
kspade

哥們我這幾天也是一樣的需求

固定每秒500 - 1000 請求,數(shù)據(jù)庫基礎(chǔ)數(shù)據(jù)30萬 數(shù)據(jù)庫每天新增幾千數(shù)據(jù)

請求來時判斷數(shù)據(jù)庫中是否存在數(shù)據(jù),數(shù)據(jù)內(nèi)容為:(34 - 64位字符串)

webman 群友給我的建議是將數(shù)據(jù)同步給redis,從redis中判斷(redis 理論每秒支持10萬+查詢并發(fā))

一些開發(fā)群給我的建議是上GO JAVA (當(dāng)然無視這些吊毛打心眼里看不起php)

nitron

人啊,要認(rèn)清現(xiàn)實,不要指著個正常的拖拉機要他跑出F1的速度
給結(jié)論,不想上各類緩存手段就堆硬件
MySQL查詢走PK基本是最快的了,select * from tbl where pk = ?數(shù)據(jù)庫查詢內(nèi)就幾ms,算上網(wǎng)絡(luò)消耗一來一回就二三十ms
我給你算個數(shù)據(jù)
FPM要5000qps,意味著1秒內(nèi)要創(chuàng)建/銷毀5000MySQL連接,問題在哪看到了么

  • 暫無評論
箜篌

想啥呢,高并發(fā)不上redis

  • 暫無評論
tanhongbin

直接查mysql 扛不住呀,redis 是最好的處理方案 bitmap 你可以嘗試一下,這個理論 最省redis內(nèi)存,然后入庫 還是用隊列最好,webman進(jìn)程多開一切,理論 5000qps 沒啥問題 ,最好是 webman 和 redis 在一個機器 他們直接通信基本能做3ms以內(nèi),你可以試試

  • longlong 2023-07-14

    壓測了下,走數(shù)據(jù)庫QPS能達(dá)到9000+了,就是cpu有點高,快80%了

  • TM 2023-07-14

    他的業(yè)務(wù)好像只需要判斷存在不存在,直接可以存redis里面判斷就可以了吧? 寫入和修改另外處理了

six

webman常駐內(nèi)存的,直接走webman內(nèi)存緩存數(shù)據(jù),數(shù)據(jù)不存在時再走mysql,我們試過,性能無敵,架構(gòu)也不用做什么改動。
代碼類似這樣,壓測試下

<?php
namespace app\controller;

use support\Db;
use support\Request;

class IndexController
{
    // 緩存的數(shù)據(jù)
    protected static $data = [];

    public function index(Request $request)
    {
        $id = $request->get('id');
        return json(['result' => static::get($id)]);
    }

    protected static function get($id)
    {
        // 初始化緩存
        if (!static::$data) {
            ini_set('memory_limit', '512M');
            static::$data = array_flip(Db::table('orders')->pluck('id')->toArray());
        }
        // 緩存不存在則查數(shù)據(jù)庫
        if (!isset(static::$data[$id])) {
            if (Db::table('orders')->find($id)) {
                // 訂單存在繼續(xù)緩存
                static::$data[$id] = 1;
                return true;
            }
            return false;
        }
        return true;
    }
}

這個方案就是有點費內(nèi)存,但是性能那是真的好,比redis緩存快好幾倍

  • nitron 2023-07-14

    有情提示,記得開啟控制器復(fù)用

  • six 2023-07-14

    用的static靜態(tài)變量,不用開控制器復(fù)用。當(dāng)然開了性能更高

  • tanhongbin 2023-07-14

    這種怎么說呢,就是有點耗費內(nèi)存,實際如果redis和webman 通信 內(nèi)網(wǎng) 基本還是redis bitmap比較好一個512M 的 key就夠用了 查詢是 (0)1,5000qps應(yīng)該問題不大

  • nitron 2023-07-14

    我單機應(yīng)用緩存基本實現(xiàn)跟你差不多,緩存不用Redis,直接用內(nèi)存

  • tanhongbin 2023-07-14

    問題是 你每個進(jìn)程 都得存全量數(shù)據(jù)了 100多萬呢,10個進(jìn)程 就相當(dāng)于內(nèi)存中存了1000萬數(shù)據(jù)呀,內(nèi)存估計占用很大

  • nitron 2023-07-14

    看情況,量大我存/dev/shm,多進(jìn)程共享,寫時加鎖

  • tanhongbin 2023-07-14

    這個很高級呀 ,沒用過 這個怎么寫??分享一下

  • longlong 2023-07-14

    截圖
    握了草,這個性能太爆表了,11W+ QPS,無以言表... 。就是有點占用內(nèi)存,每個進(jìn)程50M+

  • longlong 2023-07-14

    即使不命中緩存都走M(jìn)YSQL,QPS也有9000+ ...

  • nitron 2023-07-14

    其實就是文件緩存,但是文件是直接寫在內(nèi)存里,dev/shm你可以當(dāng)成RamDisk,因為是單機應(yīng)用,所以也不在乎
    主打一個簡單...

  • tanhongbin 2023-07-14

    怎么樣 webman 猛不猛?嚇一跳 吧 哈哈

  • nitron 2023-07-14

    單機應(yīng)用的前提下,APCu之類不走網(wǎng)絡(luò)的緩存方式其實比Redis快很多

  • tanhongbin 2023-07-14

    @longlong 之前沒用過webman框架嘛?

  • longlong 2023-07-14

    這性能沒得說,我在想怎么把內(nèi)存也降下去。內(nèi)存再降下去就是幾乎最完美的方案了。

  • longlong 2023-07-14

    我嘗試讓AI給我寫一個php版本的bitmap來解決

  • tanhongbin 2023-07-14

    你這想法不錯呀,哈哈

  • 稚出 2023-07-14

    既要..還要,不存在這種東西,要不就是時間換空間,要不就是空間換時間

  • TM 2023-07-14

    沒有又快又不占內(nèi)存吧,總要用一樣換取另一樣

  • longlong 2023-07-14

    讓官方的AI幫忙寫了個php版本的bitmap,完美解決內(nèi)存占用問題,現(xiàn)在每個進(jìn)程占用內(nèi)存28M+(相比主進(jìn)程就多了5M左右),可緩存1000萬訂單id。webman真是牛逼,webman的AI也牛逼...

    截圖

    代碼,各位參考下

    <?php
    namespace app\controller;
    
    use support\Db;
    use support\Request;
    
    class IndexController
    {
        protected static $bitmap;
    
        public function index(Request $request)
        {
            $id = $request->get('id');
            return json(['result' => static::get($id)]);
        }
    
        protected static function get($id)
        {
            if (!static::$bitmap) {
                static::$bitmap = new Bitmap(10000000);
                ini_set('memory_limit', '512M');
                $data = Db::table('orders')->pluck('id');
                foreach ($data as $order_id) {
                    static::$bitmap->set($order_id, 1);
                }
            }
            return static::$bitmap->get($id);
        }
    }
    
    class Bitmap {
    
        protected $bitmap;
    
        public function __construct($num) {
            $this->bitmap = str_repeat("\x00", ceil($num / 8));
        }
    
        public function set($num, $value) {
            $byteIndex = intval(($num - 1) / 8);
            $bitIndex = ($num - 1) % 8;
            $byte = ord($this->bitmap[$byteIndex]);
            if ($value) {
                $byte |= (1 << $bitIndex);
            } else {
                $byte &= ~(1 << $bitIndex);
            }
            $this->bitmap[$byteIndex] = chr($byte);
        }
    
        public function get($num) {
            $byteIndex = intval(($num - 1) / 8);
            $bitIndex = ($num - 1) % 8;
            $byte = ord($this->bitmap[$byteIndex]);
            return (($byte >> $bitIndex) & 1) == 1;
        }
    }
  • kspade 2023-07-14

    @longlong 有個問題 如果說訂單ID 換成 訂單號呢?bitmap 是不是不適用了 (34-64位長度的字符串)

  • tanhongbin 2023-07-14

    過長 就肯定不適用了,不過你可以用 布隆過濾器 ,讓ai幫你寫一個 php版本的布隆過濾器 一樣的

  • tanhongbin 2023-07-14

    @longlong 你現(xiàn)在這么寫 qps能有2W+ 嘛?

  • kspade 2023-07-14

    注意,使用BloomFilter擴展需要先安裝該擴展。你可以使用pecl命令來安裝擴展,例如pecl install BloomFilter。安裝完成后,你可以在PHP代碼中使用BloomFilter類。

    需要注意的是,布隆過濾器是一個概率型數(shù)據(jù)結(jié)構(gòu),因此在判斷元素是否存在時,可能會出現(xiàn)一定的誤判率。誤判率取決于過濾器的大小和哈希函數(shù)的數(shù)量。在使用布隆過濾器時,需要根據(jù)實際情況來選擇適當(dāng)?shù)倪^濾器大小和哈希函數(shù)數(shù)量,以平衡誤判率和空間效率的要求。

    這玩意有誤差啊

  • tanhongbin 2023-07-14

    其實 看量大小 ,如果量不是很大 ,可以redis 集合 是最簡單的,不要在集合中查詢 ,直接sadd 是最好的,這玩意效率高

  • longlong 2023-07-14

    @tanhongbin webman+bitmap 也是11W QPS

  • tanhongbin 2023-07-14

    這個有點猛呀,不過你新添加的數(shù)據(jù) 怎么往bitmap里面放呀?

  • longlong 2023-07-14

    不存在就讀下數(shù)據(jù)庫,然后set進(jìn)去,上面忘記寫了

  • tanhongbin 2023-07-14

    哦哦,方案可以 就是重啟 還得重新寫 ,寫一個系統(tǒng)重新啟動 ,直接把數(shù)據(jù)全寫進(jìn)去,就完美了,還有哪個查表 可以用省內(nèi)存方式的那種寫法

  • longlong 2023-07-14

    @kspade 字符串類型的訂單號沒辦法用bitmap,直接用 @six 的方案,30萬訂單占用50M內(nèi)存,完全可以接受。

  • kspade 2023-07-14

    @longlong
    有點沒看明白 上面@six 的方案 是否可以寫成一個公用的class ,然后再各個控制器方法中調(diào)用?
    還是說必須放在Controller 里面 protected static function get($id) 定義后調(diào)用

  • kspade 2023-07-14

    我覺得@six 的是不是最佳方案也應(yīng)該是在啟動項目時,把x表內(nèi)所有數(shù)據(jù)給緩存到內(nèi)存中去?

  • longlong 2023-07-14

    可以封裝成公共類,@six的方案就是第一次請求時從數(shù)據(jù)庫載入,也可以做成啟動時就緩存到內(nèi)存去。

  • tanhongbin 2023-07-14

    最好是 啟動就把數(shù)據(jù)緩存到內(nèi)存中 ,webman就能實現(xiàn),里面有一個隨著 進(jìn)程啟動執(zhí)行的類

  • kspade 2023-07-14

    config/bootstrap.php 學(xué)習(xí)了,我去實踐一下

  • kspade 2023-07-14

    // 初始化緩存
    if (!static::$data) {
    ini_set('memory_limit', '512M');
    static::$data = array_flip(Db::table('orders')->pluck('id')->toArray());
    }

    其中 Db::table('orders')->pluck('id')->toArray() 假設(shè)orders 表有100萬條數(shù)據(jù),這個語句應(yīng)該要耗時挺久吧?我用think 感覺不利索呢

  • Dalong 2023-07-15

    制器復(fù)用開跟不敢有啥區(qū)別?@six

  • longlong 2023-07-15

    @kspade 我這阿里云服務(wù)器,本地部署的mysql,100萬耗時1秒左右

  • 天天聊天 2023-12-05

    沒有能力只能默默敬佩

按照訂單后后綴做分表

  • nitron 2023-07-14

    你認(rèn)真的嗎?瓶頸在哪里你都沒弄清楚,才100萬的數(shù)據(jù)你給說說分表?

  • kspade 2023-07-14

    這個問題不是分表解決的。。。5000QPS每秒。。你分5000個表都沒用。 單MYSQL 鏈接 銷毀 都給你干嗝屁。。

  • longlong 2023-07-14

    php-fpm 每次請求都建立銷毀MYSQL鏈接,性能太低了,我機器上只有200QPS

pader

用 Wind Framework,你這每天幾百條數(shù)據(jù),單機 5000+ QPS 用這個框架,單個 HttpServer 進(jìn)程輕輕松松,我們每天處理百萬條數(shù)據(jù),單機兩個進(jìn)程輕輕松松。

  • 鄔綵唔惪 2023-07-17

    你們用wind Framework,用到不兼容的composer依賴,都是自己改造嘛?

happy321

用webman V5的協(xié)程+redis 輕輕松松幾十萬QPS

  • tanhongbin 2023-07-14

    這個協(xié)程 redis 為啥我用著干啥 和直接用redis 沒啥區(qū)別 ,性能 感覺是一樣的,因為redis足夠快呀

  • happy321 2023-07-14

    數(shù)據(jù)分塊 同時查

  • JackDx 2023-07-14

    有時間寫個demo嘛大佬~ 學(xué)習(xí)下

  • kspade 2023-07-14

    分享例子 攜程怎么玩的 我一直沒搞懂

  • tanhongbin 2023-07-14

    static public function httpRequest(string $url, string $method = 'GET', array $headers = [], array $data = [], bool $log = false) : string
    {
    $start_time = microtime(true);
    $options = [
    'max_conn_per_addr' => 128, // 每個域名最多維持多少并發(fā)連接
    'keepalive_timeout' => 15, // 連接多長時間不通訊就關(guān)閉
    'connect_timeout' => 30, // 連接超時時間
    'timeout' => 30, // 請求發(fā)出后等待響應(yīng)的超時時間
    ];
    $http = new Client($options);
    //$http = \support\Container::get('Workerman\Http\Client');
    $postData = in_array('application/json',$headers)?json_encode($data):$data;
    $response = $http->request($url, [
    'method' => $method,
    'version' => '1.1',
    'headers' => $headers,
    'data' => $postData,
    ]);
    $end_time = microtime(true);
    $res = $response->getBody()->getContents();
    $logStr = json_encode(['url' => $url,'method' => $method,'response' => json_decode($res),'time' => ($end_time - $start_time) . 's']);
    if($log) {
    //第三方請求日志
    Log::channel(self::$httplog)->info($logStr,$data);
    }
    return $res;
    }
    協(xié)程請求第三方接口的代碼

  • tanhongbin 2023-07-14

    前提是 composer "workerman/workerman": "v5.0.0-beta.5",
    "revolt/event-loop": "1.0.1",
    "workerman/http-client": "2.0.1",
    這三個包

  • nitron 2023-07-14

    我?guī)湍忝阑?/p>

    static public function httpRequest(string $url, string $method = 'GET', array $headers = [], array $data = [], bool $log = false) : string
    {
        $start_time = microtime(true);
        $options = [
            'max_conn_per_addr' => 128, // 每個域名最多維持多少并發(fā)連接
            'keepalive_timeout' => 15, // 連接多長時間不通訊就關(guān)閉
            'connect_timeout' => 30, // 連接超時時間
            'timeout' => 30, // 請求發(fā)出后等待響應(yīng)的超時時間
        ];
        $http = new Client($options);
        //$http = \support\Container::get('Workerman\Http\Client');
        $postData = in_array('application/json',$headers)?json_encode($data):$data;
        $response = $http->request($url, [
            'method' => $method,
            'version' => '1.1',
            'headers' => $headers,
            'data' => $postData,
        ]);
        $end_time = microtime(true);
        $res = $response->getBody()->getContents();
        $logStr = json_encode(['url' => $url,'method' => $method,'response' => json_decode($res),'time' => ($end_time - $start_time) . 's']);
        if($log) {
            //第三方請求日志
            Log::channel(self::$httplog)->info($logStr,$data);
        }
        return $res;
    }
  • tanhongbin 2023-07-14

    我這個協(xié)程 不一定正確 ,你們還是 自己實現(xiàn)最好 ,萬一不對 就坑人了

  • kspade 2023-07-15

    guzzle 好像自帶有?

  • tanhongbin 2023-07-17

    不是guzzle是workerman的http組件

  • xiaopi 2023-07-28

    老哥這個注釋了,是復(fù)用Client對象會出問題嗎?//$http = \support\Container::get('Workerman\Http\Client');

  • tanhongbin 2023-07-28

    不會 我為了測試 用的

oxiaohaio
/*
//生成100萬個文件
$start = microtime(true);
echo "wait for file creation... \r\n";
for($i = 1; $i < 1000000; $i++){
    file_put_contents('md5/' . md5($i), '');
}
$all_time = round((microtime(true) - $start) * 1000, 2);
echo $all_time . "all run time: $all_time ms \r\n";
//生成結(jié)束
*/

$start = microtime(true);
$query_num = 50000;
$s = md5(rand(1, 1000000)); 
for($i = 1; $i < $query_num; $i++){
    //$s = md5(rand(1, 1000000)); //放在這里隨機查找,會慢一些
    $check_file = 'md5/' . $s;
    //$rs =file_get_contents($check_file);
    $rs = file_exists($check_file);
}

//總計運行時間(ms)
$all_time = round((microtime(true) - $start) * 1000, 2);
//單次運行時間(ms)
$single_time = round($all_time / $query_num, 4);
//1秒鐘可以檢測次數(shù)
$one_second_check_num = floor(1000 / $single_time);

echo "query num: $query_num \r\n";
echo "all run time: $all_time ms \r\n";
echo "single run time: $single_time ms \r\n";
echo "one second check num: $one_second_check_num\r\n";

先建立一個md5文件夾,把注釋打開生成100萬條訂單數(shù)據(jù)
然后運行測試代碼 直接用文件檢測
截圖
單訂單號檢測和隨機訂單號檢測速度差距還是挺大的
但是可以滿足樓主的需求

Linux服務(wù)器上實測也差不多
截圖

  • 暫無評論
ontheway

你這個開了多少進(jìn)程?還有用的是什么軟件壓測的,我看你的壓測時間太短了

  • 暫無評論
胡桃
  1. 靜態(tài)變量保存bitmap,有兩大弊端。一、數(shù)據(jù)庫增刪時,需要及時更新維護(hù);二、消耗額外[bitmap容量*(子進(jìn)程數(shù)-1)]的內(nèi)存。
  2. Redis保存bitmap,也有兩個弊端,Redis運行需要內(nèi)存,并且與其通信的成本巨大。

使用共享內(nèi)存保存bitmap,既節(jié)省內(nèi)存,又無IO。
https://www.php.net/manual/zh/book.shmop.php

  • kspade 2023-07-15

    webman 上實踐過沒?

  • 胡桃 2023-07-15

    這東西早玩爛了,對于PHP來說,既要……又要……,這是唯一的辦法。

  • kspade 2023-07-15

    看了一下這個 如果要存入100萬數(shù)據(jù),還是很麻煩啊, 感覺就和tp的 cache 一樣

  • 胡桃 2023-07-15

    何來跟tp的cache一樣?shmop函數(shù)的唯一弊端是最小讀寫單元是8位,寫入時可能需要加鎖,但是鎖字節(jié)即可,粒度很小,按樓主所言每日增加幾百條,即使使用文件鎖也毫無性能問題。

  • nitron 2023-07-16

    單機應(yīng)用用shm的性能真不是redis可以比的

  • kspade 2023-07-16

    真羨慕你們懂那么多。我研究研究去,最近對這塊正好有需求,

  • tanhongbin 2023-07-17

    這玩意多思考,多想多測試啥都明白了

  • dignfei 2023-07-20

    共享內(nèi)存的缺點是需要序列化和反序列化, 這個難道不是最慢的嗎

kspade

求教
要怎么初始化 才可以在所有進(jìn)程的控制器方法中使用? 包括 redis 消費中 可以調(diào)用判斷是否存在

  • tanhongbin 2023-08-25

    多思考,多嘗試,多測試

  • 軟飯工程師 2023-08-25

    參考文檔http://wtbis.cn/doc/webman/others/bootstrap.html
    初始化定義

        public static function start($worker)
        {
            // Is it console environment ?
            $is_console = !$worker;
            if ($is_console) {
                // If you do not want to execute this in console, just return.
    //            return;
            }
            $userService = Container::get(UserService::class);
    
            $userService::$data = ['aaa', 'bbb', 'ccc'];
    
        }

    讀取初始化變量

        public function json(Request $request,UserService $userService)
        {
            return json(['code' => 0, 'msg' => 'ok', 'data' => $userService::$data]);
        }

    定義靜態(tài)變量

    class UserService
    {
        // 緩存的數(shù)據(jù)
        public static array $data = [];
    }

    測試結(jié)果

    mac-mini ~ %
    mac-mini ~ % curl http://127.0.0.1:8686/index/json
    {"code":0,"msg":"ok","data":["aaa","bbb","ccc"]}%
    mac-mini ~ %
  • xiaopi 2023-12-05

    我有個問題哈,這種寫法的話,對于新增或者刪除的數(shù)據(jù),無法跨進(jìn)程啊。 比如http開了8個進(jìn)程處理訂單號,自定義進(jìn)程4個用于處理新增/刪除的數(shù)據(jù),這種如何更新8個http進(jìn)程中的內(nèi)存數(shù)據(jù)呢。

muvtou

學(xué)習(xí)了

  • 暫無評論
dangpengsong

學(xué)習(xí)了

故人重來

學(xué)習(xí)了

  • 暫無評論
年代過于久遠(yuǎn),無法發(fā)表回答
??