読者です 読者をやめる 読者になる 読者になる

8t's BBR

よくつまったあれこれをメモ

phpでのファイルパスの定数宣言について

web系

phpでファイルパスを定数として定義しておく場合、例えば、

const JSON_PATH = "./sample.json";

とやりがちだったが、このやり方だと不具合を起こす場合がある。

この書き方をしたphpだけを実行する場合は問題なく動作するが、execなどで呼び出される際はディレクトリが違う場合うまく動作しない。
phpでは基本的に絶対パスで記述しておけば余計な不具合に頭を悩ませないで済むっぽいが、いくつもphpファイルがある場合、管理が面倒くさい。

この時に便利なのが__DIR__とかいうマジカル定数で、その記述があるファイルのディレクトリを表してくれるものだが、

const JSON_PATH = __DIR__.'./sample.json';

とするとphpのverが5.6以降でないと文法エラーと出てしまう。ver5.6より古いとconstによる定数宣言ではスカラー式は使えないからである。includeの時はこの記述の仕方で大丈夫だからややこしい。

というわけで長くなったが、この書き方をしたい場合は

define("JSON_PATH", __DIR__.'./sample.json');

とすれば解決。

Hadoopがjava8対応しそうな件

Hadoop

 
 
ついにHadoopがjava8の対応をしてくれそうってだけのエントリー。

 参照: Hadoop – Apache Hadoop 3.0.0-alpha1

8月末頃にHadoop3.0.0-alpha1が公開されたようです。
Hadoop-2.x系を使っていた身からするとついに来たかって感じで、3系の本リリースを待っていたんですが、ここ3ヶ月あまり大きな更新がなくα版のままです。


まだα版なので、
There are no guarantees regarding API stability or quality.
とドキュメントに書いてあるように「APIの安定性や品質に関する保証はありません」ので、気がはやいかもしれませんが、3系になって何が変わったか「日本語」で改めてまとめようかと思います。

java8の対応

何と言ってもメインはこれです。HadoopのJARがすべてJava8でコンパイルされました。
java8のアプリケーションを並行して使っていると、うまく動作しなかったのでありがたいです。
まぁまだしばらくはjava7対応のHadoop-2.x系を使うためにjavaのバージョンを切り替えながら使うことになりそうですが。

HDFSにおける消去エンコーディングのサポート

今までHDFSではレプリケーションを使ってデータの損失を防いできましたが、レプリケーション数の分だけストレージを消費していました。(例えば、レプリケーション数を3に設定した状態で、6ブロック分のデータをHDFSに保存しようとするとその3倍の18ブロック分消費していた。)
それに対して今回サポートする消去コーディング(EC)では1.4倍程度の消費で済むそうです。(つまり、先ほどの例では6*1.4=8.4よりせいぜい9ブロックの消費で済むようになるとのこと)

ストレージを節約できるというのは嬉しいニュースですね。

YARNタイムラインサービスver2(α版)登場

ver2ではスケーラビリティと信頼性を向上し、フローと集約を導入することで使いやすさを向上させたそうです。
ユーザーと開発者が、ver1系をすぐに置き換えてテストできるようにしてあるそうですが、セキュリティが有効になっていないとのことなので、テストする際には注意が必要です。

セキュリティが大事なものに対して扱いたい場合は、セキュリティが実装されるまで待ちましょう。
 

シェルスクリプトの書き換え

ほとんどの変更は互換性を保っているそうですが、一部の変更は既存のインストールを壊す可能性があるそうなので、詳しくはリリースノート[HADOOP-9902] Shell script rewrite - ASF JIRA

MapReduceタスクレベルネイティブ最適化

MapReduceがMap出力コレクタのネイティブ実装をサポート。シャッフルを多用するジョブでは、パフォーマンスが30%以上向上するらしい。
これも詳細についてはリリースノート[MAPREDUCE-2841] Task level native optimization - ASF JIRAを参照。

2つ以上のNameNodeのサポート

アクティブNameNodeとスタンバイNameNodeによるHDFSのNameNode高可用性の初期実装が提供されました。
つまり、ユーザーは複数のスタンバイNamenodeを実行できるようになりました。
また、3つのJournalNodeのクォーラムに編集内容を複製することで、システム内のいずれかのノードの障害に耐えることができます。

より高いフォールトトレランスが必要になった場合は、この新機能で対応可能になりました。例えば、3つのNameNodesと5つのJournalNodeを構成することで、クラスタは1つだけではなく2つのノードの障害に耐えることができるようになったそうです。

2つ以上のNameNodeを設定する方法については以下のドキュメントを参照とのこと。
Apache Hadoop 3.0.0-alpha1 – HDFS High Availability Using the Quorum Journal Manager


複数のサービスのデフォルトポートが変更

以前までは複数のHadoopサービスのデフォルトポートはLinuxの一時ポート範囲(32768-61000)にあり、別のアプリケーションと競合する場合、サービスを起動する際にポートにバインドできないことがありました。これらの競合するポートを変更し、先ほどの範囲外に移動したそうです。

NameNode、Secondary NameNode、DataNode、KMSが影響しており、ポート変更のリストが見たい方は、これもリリースノートを参照。
[HDFS-9427] HDFS should not default to ephemeral ports - ASF JIRA
[HADOOP-12811] Change kms server port number which conflicts with HMaster port number - ASF JIRA
 

Microsoft Azure Data Lakeファイルシステムコネクタのサポート

Hadoopは、代替のHadoop互換ファイルシステムとしてMicrosoft Azure Data Lakeとの統合をサポートするようになりました。

intra-DataNodeバランサの実装

1つのDataNodeが複数のディスクを管理できるようになります。

通常の書き込み操作では、ディスクは均等に塗りつぶされます。ただし、ディスクを追加または交換すると、DataNode内で大きなスキューが発生する可能性があります。
既存のHDFSバランサではこれを処理できなかったが、新しいintra-DataNodeバランシング機能によって処理されるようになったとのこと。

これも詳細は
Apache Hadoop 3.0.0-alpha1 – HDFS Commands Guide
のディスクバランサのセクションを参照。

Reworkedデーモンとタスクヒープ管理

HadoopデーモンやMapReduceタスクのヒープ管理に一連の変更。

HADOOP-10950:[HADOOP-10950] rework heap management vars - ASF JIRA
デーモンのヒープサイズを設定するための新しい方法が導入。 特に、ホストのメモリサイズに基づいてオートチューニングが可能になり、HADOOP_HEAPSIZE変数は推奨されなくなりました。

MAPREDUCE-5785:[MAPREDUCE-5785] Derive heap size or mapreduce.*.memory.mb automatically - ASF JIRA
マップの構成を簡素化し、タスク・ヒープ・サイズを縮小するため、タスク構成およびJavaオプションの両方で目的のヒープ・サイズを指定する必要がなくなりました。 すでに両方を指定している既存の設定はこの変更の影響を受けません。



後半はあまり意識してない部分なので、すごさがよくわかりませんでしたが、早くα、β版を終えて本リリースされることを切実に願っております。

sshで公開鍵を登録したのにsshできない

Hadoop server系

 
 

今年もポッキーの日がきましたね。
熱いカップルさんのキスを見ないように、ひきこもるのが一番だと思います。




・・・とまぁそれはさておき、
最近、新たにHadoopクラスタを組みなおすことになりました。

そんな訳でご新規なサーバーさんと仲良くしようと自己紹介して、友達になり、さぁこれで認証なしでssh接続できるはずやから確認しようーってしたらこれ。



Temporary failure in name resolution




俺「ふぁーーーーーーー」




状況整理

新たにHadoopクラスタを組みなおすにあたって、ご新規サーバー6台とご対面。
昔の記事を参考にしながら、それぞれのマシンがお互いにパスなしでSSH接続するための設定をする。
複数の仮想マシンを互いにSSHで接続 - 8t's BBR

大雑把に言えば、
 ① 公開鍵と秘密鍵をすべてのサーバーで作る
 ② 全サーバーの公開鍵をauthorized_keysに登録(もちろん全サーバーとも)
こんだけです。



・・・こんだけなのですが、
ご新規サーバー6台のうち3台は、ご新規サーバー⇒いつも使っているサーバー(以下ホスト)にsshしようとしても
Temporary failure in name resolution
っていうエラーがでる。

逆は大丈夫でした。また、ご新規さん同士は問題なくsshできる。



原因については後回しにして、とりあえず解決策を


解決策① /etc/hostsに接続できないサーバーを追加する

ムリヤリ感のある方法ですが、これが一番手っ取り早いかもしれません。
ホストにsshできないサーバーの/etc/hostsをいじります

sudo vim /etc/hosts

とでもしてやって、最後の方に

[ホストのIPアドレス] [ホスト名]

で追加するだけ


解決策② DNSサーバーを設定する

今後、他にサーバーを追加しないなら解決策①で問題ないけど、
そうでもないならこちらの方がいいかも

具体的には、/etc/resolv.confをいじります。
/etc/resolv.confとはなんぞやって人は以下を参照。
Linux初心者の基礎知識 - /etc/resolv.conf -

うまくいってなかったサーバーたちはこの中のnameserverが設定されていなかった。
最低でも、このnamesererをきちんと設定していれば大丈夫っぽい?けど、

 nameserver ネームサーバのIPアドレス
 domain     ドメイン名
 search     検索リスト

を設定しておけば、無事解決しました。

問題のあるサーバーのnameserverがわかりませんって人はお偉いさんに聞くか、解決策①を使ってください。



結局、原因は?

解決策②でも少し触れましたが、どうやらnameserverの設定がされていなかったからのようです。
failure in name resolution
って言われても仕方ないです。
DNSについては、あまり詳しく知らないのでぼろが出まくる前に、これが原因でしたよーっとだけ言っておきます。


やっぱこのあたりの分野は苦手かもしれない(致命傷)

githubでグループ開発するときの設定とか

git

グループ開発をする際にGithubを利用する時の最初の設定の仕方とか



大まかな流れはこんな感じ

①グループ用のgithubアカウントを作る
②レポジトリ作成
③collaborator追加    ←重要
④開発

 

①グループ用のgithubアカウントを作る

元からある場合はここの話は飛ばしてください。
ない場合は、https://github.com/にアクセスしてアカウントを作ってください。
すでに個人のアカウントを持っている人がアクセスするとマイページに飛ぶかもしれませんが、その場合はログアウトすればいけます。

作ったアカウントの
・ユーザー名
・メールアドレス
・パスワード
は大切に保管しましょう。


②レポジトリ作成

グループアカウントでレポジトリを作ります。
これは普通に[Create New Repository]で問題ありません。


③collaborator追加(重要)

今のままでは、個人のgithubアカウントで②のレポジトリをクローンしてソースいじってpush・・・はできません。
権限がないよー(403 ERROR)と言われます。

--------------------------------------------------------------------------------------------
追記:cloneではなくforkであれば、PullRequestは送れます。cloneする場合に以下のようにcollaboratorを設定する必要があります。個人的にはこの多少の手間を省いてforkするよりかはcloneでグループ開発した方が後々わかりやすいと思いますがどうなんでしょう・・・
--------------------------------------------------------------------------------------------


このままではプルリクベース開発がはかどりません。
全員がグループアカウントを使って開発するという手もあるかと思いますが、これでは誰のプルリクなのかとかがわかりづらくなるからです。
できることなら、個人のアカウントからプルリクを投げたい(そしてcontributeの証を手に入れたい)。

これを実現するには、グループアカウントでサインして、そのレポジトリのページに行き、collaboratorを追加します。
f:id:ykng0:20161025154436p:plain
この項目はもちろん外部アカウントでは表示されないので、グループアカウントでサインインするのを忘れないでください。
飛んだ先のページで一緒に開発する人のgithubをアカウントを登録すればそのアカウントでプルリクが投げれるようになります。


④開発

もうあなたの開発を邪魔するものはありません!
バリバリ頑張りましょう!

duコマンドでのオプションで表示される値の違い

豆知識

ディレクトリ内のファイル容量を調べるときによく使っていたduコマンドですが、いつもは適当に「あーこれくらいね、りょーかい」とか言っていたけど、ちゃんとわかっていなかった。


「duコマンドで[-b]オプションを指定した時と[-k]オプションを指定したときで表示される値が全然違くないか・・・?」

当たり前といえば当たり前なんだけど、変に迷走して悩みまくった話。



おそらくduコマンドの正しい定義は、ディレクトリのディスク使用量の表示」になるかと思います。


ポイントは「データサイズ」ではなくて「ディスク使用量」というところです。(なぜこの違いに早く気づかなかったのか・・)
つまり、特にオプションを指定しない場合は「そのディレクトリがどれだけディスクを喰っているのか」を表示するということです。



そして、[-b]オプションは「デフォルトのブロックサイズを無視して、バイト単位でサイズを表示する」といったものです。

前半が重要です。つまり、[-b]オプションを指定することで、「そのディレクトリがどれだけディスクを喰っているかバイト単位で表示する」のではなくて、「実際のデータサイズバイト単位で表示する」のです。


それに対して[-k]or[-m]オプションは「キロ(orメガ)バイト単位で表示する」だけです。



たとえば、700バイトのデータがあったとして、ディスクに書かれるときは4kBなどブロックサイズごとに書き込まれます。
ブロックサイズが4kBなら、10バイトのデータであっても3900バイトのデータであっても4kBの容量を使ってディスクに書き込まれます。





そら[-b]と[-k]オプションでは表示される値が違うよな・・・

【対策】基本情報技術者試験で出そうな頭字語【FE】

豆知識

ふと思い立って基本情報技術者試験を受けることになっていたのですが、
そろそろ対策しとかないと怖いぞと思って最近勉強していました。

何よりの心配は午前で知らない頭字語が出まくってどうしようもないパターン。
真面目に覚えようにもいろんなジャンルから出るので、ごちゃごちゃに・・・。


ってことで、今回は重要そうな頭字語をひたすら並べます。
深い説明までするときりがないので、簡単な補足説明だけ。
あと、網羅はさすがにできません。多すぎ。

あれ、これなんやったっけって時のカンニングに。

テクノロジ系

LIFO (Last In First Out) : 後入れ先出し。スタックはこれ。
FIFO (First In First Out) : 先入れ先出し。キューがこっち。
LRU (Least Recently Used) : 一番最後に参照されたものを追い出す。
LFU (Least Frequently Used) : 一番参照された数が少ないものを追い出す。

RISC (Reduced Instruction Set Computer) : 1つ1つの命令を簡単にしたもの。
CISC (Complex Instruction Set Computer) : 1つ1つの命令は複雑だが高機能。

CPI (Clock cycles Per Instructions) : 1命令あたり何クロック必要か
MIPS (Million Instructions Per Second) : 1秒に実行できる命令数。Millionなので100万単位。

ROM (Read Only Memory)
RAM (Random Access Memory)
DRAM (Dynamic RAM) : 主記憶装置に。リフレッシュ必要。メモリといったら基本これ。
SRAM (Static RAM) : キャッシュメモリに。フリップフロップ回路使ってる。
RAID : 複数のハードディスクを仮想的に1つにまとめる技術の代表例。

OSS (Open Source Software)
NFS (Network File System) : ネットワークを使って分散ファイルシステムを構築。

LAN (Local Area Network)
WAN (Wide Area Network)

--------------------------------[プロトコル]-----------------------------------------
HTTP (HyperText Transfer Protocolo)
HTTPS (HTTP over Secure) : HTTPを安全にしたもの。
FTP (File Transfer Protocol) : ファイル転送サービス。転送用と制御の2ポートもち。
SMTP (Simple Mail Transfer Protocol) : メール送信
POP (Post Office Protocol) : メール受信
NTP (Network Time Protocol) : コンピュータの時刻合わせ。
SNMP (Simple Network Management Protocol) : サーバーなどを監視・制御。2ポート有。
ARP (Address Resolution Protocol) : IPアドレスからMACアドレスを知る。
DHCP (Dynamic Host Configuration Protocol) : 動的にIPアドレスを割り当てる。
------------------------------------------------------------------------------------

CGI (Common Gateway Interface) : HTMLだけでは記述できない動的ページを作成。
MIME (Multipurpose Internet Mail Extension) : メールに画像とかファイルを添付する。
DNS (Domain Name System) : ドメイン名とIPアドレスの対応を管理。

SSL (Secure Socket Layer) : WWWやFTPなどのデータを暗号化して送受信する。
SPF (Secure Policy Framework) : 送信元をIPアドレスドメイン認証。なりすまし防止。


マネジメント系

RFI (Request For Information) : 情報提供依頼書。発注側がベンダ側に依頼。
RFP (Request For Proposal) : 提案依頼書。これも発注側がベンダ側に依頼。RFIの後に。

CASE : 開発支援ツール。上流(E-R図など)、下流(プログラミングやテストなど)がある。

PMBOK : 目標達成のための知識体系。
WBS (Work Breakdown Structure) : プロジェクトを細分化、トップダウンの階層図で表す。

SLA (Service Level Agreement) : サービスレベルを決める合意書
SLM (Service Level Management) : サービス水準の維持向上に努める活動のこと。
ITIL (Information Technology Information Library) : ITサービスの提供のベストプラクティス。

MTBF (Mean Time Between Failure) : 平均故障間隔
MTTR (Mean Time To Repair) : 平均修理時間

ストラテジ系

EC (Electronic Commerce) : 電子商取引
SWOT : 自社の現状をStrength,Weakness,Opportunity,Threatに分けて分析。
PPM (Product Portfolio Management) : 横軸にシェア、縦軸に市場成長率で分析

BPO (Business Process Outsourcing) : コアビシネスに集中。あとはアウトソーシング
BPM (Business Process Management) : ビシネスプロセスマネジメント
BPR (Business Process Re-engineering) : ビシネスプロセスをデザインし直す
SFA (Sales Force Automation) : 営業重視ってこと
PBP (Pay Back Period) : 投資がどれだけの期間で回収できるかを算定
SOA (Service Oriented Architecture) : 業務の一部をサービスとして実装。それらでシステム全体を構築。

ERP (P:政治,E:経済,S:社会,T:技術) : 業務情報を把握し、経営資源の最適化
SCM : サプライチェーンをネットワークで結び、チェーン全体を最適化
MRP (Material Requirements Planning) : 資材所要量計画。
EIP (Enterprise Information Portal) : 企業内情報ポータル
CSF (Critical Success Factors) : 主要成功要因
KPI (Key Performance Indicator) : 重要業績評価指標
KGI (Key Goal Indicator) : 重要目標評価指標
CSR (Corporative Quality Management) : 企業の社会的責任。
TQM (Total Quality Management) : 総合的品質経営。
BCP (Business Continuity Plan) : 災害などのリスク発生時に重要業務が中断しないこと
PTS法 : 各作業の正味時間を分析する方法の1つ
IFRS : 国際財務報告基準
NDA : 守秘契約

Springフレームワークでのクエリの書き方

web系

Spring JTA DATAを使ってクエリを書くことに最近挑戦していました。

まぁ初心者には難しい。
挫折寸前ですね。

Spring Data JPA の Specificationでらくらく動的クエリー - Qiita
この記事とかは非常に参考になるのですが、それでも頭パンクしていました。

で、今回の記事は技術的な話というよりかは、アイデア的な話で、
せっかく教えていただいたことを忘れないようにと、今回も備忘録として残します。



さて、先ほど紹介した記事では、
動的クエリを作成するにあたってSpecificationを利用しています。

Specificationは仕様という意味ですが、これの使い方とかよくわからなかった。
なので例えば、年齢や性別などの検索条件を満たすUserデータを全て取ってくる
findAllメソッドを書くとしたら、このような感じに愚直に書いていました。

public class UserService {

    public List<User> findUsers(String name, Integer id, Integer age, Boolean isMale) {
        return userRepository.findAll(Specifications
                .where(new Specification<User>() {
                    @Override
                    public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                        return cb.le(root.get("id"), 1000);
                    }})
                .and(new Specification<User>() {
                    @Override
                    public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                        return cb.ge(root.get("age"), 20);
                    }})
                .and(new Specification<User>() {
                    @Override
                    public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                        return cb.isTrue(root.get("isMale"));
                    }})
                .or(new Specification<User>() {}
                        :
                        :
}

それぞれのパラメータについて、1つ1つandやorを繋げていってます。これだと、
(id <= 1000) && (age >= 20) && isMale || (... )
というような感じの条件ですかね。



こんな感じでもできなくはないみたいです。
ただ、これだと困ることがあります。

  • 条件が複雑になった場合、andやorを使いすぎてごちゃごちゃに(そして混乱する)
  • やたらと長いコードになりやすい
  • 条件が少し変わるだけでも、下手に変えると大変なことに
  • 将来、この書き方だとfindByAgeとか色々メソッド作らなければ・・・

一番下の話については後程少し触れます。
一番上の話については、もうすでにそうなっていますね。
今ならまだ理解できますが条件A、B、C、・・・について
(A and B) and (C or { D ? E : F } )
ならどう書けばいいでしょうか。
やってみて即答できる人は決して多くないと信じています。
テストのしづらさもあって、私は実際にここで丸1日つぶしました。

答えの1つとしては、

public List<User> findUsers(String name, Integer age, Boolean isMale) {
    return userRepository.findAll(Specifications
        .where(new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                return cb.and(cb.le(root.get("id"), 1000), cb.ge(root.get("age"), 20));   // A and B
            }})
        .and(new Specification<User>() {
            @Override
            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                isMale  // D
                    ? return cb.or( /*C*/ , /*E*/ );
                    : return cb.or( /*C*/ , /*F*/ );
            }})
        );
}

的な感じのものがあります。(確認してないので、間違っていたらすみません。)
この解答でのポイントは、

  • Specificationをorで結ばない
  • CriteriaBuilderに頑張らせる

かと思っています。
特に上の意識は大事で、orは極力使わない方がいいと思います。
理由はやればわかります、下手すれば地獄を見ます。



正直なところ、これではベテランの方々に笑われるのでしょう。
せっかくのSpecificationの意味がなくね?(笑)と。
Specificationに名前をつけれるんだから、それで満たすべきSpecificationを定義して
それをandで繋げばいいじゃん、と。

ここでようやく、先ほどのページの話が更に輝きを放ってくれます。
Spring Data JPA の Specificationでらくらく動的クエリー - Qiita(再掲)
下のコードは丸パクリで恥ずかしいですが、コメントだけつけさせていただくと

// まずはSpecificationを定義
public Specification<User> nameContains(String name) {
        return StringUtils.isEmpty(name) ? null : (root, query, cb) -> {
            return cb.like(root.get("name"), "%" + name + "%");
        };
}
public Specification<User> emailContains(String email) {
            :
}
            :

// これで見た目もスッキリ。どういう仕様を満たせばいいかも一目でわかる。
public List<User> findUsers(String name, String email, Tag followTag, Long ContributionCount) {
    return userRepository.findAll(Specifications
        .where(nameContains(name))
        .and(emailContains(email))
        .and(flolowTagsHas(followTag))
        .and(contributionCountGreaterThan(Contribution))
    );
}

という感じになるのです。ここから先はもう本当によくわかってないので、
間違ったこと言ってるかもしれないですが、Specificationを定義するときに、
コードの例のようにしたり、Optional型を使うことで、条件に使う引数がnullでも
判定ができるようになったりするとか・・・。
それによって、findBy(なんとか)とかを何個もつくらなくてよくなるそうです。


なるほど、すごいですね(適当)。



※今回の記事は、いつにも増して特にうる覚えで書きました。
 専門の人なら「なんやこいつ。トンチンカンやな」と仰られるかもしれません。
 コードも間違っている可能性が大いにあります。
 どなたかの参考になれば幸いですが、ざっくり雰囲気だけにしていただくことをお勧めします。