рдЕрд▓рд╛рд╡рд░ рд╕рд╛рдЗрдЯреНрд╕ рдкрд░ рддрд╛рд▓реЗ рд▓рдЧрд╛рдирд╛

рдкрд░рд┐рдЪрдп

рдЖрдЬ рд╣рдо рддрд╛рд▓реЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реЗрдВрдЧреЗ рдФрд░ рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рджрд┐рдЦрд╛рдПрдВрдЧреЗред рдкреНрд░рддреНрдпреЗрдХ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЛ рдмрд╛рд░-рдмрд╛рд░ рдПрдХ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИ рдЬрдм рдХрд┐рд╕реА рд╕рдВрд╕рд╛рдзрди рдХреЗ рдПрдХрд▓-рдереНрд░реЗрдбреЗрдб рдЙрдкрдпреЛрдЧ рдХреЛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрддрд╛ рд╣реИред

рдЕрдХреНрд╕рд░, рдЗрд╕ рддрд░рд╣ рдХреЗ рд▓реЙрдХ рдХреЛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рдпреЛрдЬрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдлрд╝рд╛рдЗрд▓ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рд╕рд╛рде рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдПрдХ рд╕рдВрд╕рд╛рдзрди рдХреЗ рд░реЛрдЬрдЧрд╛рд░ рдХреЗ рддрдереНрдп рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреА рд╣реИред

рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рдХрдИ рдиреБрдХрд╕рд╛рди рд╣реИрдВред рдХрдорд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рдкрд╣рдЪрд╛рдирд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:

рдореБрдЭреЗ рдХрдм рддрд╛рд▓реЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ?

рд╣рд░ рдмрд╛рд░ рдЬрд╝рд░реВрд░рддреЗрдВ рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╣реЛрддреА рд╣реИрдВ, рдореВрд▓ рд░реВрдк рд╕реЗ рд╡реЗ рдПрдХ рд╕рд╛рде рджреЛрд╣рд░рд╛рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрддреЗ рд╣реИрдВ, рдХрд┐рд╕реА рддрд░рд╣ рдХреЗ рд╕рдВрд╕рд╛рдзрди рдХреЗ рд╕рд╛рде рд▓рдЧрд╛рддрд╛рд░ рдХрд╛рдо рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдПрдХ рд╕рдорд╛рди рднрд╛рд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВред

рдЗрд╕реЗ рд╕реНрд╡рдпрдВ рдХреИрд╕реЗ рдХрд░реЗрдВ?

рд╕рд╣реА рддрд╛рд▓реЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкрд░рдорд╛рдгреБрддрд╛ рдФрд░ рд▓реЗрди-рджреЗрди рдХреЗ рд╕рд┐рджреНрдзрд╛рдВрддреЛрдВ рдХреЛ рд╕рдордЭрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рдо рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдЙрдирдХрд╛ рд╡рд░реНрдгрди рдирд╣реАрдВ рдХрд░реЗрдВрдЧреЗ, рдХреНрдпреЛрдВрдХрд┐ рдЗрди рд╡рд┐рд╖рдпреЛрдВ рдкрд░ рдЗрдВрдЯрд░рдиреЗрдЯ рдкрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрд╣реБрдд рд╕рд╛рд░реА рдЬрд╛рдирдХрд╛рд░реА рдореМрдЬреВрдж рд╣реИред

рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рджреМрд░рд╛рди, рд╣рдордиреЗ рддрд╛рд▓реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╕рдордп рдмреБрдирд┐рдпрд╛рджреА рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдирд┐рд░реНрдзрд╛рд░рдг рдХрд┐рдпрд╛:

рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рдмрд╣реБрдд рдорд╣рддреНрд╡рдкреВрд░реНрдг рдирд╣реАрдВ рд╣реИ рдХрд┐ рд▓реЙрдХ рдкреНрд░реЛрд╡рд╛рдЗрдбрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдХреНрдпрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдпрд╣ рдлрд╛рдЗрд▓, mysql, memcache, рдпрд╛ рдЖрдкрдХреЗ рд▓рд┐рдП рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдХреЛрдИ рднреА рдЕрдиреНрдп рдЙрдкрдХрд░рдг рд╣реЛ рд╕рдХрддрд╛ рд╣реИред

рд░реЗрдбрд┐рд╕ рд╣рдорд╛рд░реЗ рдХрд░реАрдм рдерд╛, рдЗрд╕рд▓рд┐рдП рд╣рдордиреЗ рдЕрдкрдиреЗ рд▓реЙрдХ рддрдВрддреНрд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛, рдЬрд┐рд╕рдореЗрдВ рдКрдкрд░ рд╕реВрдЪреАрдмрджреНрдз рдХрдорд┐рдпрд╛рдВ рдирд╣реАрдВ рд╣реИрдВ, рд░реЗрдбрд┐рд╕ рдкрд░ред

рд╣рдорд╛рд░реЗ рд╕рд╛рде рддрд╛рд▓реЗ рдХреИрд╕реЗ рдмрдиреЗ рд╣реИрдВ

рдЖрдЬ рд╣рдо рдЖрдкрдХреЗ рд▓рд┐рдП "рдЬреИрд╕рд╛ рд╣реИ" рд▓рдЧрднрдЧ рд╣рд░ рд▓рд╛рдЗрди рдкрд░ рдЕрддрд┐рд░рд┐рдХреНрдд рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдФрд░ рдЙрдкрдпреЛрдЧ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкреЗрд╢ рдХрд░рддреЗ рд╣реИрдВред

рд╣рдорд╛рд░реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдЙрдкрдпреЛрдЧ Yii рдлреНрд░реЗрдорд╡рд░реНрдХ рдкрд░ рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ Rediska рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ Redis рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди Rediska рдХреА рддрд░рд╣ Yii рдореЗрдВ рдЯрд╛рдИ рдЫреЛрдЯреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдЗрд╕ рдХреЛрдб рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рд╕реА рднреА PHP рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рддреЛ, рдЪрд▓рд┐рдП рдордЬрд╝реЗрджрд╛рд░ рд╣рд┐рд╕реНрд╕реЗ рдкрд░ рдЖрддреЗ рд╣реИрдВ:

рдмреЗрд╕ рд▓реЙрдХ рдХреНрд▓рд╛рд╕
<?php /** *    * */ class Lock { /** *       * * @param string $key * @return string */ static protected function getKey( $key ) { return $key; } /** *  true,       * * @param string $key -   * @param float $timeWait -        * @param float $maxExecuteTime -       * @return bool */ static public function getLock( $key, $timeWait = 0, $maxExecuteTime = 3600 ) { throw new Lock_Exception('Not defined method getLock'); return false; } /** *     - * * @return string */ static protected function getCurrentProcessId() { static $myProcessId = false; if ( $myProcessId === false ) { $uname = posix_uname(); $mypid = getmypid(); $myProcessId = $uname['nodename'] . '_' . $mypid; } return $myProcessId; } /** *   * * @param string $key -   * @param float $delayAfter -          * @return bool */ static public function releaseLock( $key, $delayAfter = 0 ) { throw new Lock_Exception('Not defined method releaseLock'); return false; } /** *     * * @param string $key -   * @param float $timeProlongate -      * @return bool -   false,     */ static public function prolongate( $key, $timeProlongate ) { throw new Lock_Exception('Not defined method prolongate'); return false; } } class Lock_Exception extends Exception { } class Timeout_Lock_Exception extends Lock_Exception { } class LostLock_Timeout_Lock_Exception extends Timeout_Lock_Exception { } 

рдХрдХреНрд╖рд╛ рдлрд┐рд░ рд╕реЗ рдХрд░рдирд╛
рдЗрд╕ рд╡рд░реНрдЧ рдореЗрдВ, Redis рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рддрд╛рд▓реЗ рдмрдирд╛рдП рдЬрд╛рддреЗ рд╣реИрдВ:
 <?php /** *      Redis * */ class RedisLock extends Lock { /** *    noSQL  * * @param string $key * @return string */ static protected function getKey( $key ) { //   lock@      return 'lock@'.$key; } /** *  true,       * * @param string $key -   * @param float $timeWait -        * @param float $maxExecuteTime -       * @param integer $policy -   : * 0 -     ,      , * 1 -   10,    * @return bool */ static public function getLock( $key, $timeWait = 0, $maxExecuteTime = 3600, $policy = 0 ) { /** * ,     */ $timeStop = microtime(true) + $timeWait; //     Yii    Redis   Rediska $rediska = Yii::app()->rediskaConnection->connect(); while ( true ) { $currentTime = microtime(true); if ( $policy == 0 ) { /** *  ,     */ $expireAt = $rediska->getFromHash( self::getKey($key), 'expireAt' ); /** *  ,     ,     , *         */ if ( $expireAt > $timeStop ) { return false; } /** *     ,     ,    */ elseif ( $expireAt > $currentTime ) { usleep( 1000000 * intval($expireAt - $currentTime) ); $currentTime = microtime(true); } } elseif ( $policy == 1 ) { /** *  ,     */ $expireAt = $rediska->getFromHash( self::getKey($key), 'expireAt' ); while ( $expireAt > $timeStop || $expireAt > $currentTime ) { usleep( 10000 ); /** *  ,     */ $expireAt = $rediska->getFromHash( self::getKey($key), 'expireAt' ); $currentTime = microtime(true); if ( $currentTime >= $timeStop ) { return false; } } } $getLock = false; /** *     *  getConnectionByKeyName    ,      Redis */ $transaction = $rediska->transaction( $rediska->getConnectionByKeyName( self::getKey($key) ) ); $transaction->watch( self::getKey($key) ); $arData = $rediska->getHash( self::getKey($key) ); //     $daddy = isset($arData['daddy']) ? $arData['daddy'] : ''; //     $expireAt = isset($arData['expireAt']) ? $arData['expireAt'] : 0; /** *    ,     ,     *         */ if ( $daddy != self::getCurrentProcessId() && $expireAt < $currentTime ) { $transaction->setToHash( self::getKey($key), array( 'daddy' => self::getCurrentProcessId(), 'expireAt' => $currentTime + $maxExecuteTime ) ); $transaction->expire( self::getKey($key), ceil($currentTime + $maxExecuteTime), true ); try { $transaction->execute(); $getLock = 1; } catch ( Rediska_Transaction_Exception $e ) { /** *     */ $getLock = false; } } else { $getLock = false; $transaction->discard(); } /** *      */ if ( $getLock != 1 ) { // HSETNX $getLock = $rediska->setToHash( self::getKey($key), 'daddy', self::getCurrentProcessId(), false ); } /** *    */ if ( $getLock == 1 ) { /** *  ,     */ $rediska->setToHash(self::getKey($key), 'expireAt', $currentTime + $maxExecuteTime); $rediska->expire(self::getKey($key), ceil($currentTime + $maxExecuteTime), true); return true; } else { /** *       ,       */ if ( $timeStop > $currentTime ) { usleep(20000); } /** *  ,    */ else { return false; } } } } /** *   * * @param string $key -   * @param float $delayAfter -          * @return bool */ static public function releaseLock( $key, $delayAfter = 0 ) { $currentTime = microtime(true); $rediska = Yii::app()->rediskaConnection->connect(); $transaction = $rediska->transaction( $rediska->getConnectionByKeyName( self::getKey($key) ) ); $transaction->watch( self::getKey($key) ); $arData = $rediska->getHash( self::getKey($key) ); if ( is_array($arData) && isset($arData['daddy']) && isset($arData['expireAt']) ) { $daddy = $arData['daddy']; $expireAt = $arData['expireAt']; } else { $daddy = false; $expireAt = 0; } /** *          ,     */ if ( $daddy == self::getCurrentProcessId() ) { $transaction->setToHash(self::getKey($key), 'expireAt', $currentTime + $delayAfter); $transaction->expire(self::getKey($key), ceil($currentTime + $delayAfter), true); $transaction->deleteFromHash( self::getKey($key), 'daddy' ); /** *     */ try { $transaction->execute(); $result = true; } catch (Rediska_Transaction_Exception $e) { $result = false; } } else { $transaction->discard(); $result = false; } //       if ( $expireAt < $currentTime ) { if ( $result ) { /** *  ,     */ throw new Timeout_Lock_Exception('Timeout Lock on release'); } else { /** *       */ throw new LostLock_Timeout_Lock_Exception('Timeout Lock and it was lost before release'); } } return $result; } /** *     * * @param string $key -   * @param float $timeProlongate -      * @return bool -   false,     */ static public function prolongate( $key, $timeProlongate ) { $rediska = Yii::app()->rediskaConnection->connect(); $transaction = $rediska->transaction( $rediska->getConnectionByKeyName( self::getKey($key) ) ); $transaction->watch( self::getKey($key) ); $arData = $rediska->getHash( self::getKey($key) ); $daddy = $arData['daddy']; $expireAt = $arData['expireAt']; $currentTime = microtime(true); $result = false; if ( $daddy == self::getCurrentProcessId() ) { $transaction->setToHash( self::getKey($key), 'expireAt', $currentTime + $timeProlongate ); $transaction->expire(self::getKey($key), ceil($currentTime + $timeProlongate), true); try { $transaction->execute(); $result = true; } catch (Rediska_Transaction_Exception $e) { $result = false; } } else { $transaction->discard(); $result = false; } if ( $expireAt < $currentTime ) { if ( $result ) { throw new Timeout_Lock_Exception('Timeout Lock on prolongate'); } else { throw new LostLock_Timeout_Lock_Exception('Timeout Lock and Lost them on prolongate'); } } return $result; } } 

рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
рдорд╛рди рд▓реАрдЬрд┐рдП рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╣реИ рдЬреЛ рд░рд┐рдкреЛрд░реНрдЯ рддреИрдпрд╛рд░ рдХрд░рддреА рд╣реИред рдФрд░ рдЗрд╕ рд▓рд┐рдкрд┐ рдХрд╛ рдХрдИ рдзрд╛рдЧреЛрдВ рдореЗрдВ рдПрдХ рд╕рд╛рде рдЪрд▓рдиреЗ рдХрд╛ рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рд╡реЗ рд╕рднреА рдкрд░рд┐рдгрд╛рдо рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рд╣реА рдкрд░рд┐рдгрд╛рдо рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХрд░реЗрдВрдЧреЗ, рд▓реЗрдХрд┐рди рдкреНрд░рддреНрдпреЗрдХ рдХреЛ рдХрд╛рдо рдХреЗ рджреМрд░рд╛рди рдмрдбрд╝реА рдорд╛рддреНрд░рд╛ рдореЗрдВ рд╕рдВрд╕рд╛рдзрдиреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдФрд╕рддрди 40-50 рдорд┐рдирдЯ рдЪрд▓рддреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рдЕрдВрддрд░ рдХрд░реЗрдВ рдФрд░ 60 рдорд┐рдирдЯ рдХреЗ рд▓рд┐рдП рд▓реЙрдХ рд╕реЗрдЯ рдХрд░реЗрдВред
  $lockKey = 'cron-report'; $timeWait = 0; $timeLock = 3600; if ( RedisLock::getLock( $lockKey, $timeWait, $timeLock ) ) { //  ,     ... //          ,     try { RedisLock::releaseLock( $lockKey, 0 ); echo 'Ok'; } catch ( Timeout_Lock_Exception $e ) { //   //     ,      ,             echo 'Timeout_Lock_Exception ' . ( $endTime - $currentTime ); } catch ( LostLock_Timeout_Lock_Exception $e ) { //   //     ,      ,               echo 'LostLock_Timeout_Lock_Exception' . ( $endTime - $currentTime ); } } 

рд╣рдореЗрдВ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рд╣рдорд╛рд░рд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЖрдкрдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрдЧрд╛ред

рдЖрдкрдХреЗ рд╕рд╡рд╛рд▓реЛрдВ рдФрд░ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХрд╛ рдЗрдВрддрдЬрд╛рд░ рд░рд╣реЗрдЧрд╛ред

Source: https://habr.com/ru/post/In158799/


All Articles