Implementation of data warehousing by asynchronous Redis queues

Source: Internet
Author: User
Tags bulk insert hash log log php script


Business requirements


The app client sends the JSON data to the server interface once a day, emptying the cache and sending it again.


Business logic before a problem:

The PHP interface first converts JSON to an array to insert nonexistent data in a large table

The user already exists and the new ID

into a different table of particulars


The problem lies in:

When the user clears the cache due to special circumstances, the app sends the JSON string into the warehouse, causing the CPU to burst to 88% and remain high.



Optimization ideas:

1. Asynchronous Queue Processing

2, Redis filter (is only to deal with the first request of the day)

3. Redis Secondary Storage app name (after verification, bulk insert data in App Name table)

4, splicing insert and add as detailed table


Solution:

1, Interface modification Redis filter + such as List queue and deposit the result into Redis

First, Redis the previous historical data in the Redis hash. The Key name ID is the key value

<?php/** * Created by Haiyong.


* User:jia * DATE:2017/9/18 * time:20:06 * * namespace App\http\controllers\app;
Use App\http\controllers\controller;
Use Illuminate\http\request;
Use illuminate\support\facades\db;

Use Illuminate\support\facades\redis; Class Otherappcontroller extends controller{/** * App Application Statistics interface * @param Request $request * @return Strin G/Public Function apptotal (Request $request) {////Historical data warehousing//$redis = Redis::connection ('
        Web_active '); $app _name = db::connection (' Phplog ')->table (' App_set_name ')->where ("AppName", ' <> ', ')->lists ('
        Id ', ' appName ');
        $str = ';
        foreach ($app _name as $key => $val) {//$str. = "{$val} {$key}";
        }//$redis->hmset (' app_name ', $app _name);
        Echo $str, exit;
        $result = $request->input (' res ');
        $list = Json_decode ($result, true); if (Empty ($list) | |!is_array ($lIST)) {return Json_encode ([' Result ' => ' error ', ' msg ' => ' parameter error ')]; $data [' uid '] = isset ($list [' uid '])?
        $list [' uid ']: ' 20001 ';
        $data [' time '] = date (' y-m-d ');
        $redis _key = ' Log_app: '. $data [' time '];
        Redis Filter $redis = redis::connection (' web_active ');
            Redis key value expiration setting if (Empty ($redis->exists ($redis _key)) {$redis->hset ($redis _key, 1, ' Start '); $redis->expireat ($redis _key, Strtotime ($data [' time '].
        +2 Day '));  The//value determines if ($redis->hexists ($redis _key, $data [' uid ')]) {return Json_encode ([' Result ' =>
        ' SUCCESS ']);
            else {//push queue $redis->hset ($redis _key, $data [' uid '], $result); $redis->rpush (' log_app_list ', $data [' time ']. ':' .
            $data [' uid ']);
        return Json_encode ([' Result ' => ' SUCCESS ']);


 }
    }
}


2, PHP script loop monitoring Redis queue execution logic to prevent memory overflow

Mget returns null if the user's app ID does not exist

By judging null using the Redis new value as a self-increasing ID pointer to fill in MySQL and following the new Redis hash and pointer values and warehousing details table

<?php namespace App\console\commands;
Use Illuminate\console\command;
Use Illuminate\support\facades\redis;
Use illuminate\support\facades\db;

Use Illuminate\support\facades\storage;
     Class Apptotal extends Command {/** * The name and signature of the console command.

    * * @var string/protected $signature = ' apptotal:run ';
     /** * the console command description.

    * * @var String */protected $description = ' Command description ';
     /** * Create A new command instance.
    * * @return void */Public function __construct () {parent::__construct ();
     }/** * Execute the console command. * * @return Mixed */public function handle () {//Historical data warehousing//$redis = Redis::connectio  
        N (' web_active '); $app _name = db::connection (' Phplog ')->table (' App_set_name ')->where ("AppName", ' <> ', ')->lists ('  
        Id ', ' appName '); // $Redis->hmset (' app_name ', $app _name);  
          Exit
            while (1) {$redis = redis::connection (' web_active ');   
            Queue name $res = $redis->lpop (' log_app_list ');
            Switch button $lock = $redis->get (' Log_app_lock ');
                if (!empty ($res)) {list ($date, $uid) = Explode (': ', $res);
                $result = $redis->hget (' Log_app: '. $date, $uid);
                        if (!empty ($result)) {$table _name = ' app_total '. Date (' Ym ');
                        $list = Json_decode ($result, true); $data [' uid '] = isset ($list [' uid '])?
                        $list [' uid ']: ' 20001 '; $data [' sex '] = isset ($list [' sex '])?
                        $list [' Sex ']: '; $data [' device '] = isset ($list [' Device '])?
                        $list [' Device ']: '; $data [' applist '] = isset ($list [' list '])?
                        $list [' list ']: ';
          Data to flip is more performance-saving than unique              $data [' applist '] = Array_flip ($data [' applist ']);
                        $data [' applist '] = Array_flip ($data [' applist ']);
                        $data [' time '] = date (' y-m-d ');
                        App Application filter $app _res = $redis->hmget (' app_name ', $data [' applist ']);
                        New Add app array $new _app = [];
				        MySQL storage array $mysql _new_app = [];
				        Gets the current Redis pointer $total = $redis->get (' app_name_total ');
				                foreach ($app _res as $key =>& $val) {if (Is_null ($val)) {$total = 1; 
				                $new _app[$data [' applist '] [$key]] = $total;
				                $val = $total;
				            Array_push ($mysql _new_app,[' id ' => $total, ' appName ' => $data [' applist '] [$key]]); } if (count ($new _app)) {$str = INSERT IGNORE into app_set_name(id,appname) values ";
				        	foreach ($new _app as $key => $val) {$str. = "(. $val.", ' ". $key." '), ";
				        	$str = Trim ($str, ', ');
				        	$mysql _res = db::connection (' Phplog ')->table (' App_set_name ')->insert ($mysql _new_app);
						        $mysql _res = db::connection (' Phplog ')->statement ($STR);
						            if ($mysql _res) {//Set Redis pointer $redis->set (' app_name_total ', $total);
						        Redis Data Warehousing $redis->hmset (' app_name ', $new _app);
                        }//Details Data warehousing $data [' applist '] = implode (', ', $app _res); App stats warehousing db::connection (' Phplog ')->statement ("INSERT IGNORE into". $table _name. " (Uid,sex,device, ' time ', applist) VALUES (' ". $data [' uid ']." ', '. $data [' sex ']. $data [' Device ']. $data ['
                        Time ']. "', '". $data [' applist ']. "]);  Log log Generate memory error when file reaches 123MB all this place is using log cutting or not writing log Storage::d ISK (' local ')->append (Directory_separat OR. ' Total '.  Directory_separator ' LoaAppTotal.txt ', date (' y-m-d h:i:s '). ' Success '. $result. " 
				    \ n "); else {Storage::d ISK (' local ')->append (directory_separator. ' Total ').  Directory_separator ' LoaAppTotal.txt ', date (' y-m-d h:i:s '). ' Error '. $result. "
				    \ n ");
            }///Perform interval sleep (1);
            The end button if ($lock = = 2) {exit; }//Memory Detect if (Memory_get_usage () >1000*1024*1024) {exit (' memory overflow ');//greater than 100M memory exit program to prevent internal
 Save leak is killed by System cause task Terminal}}}



3, fixed Timing task monitoring script implementation

Crontab-e

/2 * * * * */bin/bash/usr/local/nginx/html/test.sh 1>>/usr/local/nginx/html/log.log 2>&1


test.sh content (view the process ID returned by the execution command if the command is not opened)

#!/bin/bash
Alive= ' Ps-ef | grep apptotal | Grep-v grep | awk ' {print $} '
if [! $alive]
Then
/usr/local/php/bin/php/var/ms/artisan apptotal:run >/dev/null &
Fi

Remember to authorize OH chmod +x test.sh


The author uses the Laravel framework to throw command activation into the background

Execute command

/usr/local/php/bin/php/var/ms/artisan apptotal:run >/dev/null &

It's done. Direct ctrl-c end on line command to run in the background you can view the process ID with commands in the shell


This enables the asynchronous storage of queues

There are many problems to be optimized. The general function has been implemented ...

Optimized CPU after completion



Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.