カテゴリー: テクノロジー

WebTransportのサンプルを触ってみる。

「Google Chrome 97」のオリジントライアルに追加されたWebTransportを早速触ってみたいと思います。

WebTransportとは・・・。

WebTransport is a protocol framework that enables clients constrained by the Web security model to communicate with a remote server using a secure multiplexed transport.

https://chromestatus.com/feature/4854144902889472

WebTransportは、HTTP/3プロトコルを双方向トランスポートとして使用するWebAPIです。これは、WebクライアントとHTTP/3サーバー間の双方向通信を目的としています。データグラムAPIを介した信頼性の低いデータ送信と、ストリームAPIを介した信頼性の高いデータ送信の両方をサポートします。

https://web.dev/webtransport/

なんだかよく分かりませんが、HTTP/3を使用したすごい転送規格です。
双方向ですし、multiplexed-transport?かっこいいですね。

きっとブラウザOSが更に進化していくとか、ブラウザ上でゲームがネイティブアプリかのように動作するだとか、もうブラウザの意味が変わる時代が来るのかもしれません。

内容自体は難解かつ複雑ですが、今回はサンプルを触るだけですので何も考えずにやってみようと思います。

サーバー準備。

「WebTransportの実験」によると、現時点では、WebTransportはまだ公開されていません。
「試してみましょう」の項目にもありますが、HTTP/3サーバーをローカルで準備して起動する必要があるとのこと。

JavaScriptクライアントは、以下のURLに用意してくれています。
https://googlechrome.github.io/samples/webtransport/client.html

HTTP/3サーバーとは?
となったところで、GoogleChrome/samplesのgithubのスクリプトの中にコメントで、

An example WebTransport over HTTP/3 server based on the aioquic library. 

とありました。

aioquic。

aioquicを検索してみるとすぐ出てきたので、githubからcloneしてきます。
https://github.com/aiortc/aioquic/

導入は README の通りに進めます。

親切なことに、ブラウザの起動方法やオプションの説明、test/ ディレクトリの下に .pem ファイルまで用意されています。(独自証明書の場合のハッシュの生成コマンドもあります。)

Chromeもこれぐらいやって欲しい

また、aioquic/exapmplesにHTTP/3のテスト用サンプルが置いてあります。
試してみたところ、サーバー起動とHTTP/3のサンプルスクリプトは動作したのですが、クライアントからWebTransportの接続が上手くいきませんでした。深追いはしてませんが、バージョンアップで何か変わったのかもしれません。

HTTP/3のサンプル実行 – Ubuntu

ということで、元のGoogleChrome/samplesに戻ります。

Chromiumからアクセス。

cloneしてきたGoogleChome/samplesからサーバー用スクリプトを起動します。

mv samples/webtransport/webtransport_server.py aioquic/
python3 webtransport_server.py tests/ssl_cert.pem tests/ssl_key.pem 

aioquicの説明の通り、Chromiumをコマンドから起動します。

chromium --enable-experimental-web-platform-features --ignore-certificate-errors-spki-list=BSQJ0jkQ7wwhR7KvPZ+DSNk2XTZ/ MS6xCbo9qu++VdQ= --origin-to-force-quic-on=localhost:4433 https://localhost:4433/

上の方で紹介したJavaScriptクライアントを開きます。
https://googlechrome.github.io/samples/webtransport/client.html

画面にある「Connect」を押し、以下のように表示されると接続成功です。

Initiating connection...
Connection ready.
Datagram writer ready.
Datagram reader ready.

お疲れさまでした。

[Solr]ロギングについてのTips

動的にログレベルを変更する

管理画面から

Solrの管理画面 Logging → Level で Solr 稼働中にログレベルを変更できます。
特定のクラスのログ出力だけを変更することもできますし、rootを変更することで全体を変更することもできます。

APIで

以下のようにAPIを呼び出すことでログレベルを変更できます。

curl -s http://localhost:8983/solr/admin/info/logging --data-binary "set=root:WARN"

設定ファイルの場所を指定する

環境変数 LOG4J_PROPS で log4j2.xml の場所を指定します。

LOG4J_PROPS=/var/solr/log4j2.xml

ログの出力先を指定する

環境変数 SOLR_LOGS_DIR でログの出力先を指定します。

SOLR_LOGS_DIR=/var/solr/logs

日付ベースのログローテーションにする

log4j2.xml の MailLogFile の設定を以下のように変更します。

<RollingRandomAccessFile
    name="MainLogFile"
    fileName="${sys:solr.log.dir}/solr.log"
    filePattern="${sys:solr.log.dir}/solr.log.%d{yyyyMMdd}" >
  <PatternLayout>
    <Pattern>
      %maxLen{%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p (%t) [%X{collection} %X{shard} %X{replica} %X{core}] %c{1.} %m%notEmpty{\
 =>%ex{short}}}{10240}%n
    </Pattern>
  </PatternLayout>
  <Policies>
    <TimeBasedTriggeringPolicy interval="1"/>
  </Policies>
  <DefaultRolloverStrategy max="10"/>
</RollingRandomAccessFile>

TimeBasedTriggeringPolicy の interval=1 が1日単位という意味になるのは、filePattern に含まれる最小の単位が日だからです。filePattern に HH が含まれていれば interval=1 は1時間単位の意味になり、 mm が含まれていれば1分単位になります。

log4j2をアップデートする

Solr の配布物に含まれる log4j2 関連の jar ファイルは以下の通りです。

  • server/lib/ext/log4j-slf4j-impl-2.14.1.jar
  • server/lib/ext/log4j-layout-template-json-2.14.1.jar
  • server/lib/ext/log4j-core-2.14.1.jar
  • server/lib/ext/log4j-1.2-api-2.14.1.jar
  • server/lib/ext/log4j-api-2.14.1.jar
  • server/lib/ext/log4j-web-2.14.1.jar

log4j2 をアップデートするときはこれらのファイルを置き換えます。

prometheus-exporter を利用している場合は以下のファイルの置き換えも必要です。

  • contrib/prometheus-exporter/lib/log4j-slf4j-impl-2.14.1.jar
  • contrib/prometheus-exporter/lib/log4j-core-2.14.1.jar
  • contrib/prometheus-exporter/lib/log4j-api-2.14.1.jar

npm-scriptsでSCSSをコンパイルしてみよう!

sassをコンパイルする方法として、gulpを使っていますが、npm-scriptsが主流になってきています。npm-scriptsを使うメリットとして、記述がシンプルでバージョン依存が少なく共有がしやすいことが挙げられます。

今回はnpm-scriptsを使ってSass/Scssのコンパイルする方法についてまとめてみようと思います。

準備とSCSSをコンパイル

まずは任意のディレクトリにサンプルとして「sass_test」ディレクトリを作成し移動します。

mkdir sass_test
cd sass_test

今回使用するsassファイルを作成します。
ディレクトリは下記を想定しています。

sass_test
└resources
 └sass
  └style.scss
└dist
 └sass
  └style.css

「sass_test」の中でpackage.jsonを生成します。
「sass_test」に移動して、ターミナルで下記のコマンドを入力すると「package.json」が生成されます。
(質問は全てenterで大丈夫です)

npm init

sassのコンパイルとして、「Sass」をインストールします。

npm install sass --save-dev

package.jsonの「scripts」欄を次のように変更します。

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },

  "scripts": {
    "sass": "sass resources/sass/:dist/css/ --no-source-map --watch"
  },

sassをコンパイルするために下記を「sass_test」の階層で実行します。

npm run sass

「dist/css/」ディレクトリに「style.css」が生成されたと思います。
(終了するには[Ctrl + C]を押します。)
sassをコンパイルするのみならこれだけです。

自動でベンダープレフィックスを付与

自動でベンダープレフィックスを付与するために「autoprefixer」をインストールします。
合わせて「postcss」「postcss-cli」をインストールします。

npm install postcss postcss-cli autoprefixer --save-dev

複数のnpm-scriptsを実行するために「npm-run-all」をインストールします。

npm install npm-run-all --save-dev

ファイル変更の監視をするために「watch」をインストールします。

npm install watch --save-dev

package.jsonの「scripts」欄を次のように変更します。

  "scripts": {
    "all": "run-p watch",
    "watch": "watch 'run-s scss postcss' ./resources/sass",
    "scss": "sass resources/sass/:dist/css/ --no-source-map",
    "postcss": "postcss dist/css/style.css -o dist/css/style.css"
  },

pakcage.jsonと同じ階層に「postcss.config.js」を作成します。

module.exports = {
  plugins: [
    require('autoprefixer')()
  ]
}

そしてpakcage.jsonと同じ階層に「.browserslistrc」を作成します。
ブラウザリストはここで調整します。

last 2 versions
ie >= 11
Android >= 7

それではコンパイルしてみましょう。
「resources/sass/style.scss」に下記を記載します。

a{
  transition: 0.3s all;
  color: red;
  
  p{
    color: green;
  }
}

次にターミナルでpackage.jsonと同じ階層で下記を実行します。

npm run all

そうすると、「dist/css/style.css」に下記が出力されています。

a {
  -webkit-transition: 0.3s all;
  transition: 0.3s all;
  color: red;
}
a p {
  color: green;
}

無事にsassがベンダープレフィックスがついてコンパイルされていることが確認できました。
(終了するには[Ctrl + C]を押します。)

以上がnpm-scriptsを使ったsassのコンパイル方法をです。
読んでいただいた方の参考になればと思います!

[Solr]バックアップの置き場をS3にする

Solr には予め設定しておいたレポジトリにバックアップする機能があります。
レポジトリには以下の種類があります。

  • ローカルファイルシステム
  • HDFS
  • GCS(Google Cloud Storage)
  • Amazon S3

ここではローカルファイルシステムとS3の設定例を見てみます。

LocalFileSystemRepository

バックアップレポジトリの設定は solr.xml に書きます。

<backup>
  <repository name="local_repo" class="org.apache.solr.core.backup.repository.LocalFileSytemRepository">
    <str name="location">solr/backup_data</str>
  </repository>
</backup>

LocalFileSystemRepository の場合、設定項目は location だけです。

以下のようにAPIを利用してバックアップを実行した場合、Solr のインストールディレクトリを $SOLR_DIR とすると $SOLR_DIR/server/solr/backup_data/backup1 にコレクション backup_test のバックアップが作られます。

$ curl 'http://localhost:8983/solr/admin/collections?action=BACKUP&name=backup1&collection=backup_test&repository=local\
_repo'

S3BackupRepository

S3BackupRepository を使うためにはプラグインの設定が必要です。
$SOLR_DIR/server/solr/lib を作成し、dist/solr-s3-repository-8.10.0.jar と contrib/s3-repository/lib/*.jar をコピーして
solrconfig.xml に以下を追加します。

<lib dir="./lib" />                                                                                                     

レポジトリの設定はsolr.xmlに追加します。

<backup>
  <repository name="s3_repo" class="org.apache.solr.s3.S3BackupRepository" default="false">
    <str name="s3.bucket.name">XXXX.splout.co.jp</str>
    <str name="s3.region">us-west-2</str>
  </repository>
</backup>

s3.bucket.name でバケット名を、s3.region でリージョン名を指定します。
その他に S3 のエンドポイントを指定する s3.endpoint、プロキシを設定するための s3.proxy.url, s3.proxy.useSystemSettings \
があります。

上記の設定例の場合、以下のようにAPIを利用してバックアップを実行した場合、s3://XXX.splout.co.jp/backup2 にコレクション backup_test のバックアップが作られます。

$ curl 'http://localhost:8983/solr/admin/collections?action=BACKUP&name=backup2&collection=backup_test&repository=s3_re\
po'

[Solr]分散検索でどのレプリカに検索リクエストを送るのかを制御する

SolrCloud でシャードに複数のレプリカを作った場合、検索リクエストを処理する際にどのレプリカを優先するのかを shards.preference パラメータで指定できます。

以下の形式で優先順を指定します。
shards.preference=属性1:値1,属性2:値2,…
左側にあるものほど優先度が高くなります。

指定できる属性は以下の通りです。

replica.type

レプリカの種類(PULL, TLOG, NRT)を指定します

replica.location

http://hostname:port から始まる文字列でレプリカの場所を指定します。前方一致でレプリカを選びます。

特殊なケースとして “local” を指定した場合、リクエストを処理するサーバと同じサーバにある Solr インスタンスのレプリカが選ばれます。フィールド数が多い、巨大なフィールドがある、などの理由で検索結果のデータサイズが大きい場合に有効です。特定のレプリカに障害が発生した場合の影響範囲を小さくする効果もあります。

replica.base

優先順位が同じレプリカが存在するときに、それらの間でどれを優先するかを決めるためのルールを指定します。

  • random ランダムに1つ選びます
  • stable:dividend:パラメータ名 指定したパラメータに対応する整数値をレプリカ数で割った余りで決定します
  • stable[:hash[:パラメータ名]] 指定したパラメータに対応する文字列のハッシュ値をレプリカ数で割った余りで決定します。パラメータ名が指定されない場合はメインのクエリである q の値が使われます。

node.sysprop

指定したシステムプロパティの値が同じレプリカが選ばれます。
たとえば同じラックに属する Solr インスタンスが同じ rack プロパティの値を持つように -Drack=rack1 のように設定しておき、検索時に shards.preference=node.sysprop:sysprop.rack を指定すると、リクエストを処理している Solr インスタンスと同じ rack プロパティの値を持つ(=同じラックに属する)レプリカが選ばれます。

replica.leader

リーダーレプリカを優先するかどうかを true または false で指定します。たとえばレプリカが6台ある状態で replica.leader:false が指定されるとリーダー以外の5台が分散検索の対象となります。