2021年03月27日

Elasticsearchデータ修復

今回はelasticsearchのデータが破損してしまった場合(シングルノード)の修復方法について紹介します。簡易的なデータストレージとしてelasticsearchを使用する場合、クラスター化させずにシングルノードで使用する場合があります。データが冗長化されていないため、誤って電源断をしてしまった時やストレージに障害が発生した時にインデックスがred状態となってしまう場合があります。最悪のケースとしては.kibana_*等のElasticのシステム系インデックスがred状態になるとkibanaが起動できなくなり、開発consoleでコマンド操作といったkibanaの操作が一切できません。

重要なデータでない場合はred状態のindexを丸ごと削除するということが多いと思います。一方で重要でないが可能なら残っているデータを可能な限り復元、修復したいといった場合もあると思います。障害の種類によって修復方法が異なりますが、今回はtranslogの破損による障害の修復方法を紹介します。

translogの細かい説明はここではしませんが、負荷を分散させるためにインデックス内のデータを書き込む前にデータを一時保存するファイルです。translogの破損によってred状態となっている場合、一時保存された直近のデータは消える可能性があります。ただ、red状態で該当するインデックスのすべてのデータにアクセスできない、新規データ投入できない状態から回復したいという場合に有効です。

まずはブラウザやcurlコマンドで下記を実行し、red状態のノードを確認します。修復で使用するため、red状態となったインデックス名のUUIDも合わせて確認します。

続いて、ブラウザやcurlコマンドで下記を実行し、red状態の理由を確認します。

理由として表示された内容で下記の様にTranslog関連の障害が発生している場合は今回の方法で修復できます。unassigned_infoのdetailsにTranslogCorruptedExceptionと表示されており、translog関連の障害と分かります。TranslogCorruptedException以外にもtranslog整合性が合わないといった障害も同様に今回の方法で修復できます。

err_info.jpg


破損したtranslogファイル等を削除して新規に空のtranslogファイルを生成するために下記のコマンドを実行します。なお、ファイル操作を伴うため、elastcisearchを終了させた状態で実行します。また、破損ファイルを削除するため、必要に応じてdataフォルダのバックアップをしてください。インデックスに反映される前のtranslogにのみ記録された直近のデータは削除される場合があります。コマンドラインから下記のコマンドを実行します。

Elasticsearch7以降
bin/elasticsearch-shard remove-corrupted-data --index (インデックス名) --shard-id 0

Elasticsearch6以前
bin/elasticsearch-translog truncate -d (データフォルダ)/elasticsearch/data/nodes/0/indices/(UUID)/0/translog/

elasticsearch7以降の場合は下記のように表示され、translogの破損を発見した場合、修復の有無を聞いてきます。yキーを押して修復させます。

------------------------------------------------------------------------
WARNING: Elasticsearch MUST be stopped before running this tool.
-----------------------------------------------------------------------
Please make a complete backup of your index before using this tool.
-----------------------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
No problems were detected with this index.
Took 0.025 sec total.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> Translog is corrupted at \data\nodes\0\indices\~\0\translog
-----------------------------------------------------------------------
Documents inside of translog files will be lost.
The following files will be DELETED at \0\translog
--> translog-2_.tlog
--> translog.ckp
WARNING: YOU MAY LOSE DATA.
-----------------------------------------------------------------------
Continue and remove corrupted data from the shard ?
Confirm [y/N] y
Checking existing translog files
Reading translog UUID information from Lucene commit from shard at
Translog UUID :
History UUID :
Removing existing translog files
Creating new empty checkpoint at \translog\translog.ckp]
Creating new empty translog at [translog\translog-1.tlog]
Marking index with the new history uuid :
Changing allocation id to
You should run the following command to allocate this shard:
POST /_cluster/reroute
{
 "commands" : [
  {
   "allocate_stale_primary" : {
    "index" : "(インデックス名)",
    "shard" : 0,
    "node" : "(UUID)",
    "accept_data_loss" : false
   }
  }
 ]
}
You must accept the possibility of data loss by changing the `accept_data_loss` parameter to `true`.
上記は一部を書き換えています。

上記のコマンドだけでは修復したインデックスはred状態のままです。続いて、elasticsearchを起動させ、下記のコマンドを実行して再割り当てを行います。先ほどの修復コマンドの最後に表示されているように、accept_data_lossをtrueにしてcurlコマンドで下記のように実行すると再割り当てが行われ、red状態から回復します。

curl -XPOST localhost:9200/_cluster/reroute --header "Content-Type: application/json" --data "{\"commands\":[{\"allocate_stale_primary\":{\"index\":\"(インデックス名)\",\"shard\" : 0,\"node\" : \"(UUID)\",\"accept_data_loss\" : true}}]}"


再度、下記のコマンドで再割り当てされたノードを確認します。red状態から回復していれば修復完了です。

今回はelasticsearchのtranslog破損時の修復方法について紹介しました。elasticsearch-shard remove-corrupted-dataコマンドはtranslogの破損以外にも対応できるようで他の障害でも使えそうです。

もし、正常な状態のバックアップデータ(スナップショット)がある場合、邪道な方法ではありますが、該当するインデックスのtranslogファイルを丸ごと置き換える方法もあります。http://localhost:9200/_cat/indices?vでインデックス名とUUIDの関係を調べ、dataフォルダ内の該当するUUIDフォルダを見つけます。その中にtranslogフォルダがあり、同じUUIDの正常なtranslogフォルダを丸ごと置き換えます。translog自体の破損は修復できますが、インデックスデータとの整合性が合わない可能性が出てきます。ただ、この方法の場合、コマンド操作が不要なため、ダメ元で修復したい場合は作業として非常に楽になります。なお、当然ではありますが異なるUUIDのtranslogフォルダを置き換えた場合は整合性が取れないため、red状態のままです。
posted by Crescent at 00:00| Comment(0) | ナレッジ | このブログの読者になる | 更新情報をチェックする

2021年03月20日

USBホストMAX3421変換基板

USBホストICの比較検証のためにMAX3421E変換基板をAliexpressから購入してみました。以前に紹介したVinclumシリーズとの違いはどちら側に処理の中心を置くかの思想が違います。MAX3421はSPIスレーブICでUSBプロトコル変換に特化しており、動作の処理を命令するマイコンが別に必要となります。一方、VinclumシリーズはVinclum自体がプログラム可能なマイコンになっているため、用途によってはVinclum単体で動作させることが可能です。プロジェクトの目的によって使い分ける必要があります。部品コストとしてはVinculumは500円前後、MAX3421Eは1000円前後とVinculumの方が低コストです。

今回購入したAliexpressのMAX3421E変換基板は使う上で2点注意点が必要です。

@VBUS
基板上のVBUSは通常、USB電源として5Vを供給しますが、基板上で3.3VとVBUSが接続されているため、そのまま5Vを接続すると3.3Vラインにも5Vが供給されてしまいます。基板上のパターンを切って3.3Vラインと5Vラインを分離する必要があります。最初、誤ってそのまま5Vを供給してしまい、3.3V系の電圧がおかしいことに気づいて判明しました。今回は偶然?にもMAX3421E他、デバイスは壊れませんでしたが、注意が必要です。

max3421_1.jpg

ASPIシルク
基板上のシルクに間違いがあり、そのままマイコンと接続しても通信できません。基板上のMAX3421のICの足と基板上のピンをテスターで確認すると、基板上のCLKとMOSIが入れ替わっていることが分かりました。正しく配線することでMAX3421のレビジョンを正しく取得できるようになりました。


基板上のCLK→MOSIが正しい
基板上のMOSI→CLKが正しい
max3421_2.jpg


今後はVinculumとMAX3421を使いこなして、それぞれの特徴をまとめてみたいと思います。
posted by Crescent at 00:00| Comment(0) | 電子部品 | このブログの読者になる | 更新情報をチェックする

2021年03月13日

VinculumU SPIパフォーマンス

以前にFTDIのVinculumUを紹介しました。VinculumUはUSBホスト機能を備えたマイコンで最大2つのUSBポートを使用することができます。開発環境のVinculum II Toolchainを使用することで書き込むプログラムによって様々な機能のUSBホストを実現することが可能です。

今回はVinculumU を用いてSPIマスタのパフォーマンスを評価してみました。最終的にはUSBから取得したデータをVinculumU のSPIマスタを介して外付けメモリに転送することを検討しています。検討に際して想定よりもパフォーマンスが出ないことが分かったため、設定による違いをまとめてみました。

前提条件としてvos_initではVOS_Q=10、VOS_TICK=1、NUMBER_OF_DEVICES=4、VOS_48MHZ_CLOCK_FREQUENCY、VOS_IOCTL_SPI_MASTER_SET_DATA_DELAY=0で実験しています。また、CSとCLKを測定して1回のSPI通信サイクルを確認しました。

まず、DMAを無効化した状態で8byteのデータをSPIマスタから書き込む操作を行いました。

vos_dev_write(hSPI_MASTER, wcmd, 4, &num);
vos_dev_read(hSPI_MASTER, dummy, 4, &num);
vos_dev_write(hSPI_MASTER, data, 4, &num);
vos_dev_read(hSPI_MASTER, dummy, 4, &num);

■DMA未使用
VOS_IOCTL_COMMON_DISABLE_DMA、クロック3MHz

1_No_DMA_3MHz_8byte.png

黄色がCLK、赤がCSです。CSが0の期間は約820usecとなりました。1byte毎に分かれて送出されていることが分かります。また、各byte毎に50usec程度の間をおいてから次のbyteが送出されています。また、4byteの書き込み後、次の4byteを書き込むまでに200usec以上要していることが分かりました。

■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック3MHz
DMA転送を有効にしてDMAモードをDMA_ACQUIRE_AS_REQUIREDで同様に書き込みを行いました。

2_DMA_AS_3MHz_8byte.png

DMAを有効にすると1byte毎でなく、4byteまとめて送出されてるようになりました。CSが0の期間は約750usecとなりました。


■DMA使用DMA_ACQUIRE_AND_RETAINモード、クロック3MHz
DMAモードをDMA_ACQUIRE_AND_RETAINで同様に書き込みを行いました。

3_DMA_AND_3MHz_8byte.png

DMA_ACQUIRE_AND_RETAINモードでは4byteと次の4byteとの間隔が短くなり、CSが0の期間は約500usecとなりました。

■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック20MHz
SPI通信のクロックを上げてDMA_ACQUIRE_AS_REQUIREDモードで同様に書き込みを行いました。

4_DMA_AS_20MHz_8byte.png

クロックを上げると4byteと次の4byteとの間隔が短くなり、CSが0の期間は約380usecとなりました。

■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック20MHz、まとめて書き込み

4Byteを2回書き込みでなく、8byteを1回の書き込みに変更してみました。
vos_dev_write(hSPI_MASTER, data, 8, &num);
vos_dev_read(hSPI_MASTER, dummy, 8, &num);

5_DMA_AS_20MHz_8byteOnce.png

CSが0の期間は約200usecとなりました。

■DMA使用 DMA_ACQUIRE_AS_REQUIREDモード、クロック20MHz、まとめて書き込み、Writeのみ
VinculumUのSPIマスタは書き込み関数と読み込み関数がそれぞれ分かれています。通常は書き込み関数と読み込み関数の2つを使用してSPI通信の読み書きをします。書き込みのみの場合はvos_dev_write関数のみで構いませんが、読み込みの場合はvos_dev_write関数を実行してからvos_dev_read関数で値を読み込む必要があります。今回はメモリ書き込みのみを想定した場合、厳密には読み込み処理は不要です。書き込み関数のみにして同様に測定しました。

vos_dev_write(hSPI_MASTER, data, 8, &num);
//vos_dev_read(hSPI_MASTER, dummy, 8, &num);

6_DMA_AS_20MHz_8byteOnceWriteOnly.png

CSが0の期間は約100usecとなりました。

■結果まとめ
以上の結果からSPI通信を短時間で実行するためにはDMA転送の有効化、DMA_ACQUIRE_AS_REQUIREDよりもDMA_ACQUIRE_AND_RETAIN、クロックを高速にすることが重要であることが分かりました。また、vos_dev_write関数、vos_dev_read関数を細切れに呼び出すよりも分けずにまとめて呼び出すことが同様に短時間化に重要だと分かりました。

VinculumUは独自RTOSで実装されており、各処理の切り替え、関数呼び出しのオーバーヘッドが大きいようです。最後の結果でもCSが下がってからクロックが出るまで約40usec要しています。同様にクロックがで終わってからCSが上がるまでに約50usec要しています。VOS_Q、VOS_TICKの値を様々に変更してタイムスライスを小さくしても劇的な変化はありませんでした。VinculumU のSPIマスタは関数呼び出しのオーバーヘッドが非常に大きいことを考慮する必要があることが分かりました。

なお、今回の結果とは別に書き込みのみで書き込みデータを増やしてCSが0の区間を測定すると下記のような結果になりました。

書き込みデータ8byte192byte384byte512byte640byte800byte944byte
処理時間100usec200usec260usec310usec350usec410usec460usec

CS変化前後の処理オーバーヘッドの時間は変わらず、データ数の増加に合わせて処理時間が長くなる結果となりました。

これらのことからVinculumU のSPIマスタは高速な読み書き用途としてあまり向いていないことが分かりました。実装する際は関数呼び出しのオーバーヘッドを考慮してコーディングする必要があると分かりました。特にUSBのIsochronous転送の場合、最短1msecごとにデータが転送されます。少なくとも1msecより短い時間で1回の転送データを書き込む必要があり、SPI通信の処理速度が求められます。今後はIsochronous転送でどれくらいのデータ処理ができるか検討したいと思います。
posted by Crescent at 00:00| Comment(0) | 組込ソフト | このブログの読者になる | 更新情報をチェックする

2021年03月06日

Nuclei StudioとGD32FV103試食

Sipeed Longan Nanoの開発環境の構築と試食としてUARTの出力について紹介します。Sipeed Longan NanoはRISC-VベースのマイコンGD32VF103CBT6を搭載した評価基板です。マイコン以外にLED、OLEDディスプレイやSDカードスロットが搭載されて1000円弱とお手頃です。

longannano.jpg

Sipeed Longan Nanoの開発環境として、VisualStudioCode+PlatformIOの組み合わせで使用する場合がほとんどだと思います。一方で開発環境のバージョン差による影響を抑えたい場合や社内利用で追加パッケージを入れずらい、入れられないといった場合があると思います。そのような場合におすすめなのがNuclei Studioです。GD32VFマイコンのアーキテクチャを開発しているNuclei社が無償で提供しています。Eclipseベースの開発環境でWindowsやLinux向けのインストーラが準備されています。STM32マイコンのSW4STM32やSTM32CubeStudioを使用したことがある方ならそのまま同じような感覚で利用することができます。

nuclei_studio.jpg

Nuclei Studioはこちらの公式サイトからダウンロードしてください。Zipを解凍してNucleiStudio内のeclipse.exeをクリックするとNucleiStudioが起動します。開発環境にサンプルプログラムが含まれているため、今回はサンプルプログラムベースにGD32FV103を試食します。まず、File→New→C/C++ Projectを選択します。


nuclei_studio_1.jpg


C Managed Buildを選択します。

nuclei_studio_2.jpg



適当なProject名を設定します。ProjectTypeにはNuclei SDK Project For GD32VF103 Socを選択しました。

nuclei_studio_3.jpg


 Board選択はgd32vf103v_evalを選択しました。

nuclei_studio_4.jpg

いくつかサンプルが準備されていますが、baremetal_helloworldを選択しました。他の設定は必要に応じて選択します。例えば、printfでfloat出力する場合は下記の様に対応するNEWLIBを選択します。

nuclei_studio_5.jpg

以降の設定はデフォルトのまま、次に進め、Finishをクリックします。

nuclei_studio_6.jpg

nuclei_studio_7.jpg


今回のbaremetal_helloworldはMISA情報をprintf出力します。今回はprintfの出力先をuart0に出力させます。プロジェクトフォルダ内のnuclei_sdk→SoC→gd32vf103v_rvstar→Includeのnuclei_sdk_hal.hをクリックし、下記を書き換えます。

GD32_COM0
から
USART0
に設定します。

また、main.cのグローバル関数に下記を追加します。
void usart_init(void) {
 rcu_periph_clock_enable(RCU_USART0);
 rcu_periph_clock_enable(RCU_GPIOA);
 gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
 gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
 USART_BAUD(USART0) = (58 << 4) | (10 << 0); //115200bps@108MHz
 USART_CTL0(USART0) = USART_CTL0_TEN | USART_CTL0_REN;
 USART_CTL0(USART0) |= USART_CTL0_UEN;
}

main関数頭に
usart_init();
を追加します。

書き換えたコードを保存して、Ctrl+bでプロジェクトをビルドします。Debugフォルダ内にプロジェクト名.hexファイルができているはずです。

書き込みツールは「GD32 MCU Dfu Tool_vXXXX」をダウンロードします。ファイルを7Zip等で解凍し、フォルダ内のドライバGD32 MCU Dfu Drivers_vXXXX.exeをクリックし、ドライバをインストールします。

nuclei_studio_8.jpg

GD32 MCU Dfu Tool_vXXXフォルダ内のGD32 MCU Dfu Tool.exeをクリックし、書き込みツールを起動させます。アップデート有無を聞いてきますが、いいえを押して無視します。Sipeed Longan NanoとPCをUSBで接続し、BOOTボタンを押しながらリセットを1秒程度押してから離すと書き込みモードになります。スイッチのチャタリングなのか、書き込みモードに入っても書き込みに3回に1度ほど失敗します。そのような場合は再度、Resetボタンでリセットさせてから、書き込みモードにして書き込みを行います。認識するとDFU Deviceにデバイスが自動で「GD DFU Device1」といった表示がされます。

nuclei_studio_9.jpg

Download to Deviceにチェックを入れて、Openで先ほどのプロジェクトフォルダ内のDebugフォルダ、***.hexファイルを選択し、画面下のOKボタンを押すと書き込みが開始されます。100% Download successfully!が表示されれば書き込み完了です。Resetボタンを押すとコードが実行されます。

USBシリアル変換アダプタ等をSipeed Longan NanoのT0、GNDを配線してTeraterm等で開くと出力結果を確認できます。サンプルプログラムをベースに簡単にprintf出力することができました。J-tagのデバッガなしでも本体のみでUSB経由で書き込めるのは非常に楽だと思いました。今後はデバッガーを使ったデバッグ方法やSPI、I2C等のペリフェラル機能を使ってみたいと思います。

posted by Crescent at 00:00| Comment(2) | 電子工作 | このブログの読者になる | 更新情報をチェックする