アカウントを実行している調査:
- プラットフォームを監視することで、我々は多くの臨時のビューを推奨インターフェース遅延のリストが0.5秒以上であることがわかりました
- ユニットテストを書く、再現することはできません。テスト環境で再現することはできません。唯一の散発的なフォーマルな環境を再現することができます。
- 再現するために待機して、ログに埋もれ
- 継続的にログを追加した後埋葬発見は、Redisののhmget操作をしました
- それから私は、その理由を推測します
- hmgetコマンドがあります、それは問題のhmgetコマンドではありません
- スロークエリログRedisのビュー、および何の遅いクエリを見つかりませんでした。Redisのが遅い実装の理由を除外
- 現在の負荷を表示、負荷が低く、多くはない同時です。だから、Redisのは、待機の理由をコマンド除外
- マルチコルーチン、20 hmgetは、いないすべてのカードは、カードはほんの数は、それが正常に戻ってますでしょう
- Hmget通常の使用には、周りの0.01秒、カードに必要な0.3-0.9sです
- 自分のスクリプトを書く、hmgetを実行するために、マルチコルーチンを使用し続け、再現することはできません。
- ソリューションを推測:
- 3〜20、マルチコルーチンプールの数を変更します
- ユーザー情報を取得する代わりに、シリアル
- コードJiamaiポイントログ内のコマンドをhmgetを続行
- それは、サードパーティのライブラリを修正しているので、とても気をつけて
- ソースコードを読み取ることにより、基本的なプロセスhmgetは、クライアントファイルrediscluster機能EXECUTE_COMMAND内部のモジュールの中に発見されます
- 修正後は、何の問題の後、テスト対象のテスト環境ユニットは、正式な環境にデプロイ
- ()内にあることを最終的な位置決めをSelf.connection_pool.nodes.initializeするコード行を取ります
- refresh_table_asap = trueがソリューションので、このコード行を実行する場合にのみ
- なぜrefresh_table_asapはtrueに等しくなります
- 場合にのみ、エラーがRedisのClusterDownErrorまたはMovedErrorを接続するときは真refresh_table_asap =を設定することを発見
- ログに埋もれ。MovedErrorは異常によって引き起こされることが判明しました。
- 埋没ログを増加し続けると、全体のプロセスがトリガされることがわかりました。
- トリガー異常ConnectionError
- 設定しtry_random_node =真
- 次回は、ランダムなノードを取り、この時間は、間違ったノードのスロットを得ることができます
- ノードを接続した後、それは異常なMovedErrorが報告され、ターゲット・ノードに戻って情報を送信し、真refresh_table_asap =を設定します。
- この時点でスロットは背面にノード情報に対応するノードを設定します
- ノードを再接続し、成功したコマンドを実行します
- しかし、この時間が設定されているrefresh_table_asap = Trueの場合、次のコマンドを実行するときにself.connection_pool.nodes.initializeに実行されます()
- マルチコルーチン、およびself.connection_pool.nodes.initialize()コマンドの使用に起因するがロックされていない、それが増加し、時間がかかるにつながります
- 印刷トレースバックすることで、なぜ異常なトリガーConnectionError参照、Redisのサーバーが切断されました。
- この時点ではRedisのメカニズムがあることを思い出して、来て一定の時間をかけて指令がない、それは接続を閉じます。タイムアウト設定のRedis、通常は300秒で。これは散発的である理由だから、これは説明しています。
- 接続を確立した後、ユニットテストを記述し、コマンド待ち350S、安定的かつ再現性のあるバグを実行します。
- なぜそんなに遅いがかかり初期化
- 初期化コマンドが遅いではないテストによって、およそ0.04sを行うことができるよりも大きいが、マルチコルーチンは約0.5秒です。
- ないロックが存在しないので、コルーチン複数のこのコマンドが実行されるようにそのため、考慮すべきことは、元の10倍で最終結果と、、、マルチコルーチンであります
- Redisのは、テストケースを書いて、=の5Sをタイムアウトテスト環境を変更し、テスト環境で再現するために安定化させることができます。
- だから、rediscluster問題、解決策を見つけます
- 複数のRedisのコルーチン上でコマンドを実行しないでください(悪い感じ)
- 私は解決することができるかどうかを確認し、ライブラリをアップグレードします。このライブラリのgitのアドレス(閲覧https://github.com/Grokzen/redis-py-cluster)の最新バージョンを、問題がまだ存在しています。
- それはtry_random_node = trueの場合、再試行提供されない場合、サーバが切断されているかどうかを区別する場合catchConnectionError異常
- ロックされたときのinit
- 再接続するには切断サーバーの例外の再試行でキャッチの練習を参照することによりRedis.py
- 思考5の最終的な選択。
redisclusterライブラリclient.pyでEXECUTE_COMMAND機能(不要なコードセグメントを除去することをさらに含む、埋込みログ)
@clusterdown_wrapper デフEXECUTE_COMMAND(自己、* argsを、** kwargsから): 「」」 クラスタ内のノードにコマンドを送信します 「」」 インポートのログ ログイン= logging.getLogger( 'service.logに') log.error(u'redis EXECUTE_COMMAND 1%S '%のSTR(引数)) 外部から設定されている場合#我々は、任意のコマンドを呼び出す前に、それを更新する必要があります もしself.refresh_table_asap:self.connection_pool.nodes.initializeを行う#のコードセグメント()の log.error(u'redis EXECUTE_COMMAND 2%S '%のSTR(引数)) self.connection_pool.nodes.initialize() log.error(u'redis EXECUTE_COMMAND 3%S '%のSTR(引数)) self.refresh_table_asap =偽 log.error(u'redis EXECUTE_COMMAND 4%S '%のSTR(引数)) redirect_addr =なし = Falseを求めて try_random_node =偽 log.error(u'redis EXECUTE_COMMAND%S '%のSTR(引数)) スロット= self._determine_slot(*引数) log.error(u'redis EXECUTE_COMMAND 8%S '%のSTR(引数)) TTL = INT(self.RedisClusterRequestTTL) しばらくTTL> 0: TTL - = 1 求めている場合: ノード= self.connection_pool.nodes.nodes [redirect_addr] R = self.connection_pool.get_connection_by_node(ノード) elifのtry_random_node: R = self.connection_pool.get_random_connection() try_random_node =偽 他: self.refresh_table_asap場合: #MOVED ノード= self.connection_pool.get_master_node_by_slot(スロット) 他: ノード= self.connection_pool.get_node_by_slot(スロット) R = self.connection_pool.get_connection_by_node(ノード) 試してみてください。 r.send_command(*引数) log.error(u'redisはEXECUTE_COMMAND 10%S '%のSTR(引数)) RET = self.parse_response(R、コマンド、** kwargsから) log.error(u'redisはEXECUTE_COMMAND 11%S '%のSTR(引数)) 右を返します (RedisClusterException、BusyLoadingError)を除きます: 上げます (ConnectionError、TimeoutError)を除きます: try_random_node =真 log.error(u'redisはEXECUTE_COMMAND 14%S '%のSTR(引数)) TTL <self.RedisClusterRequestTTL / 2の場合: log.error(u'redisはEXECUTE_COMMAND 15%S '%のSTR(引数)) time.sleep(0.1) eとClusterDownError除きます: log.error(u'redisはEXECUTE_COMMAND 17%S '%のSTR(引数)) self.connection_pool.disconnect() self.connection_pool.reset() self.refresh_table_asap =真 上げ、 eとMovedError除きます: MovedErrorのこれまでのx個の#再初期化。 #このカウンタは速く増加したときに、同じクライアントオブジェクト #は、複数のスレッド間で共有されています。頻度を減らすために、あなた #は、コンストラクタで変数「reinitialize_steps」を設定することができます。 輸入トレースバック 印刷traceback.format_exc() log.error(u'redisはEXECUTE_COMMAND 16%S '%のSTR(引数)) self.refresh_table_asap =真 self.connection_pool.nodes.increment_reinitialize_counter() ノード= self.connection_pool.nodes.set_node(e.host、e.port、SERVER_TYPE = 'マスター') self.connection_pool.nodes.slots [e.slot_id] [0] =ノード
最適化:
ザ・
r.send_command(*引数) RET = self.parse_response(R、コマンド、** kwargsから) 右を返します
変更
試してみてください。 r.send_command(*引数) リターンself.parse_response(R、コマンド、** kwargsから) eとConnectionError除きます: redis.connectionインポートSERVER_CLOSED_CONNECTION_ERRORから e.messageでSERVER_CLOSED_CONNECTION_ERROR場合: r.disconnect() r.send_command(*引数) リターンself.parse_response(R、コマンド、** kwargsから) 他: 上げます
許可なしに、転載しないでください