投稿者: sumito.tsukada

  • BigQueryにbqコマンドでテーブル作成・スキーマ変更する

    BigQueryにbqコマンドでテーブル作成・スキーマ変更する

    はじめに

    BigQueryにbqコマンドでテーブル作成・データ投入・スキーマ変更する。 ネストされたデータも扱いたいので、今回はjsonファイルを読み込むようにする CSVは現段階でネストされたデータのimportをサポートされていない

    CSV ファイルはネストされたデータや繰り返しデータに対応していません。

    https://cloud.google.com/bigquery/docs/loading-data-cloud-storage-csv ちょうどいいサンプルデータ( https://gist.github.com/isdyy/5072792 )を置いてくださる方がいたので、それを拝借。

    準備

    https://gist.github.com/isdyy/5072792 にあるように2つのデータを用意する。1つはスキーマ。もう1つはデータ

    • スキーマ
      [
        {
          "name": "kind",
          "type": "string"
        },
        {
          "name": "fullName",
          "type": "string"
        },
        {
          "name": "age",
          "type": "integer"
        },
        {
          "name": "gender",
          "type": "string"
        },
        {
          "name": "citiesLived",
          "type": "record",
          "mode": "repeated",
          "fields": [
            {
              "name": "place",
              "type": "string"
            },
            {
              "name": "numberOfYears",
              "type": "integer"
            }
          ]
        },
        {
          "name": "note",
          "type": "string"
        }
      ]

       

    • データ
    {"gender": "Male", "fullName": "John Doe", "age": 22, "citiesLived": [{"numberOfYears": 5, "place": "Seattle"}, {"numberOfYears": 6, "place": "Stockholm"}], "kind": "person"}
    {"gender": "Female", "fullName": "Jane Austen", "age": 24, "citiesLived": [{"numberOfYears": 2, "place": "Los Angeles"}, {"numberOfYears": 2, "place": "Tokyo"}], "kind": "person"}
    {"note": "with newline (\\n)", "kind": "person", "gender": "Male", "age": 30, "fullName": "newline", "citiesLived": [{"place": "Shinjuku-ku,\nTokyo"}]}
    {"note": "with tab (\\t)", "age": 30, "fullName": "tab", "citiesLived": [{"place": "Shinjuku-ku,\tTokyo"}], "kind": "person"}
    {"note": "japanese / unicode escape sequence", "gender": "Female", "citiesLived": [{"place": "\u6a2a\u6d5c\u5e02"}], "fullName": "\u6a2a\u6d5c \u82b1\u5b50 (1)", "kind": "person"}
    {"note": "japanese / raw utf-8", "gender": "Female", "citiesLived": [{"place": "横浜市"}], "fullName": "横浜 花子 (2)", "kind": "person"}
    {"note": "double-quoted string", "fullName": "\"quoted\"", "kind": "person"}

    テーブルのみ作成

    # bq mk --table logs.sample nested01.fields.json
    Table '****:logs.sample' successfully created.

    ブラウザ上で以下の通り作成されている また、bq showコマンドでスキーマを確認できる

    # bq show logs.sample 
    Table ****:logs.sample
    
       Last modified                 Schema                 Total Rows   Total Bytes   Expiration   Time Partitioning   Labels  
     ----------------- ----------------------------------- ------------ ------------- ------------ ------------------- -------- 
      19 Nov 21:09:54   |- kind: string                     0            0                                                      
                        |- fullName: string                                                                                     
                        |- age: integer                                                                                         
                        |- gender: string                                                                                       
                        +- citiesLived: record (repeated)                                                                       
                        |  |- place: string                                                                                     
                        |  |- numberOfYears: integer                                                                            
                        |- note: string  

    データの投入

    # bq load --source_format=NEWLINE_DELIMITED_JSON logs.sample nested01.data.json  
    Upload complete.
    Waiting on bqjob_r4b711f3cb6f6854b_000001672be52e12_1 ... (0s) Current status: DONE  

    無事投入された。適切にネストもされている。

    テーブル作成+データ投入

    スキーマ作成と同時に、データの投入も可能

    # bq load --source_format=NEWLINE_DELIMITED_JSON logs.sample nested01.data.json nested01.fields.json
    Upload complete.
    Waiting on bqjob_r49704f78c779ebd5_000001672bd96baa_1 ... (0s) Current status: DONE  

    もちろん結果は同じ

    データのみをつかって、テーブルを自動作成

    “` –autodetect “` オプションを使う。

    # bq load --source_format=NEWLINE_DELIMITED_JSON --autodetect  logs.sample nested01.data.json
    Upload complete.
    Waiting on bqjob_r49704f78c779ebd115_00001672bd96baa_1 ... (0s) Current status: DONE  

    スキーマを変更する

    nested01.fields.jsonを以下の通り変更

    [
      {
        "name": "kind",
        "type": "string"
      },
      {
        "name": "fullName",
        "type": "string"
      },
      {
        "name": "age",
        "type": "integer"
      },
      {
        "name": "gender",
        "type": "string"
      },
      {
        "name": "country",
        "type": "string"
      },
      {
        "name": "company",
        "type": "string"
      },
      {
        "name": "citiesLived",
        "type": "record",
        "mode": "repeated",
        "fields": [
          {
            "name": "place",
            "type": "string"
          },
          {
            "name": "numberOfYears",
            "type": "integer"
          }
        ]
      },
      {
        "name": "note",
        "type": "string"
      }
    ]
    # bq update logs.sample nested01.fields.json
    Table '****:logs.sample' successfully updated.

    スキーマが追加。 今まで投入されていたデータに追加されたカラムはnullが入る。

    新しいスキーマに、旧データを投入

    (スキーマは変更したが、投入するデータは以前と同じ)

    # bq load --source_format=NEWLINE_DELIMITED_JSON logs.sample nested01.data.json 
    Upload complete.
    Waiting on bqjob_r73583e1d3c68485e_000001672bece222_1 ... (0s) Current status: DONE   

    エラーにはならず、単純に新しいスキーマにはnullが入る

    新スキーマに沿ったデータを投入

    {"gender": "Male", "fullName": "John Doe", "age": 22, "citiesLived": [{"numberOfYears": 5, "place": "Seattle"}, {"numberOfYears": 6, "place": "Stockholm"}], "kind": "person", "country": "Japan", "company": "A company"}
    {"gender": "Female", "fullName": "Jane Austen", "age": 24, "citiesLived": [{"numberOfYears": 2, "place": "Los Angeles"}, {"numberOfYears": 2, "place": "Tokyo"}], "kind": "person", "country": "USA", "company": "B company"}
    {"note": "with newline (\\n)", "kind": "person", "gender": "Male", "age": 30, "fullName": "newline", "citiesLived": [{"place": "Shinjuku-ku,\nTokyo"}], "country": "Japan", "company": "A company"}
    {"note": "with tab (\\t)", "age": 30, "fullName": "tab", "citiesLived": [{"place": "Shinjuku-ku,\tTokyo"}], "kind": "person", "country": "USA", "company": "B company"}
    {"note": "japanese / unicode escape sequence", "gender": "Female", "citiesLived": [{"place": "\u6a2a\u6d5c\u5e02"}], "fullName": "\u6a2a\u6d5c \u82b1\u5b50 (1)", "kind": "person", "country": "Japan", "company": "A company"}
    {"note": "double-quoted string", "fullName": "\"quoted\"", "kind": "person"}
    # bq load --source_format=NEWLINE_DELIMITED_JSON logs.sample nested01.data.json 
    Upload complete.
    Waiting on bqjob_r34be71bb151950ee_000001672bf33c1d_1 ... (0s) Current status: DONE 

    投入された

    テーブル作成

    jsonファイルを作成する

    [
          {
            "name": "register_day", 
            "type": "STRING"
          }, 
          {
            "name": "rtime", 
            "type": "STRING"
          }, 
          {
            "name": "tid", 
            "type": "INTEGER"
          }, 
          {
            "name": "sid", 
            "type": "INTEGER"
          }, 
          {
            "name": "flag", 
            "type": "INTEGER"
          }, 
          {
            "name": "id", 
            "type": "INTEGER"
          }, 
          {
            "name": "lesson_date", 
            "type": "TIMESTAMP"
          }
    ]

    jsonファイルを用意して、bqコマンドで作成する

    bq mk --table --expiration 3600 --description "This is my table" --label organization:development logs.mytable testTable.json
    

    Table ‘***:logs.mytable’ successfully created. と表示されたら成功。 ブラウザで確認すると、問題なく作成されている。

    スキーマ変更

     

    [
          {
            "name": "register_day", 
            "type": "STRING"
          }, 
          {
            "name": "rtime", 
            "type": "STRING"
          }, 
          {
            "name": "tid", 
            "type": "INTEGER"
          }, 
          {
            "name": "sid", 
            "type": "INTEGER"
          }, 
          {
            "name": "flag", 
            "type": "INTEGER"
          }, 
          {
            "name": "id", 
            "type": "INTEGER"
          }, 
          {
            "name": "lesson_date", 
            "type": "TIMESTAMP"
          },
          {
            "name": "lesson_date2", 
            "type": "TIMESTAMP"
          }
    ]

    lesson_date2を追加し、bq update コマンドを実施

    bq update logs.mytable testTable.json

    Table ‘****:logs.mytable’ successfully updated.

    となれば成功 無事カラムが追加された

    テーブル定義をdumpする

    bq --format=prettyjson show --schema tsukadaproject:logs.logsPartition > bbbb
    [
      {
        "mode": "NULLABLE", 
        "name": "register_day", 
        "type": "STRING"
      }, 
      {
        "mode": "NULLABLE", 
        "name": "rtime", 
        "type": "STRING"
      }, 
      {
        "mode": "NULLABLE", 
        "name": "lesson_date", 
        "type": "TIMESTAMP"
      }
    ]

    当然このformatを読み込ませることができる

    bq mk --table --expiration 3600 --description "This is my table" --label organization:development logs.bbbb bbbb   

    パーティションテーブルを作成する

    JSONはスキーマ情報のみ。パーティションテーブルの指定はbqコマンドのオプションで行う。

    [
      {
        "mode": "NULLABLE", 
        "name": "register_day", 
        "type": "STRING"
      }, 
      {
        "mode": "NULLABLE", 
        "name": "rtime", 
        "type": "STRING"
      }, 
      {
        "mode": "NULLABLE", 
        "name": "lesson_date", 
        "type": "TIMESTAMP"
      }
    ]

    パーテョションテーブル作成

    bq mk --table --expiration 3600 --description "This is my table" --time_partitioning_field=lesson_date --time_partitioning_type=DAY --label organization:development logs.cccc cccc

    Table ‘****:logs.cccc’ successfully created.

     

    参考情報

    ストーリー仕立てで分かりやすくまとまっているのでおすすめ。

  • embulkでBigQueryの分割テーブル(partitioned table)へデータ投入

    embulkでBigQueryの分割テーブル(partitioned table)へデータ投入

    はじめに

    BigQueryでクエリスキャンを行うと、いくらwhereで絞ったとしても、テーブル内の指定したカラムは全行読み、それに応じて課金される。BigQueryに分割テーブル(partitioned table)を作成することにより、時間や日付を絞り膨大なスキャンならびに課金を限定的にすることが可能だ。今回はembulkからデータのinsertを行うことにする。

    やりたいこと

    MySQL -> (embulk) -> BigQuery

    embulkの設定

    in:
      よしなに
    
    out:
      type: bigquery
      auth_method: json_key
      json_keyfile: xxxx.json
      path_prefix: /tmp/
      file_ext: .csv.gz
      source_format: CSV
      project: xxxxx
      dataset: logs
      time_partitioning:
        type: DAY
      auto_create_dataset: true
      auto_create_table: true
      delete_from_local_when_job_end: true
      table: sample
      formatter: {type: csv, charset: UTF-8, delimiter: ',', header_line: false}
      encoders:
      - {type: gzip}

    パラメータの詳細はこちら

    https://github.com/embulk/embulk-output-bigquery

    実施

    docker run -t -v ${PWD}:/work tsukada/embulk run bq.yml 

    結果(BigQuery)

    select 
    _PARTITIONTIME AS pt,
    lesson_date
    rtime
    from [logs.sample]
    
    WHERE 
      _PARTITIONTIME >= "2018-11-13 00:00:00" AND _PARTITIONTIME < "2018-11-16 00:00:00"
      

    _PARTITIONTIMEは見えないカラムのようなもので、その日付はinsertで更新される。

    WHERE _PARTITIONTIME でスキャン対象カラムを絞ることが可能。

  • BigQueryでテーブルまたぎのSelectについて

    BigQueryでテーブルまたぎのSelectについて

    はじめに

    BigQueryではFROMに複数のテーブルを指定することができる

    通常のSQL

    #legacySQL
    SELECT
      *
    FROM
    [project:logs.table_20181114];

    BigQueryで複数テーブル

    #legacySQL
    SELECT
      *
    FROM  
          TABLE_DATE_RANGE( [logs.table_] , 
                        TIMESTAMP('2018-11-13'), 
                        TIMESTAMP('2018-11-14'))

    legacySQLのみでstandardSQLで実施はできないので注意。

    参考情報

    ストーリー仕立てで分かりやすくまとまっているのでおすすめ。

  • The server time zone value ‘Asia/Tokyo’ is unrecognized or represents more than one time zone.

    The server time zone value ‘Asia/Tokyo’ is unrecognized or represents more than one time zone.

    はじめに

    embulkでmysqlへ接続しデータを抽出しようとした際、以下のようなエラーが発生し取得できなかった

    The server time zone value 'Asia/Tokyo' is unrecognized or represents more than one time zone.

    原因

    デフォルトのタイムゾーンの設定に誤りがある。1つ以上設定されてある?

    対応

    embulkのconfigのinのところに以下のオプションを追加

    options: {useLegacyDatetimeCode: false, serverTimezone: Asia/Tokyo}

    以降問題発生せず、対応完了

  • BigQueryのunnest関数が便利

    BigQueryのunnest関数が便利

    はじめに

    BigQueryの「大容量のデータを高速でスキャンできる」「従量課金の料金形態」という性質から、テーブル設計をはじめるとRDBMSといろいろ違いがでてくる。 今回は配列をカラムに格納する上で便利なunnest(アンネスト)関数を紹介。

    前提

    サンプルコードを動かす前に、with関数を使ってメモリー上に試験的に使うデータを保持するようにする。

    #standardSQL
    WITH data AS (
      SELECT "primes under 15" AS description,
      [1,2,3,5,7,11,13] AS primes_array)

    この時点で

    #standardSQL
    WITH data AS (
      SELECT "primes under 15" AS description,
      [1,2,3,5,7,11,13] AS primes_array)
      
    SELECT count(*) FROM data

    を実施すると 1 が返ってくる。つまり1レコード登録されている状態。

    unnest関数で紐解く

    #standardSQL
    WITH data AS (
      SELECT "primes under 15" AS description,
      [1,2,3,5,7,11,13] AS primes_array)
    SELECT description, prime 
    FROM data, UNNEST (primes_array) as prime

     

    from テーブル名, unnest(内部カラム) ;

    という形式でデータを取り出す。 この時点で

    #standardSQL
    WITH data AS (
      SELECT "primes under 15" AS description,
      [1,2,3,5,7,11,13] AS primes_array)
      
    SELECT count(*)
    FROM data, UNNEST (primes_array) as prime

    を実施すると 7 レコード返ってくる。

    Google Developerドキュメント

    Firebase blogのドキュメントに具体的な利用方法が書かれてある。 https://developers-jp.googleblog.com/2017/04/bigquery-tip-unnest-function.html    

    参考情報

    ストーリー仕立てで分かりやすくまとまっているのでおすすめ。

  • OpenVASからの攻撃をnginxで防ぐ

    OpenVASからの攻撃をnginxで防ぐ

    はじめに

    脆弱性スキャンツールから攻撃されることが度々ある。Nginxでその攻撃を防ぐ。

    どう防ぐか

    access logをみると、useragentに”OpenVAS”というのが記されていた。nginxを使っている場合、このuseragentを403 errorにさせることにした

    設定

    serverディレクティブに設定を追加する。

    もしhttp_user_agentにopenVASが含まれていたら 403 にさせる。という設定

    server {
    
        if ( $http_user_agent ~* (OpenVAS) ) {
            return 403;
        }
    

    この設定を入れた後nginxを再起動させるのみ

    もちろんuseragentを偽装されてしまえばこの対応では防げないが、デフォルトのuseragentから来ることが多いので、大半のアタックは防ぐことができる。

  • メールを送れない環境で、受信するはずのメールを確認する

    メールを送れない環境で、受信するはずのメールを確認する

    はじめに

    redashやwordpressなどシステムが送信するメール場合があるが、外へのメール送信が制限されている環境だとメールを確認することができない。

    redashであればuser作成したあとのpassword設定であったり、
    wordpressであればメールアドレスの変更など。

    システムの投げるメールの本文を確認したい事は結構多い。

    対応

    メールキューの中身を確認する

    システムが何らかの理由でメールが送信できない場合、メールキューというところに蓄積される。(その後指定しか期間を過ぎたらexpireされ、破棄される)

    キューの確認

    # mailq
    -Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------
    BBC672189242     1762 Mon Oct 22 11:51:30  httpd@kusanagi-aaa.localdomain
                (connect to mail.xxx.co.jp[xxx.xxx.xxx.xxx]:25: No route to host)
                                             system@sumito.jp
    
    -- 10 Kbytes in 1 Requests.
    

    Queue IDを控え、postcat -qコマンドで中身を確認する

    # postcat -q  BBC672189242
    *** ENVELOPE RECORDS deferred/B/BC1DD21B7AD9 ***
    message_size:            1207             183               1               0            1207
    message_arrival_time: Thu Oct 25 14:28:08 2018
    create_time: Thu Oct 25 14:28:08 2018
    named_attribute: rewrite_context=local
    sender_fullname: 
    sender: httpd@kusanagi-uxd.localdomain
    *** MESSAGE CONTENTS deferred/B/BC1DD21B7AD9 ***
    Received: by kusanagi-uxd.localdomain (Postfix, from userid 1000)
        id BC1DD21B7AD9; Thu, 25 Oct 2018 14:28:08 +0900 (JST)
    To: system@sumito.jp
    Subject: =?UTF-8?B?W1ImRCBSbDmlrDopo/jg6H7zjg6vjgqLjg4njg6zjgrk=?=
    X-PHP-Originating-Script: 1001:class-phpmailer.php
    Date: Thu, 25 Oct 2018 05:28:08 +0000
    From: WordPress <wordpress@sumito.com>
    Message-ID: <1a0a2f7069595074466e7d9ef2744d49@r-and-d.rarejob.com>
    X-Mailer: PHPMailer 5.2.22 (https://github.com/PHPMailer/PHPMailer)
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    こんにちは wpadmin さん
    
    お持ちのアカウントのメールアドレスの変更がリクエストされました
    
    もしこれに間違いがなければ、以下のリンクをクリックして変更を行ってください。
    https://sample.sumito.jp/wp-admin/profile.php?newuseremail=1edbc57873c6f3cbae541a8f3ebe
    
    変更をしない場合は、このメールを無視し、削除してかまいません。

    この場合はメールアドレス変更のメール。

    キューの中に記載のあるURLをブラウザに入力すれば、wordpressのメールアドレスを変更することが可能になる。

     

  • redashのuserをgitで管理する

    redashのuserをgitで管理する

    はじめに

    [本記事はredash meetup 4.0.0で発表させていただいた内容に肉付けしたものです]

    redashはデータベースに接続できるツールなのでuserの管理がとても重要になる。
    userを定期的に棚卸しをし、メンテナンスしていくことはセキュリティを維持する上で必須だ。弊社では

    1. CLIでuser一覧を出す
    2. それをgitlabで管理
    3. gitlabに上がったということをchatworkで担当者に伝える
    4. 問題なければmerge
      merge日=最終棚卸し日

    というフローを採用し運用している。

    しかし、想定していた運用を採用するうえではソースを変更する必要があった。

    現在 version 5.0.2のCLI

    残念ながらこの画像からわかる通り、非常に貧弱である。

    version 5からuserをdisableする機能が導入されたが、userがenableなのか、disableなのかという情報がCLIからだとわからない。

    pull requestの作成

    機能としては存在しているのに、CLIで見れないとなると単純に表示させていないだけなのかもと察しソースを読んだ。

    Userのenableなのか、disableの情報を表示するメソッドを見つけた

    https://github.com/getredash/redash/blob/68272678b85ef4a6498543ef6a33a2071e607628/redash/models.py#L439

    おそらくGUIであればこの処理を叩いて画面に表示している。

    機能があるのであればCUIも同じように叩けばよいのでは?という仮説のもとファイルを変更した

    https://github.com/getredash/redash/pull/2951/files

    これでenableなのか、disableなのかがコマンドラインで確認できるようになった。

    自分の管理するredashはdockerで動いているので、linux上でviコマンドで編集し、docker cpコマンドでコンテナ内に転送することで変更を動いているredashに反映させた。

    OSSのソースに手を入れるというと相当な知識がないと変更できないかと思っていたが、progateでpython覚えた程度でも変更できた。

    最初テストケースを書かずにpushしたらCIでコケたので、恥ずかしながらそこでredashのテストコードの存在を知った。。

    せっかくなのでpull reqを出すと翌日mergeしてもらい、これがコントリビュートにつながった。

     

    その後CLI機能を拡張すべく2つpull requestを出させていただき、いずれも承認された。

    redashでユーザーを取得しGitLabへpushへ

    gitlab-cliの設定する必要があるので事前にセットアップする

    https://tsukada.sumito.jp/2018/10/17/python-gitlab/

    shellをcronで動かし、その中でpythonのスクリプトを動かす

    #!/bin/bash
    
    hostname=`uname -n`
    _roomid=123456789
    output=/tmp/$hostname
    
    cd ~/redash-user/
    
    git pull 
    nohup /usr/bin/docker exec -i redash_server_1 ./manage.py users list > ~/redash-user/$hostname &
    
    sleep 10;
    ps -ef | grep "./manage.py users list" | grep -v grep | awk '{print $2}' | xargs kill -9
    
    git checkout -b $hostname
    git add $hostname
    git commit -m $hostname
    git push origin $hostname
    
    python merge.py

    pythonはGitLabへpushするのに使っている。コードはこちら

    import os
    import gitlab
    
    hostname = '%s' % os.uname()[1]
    
    gl = gitlab.Gitlab('https://gitlab.sumito.com/', private_token='abcdefgggggggg')
    gl.auth()
    
    project = gl.projects.get(123, lazy=True)
    
    mr = project.mergerequests.create({'source_branch': (hostname),
                                       'target_branch': 'master',
                                       'title': (hostname) + ' user list'
                                       })
    
    mrs = project.mergerequests.list(state='opened', order_by='updated_at')[0]
    
    print(mrs.attributes['web_url'])

    以下のようにcronを仕込み月に一度listを更新し、GitLabにpushするようにしている。

    0 0 1 * * sh /root/redash-user/redashUsers.sh 1> /tmp/stdout.log 2> /tmp/stderr.log

    GitLabにMergeRequest上がっているのを取得、chat投げる処理

    これも同様にshellからpythonを動かすようにしている。

    #!/bin/bash
    
    cd /root/redash-user/
    hostname=`uname -n`
    _roomid=123456789
    
    tmp=$(/usr/bin/python ./chat.py)
    tmowl=`echo $tmp | grep git.sumito.com | wc -l`
    output=/tmp/gomi
    
    if [ $tmowl -eq 0 ] ; then
      exit
    else
    
    /usr/bin/cat << _EOT_ > /tmp/gomi
    [toall]
    [info]
    [title]latest redash account Please check it!!
    [/title] 
    `/usr/bin/python ./chat.py`
    [/info]
    _EOT_
      
    _body=`/usr/bin/cat $output`
    /usr/bin/curl -X POST -H "X-ChatWorkToken: 123456789" -d "body=${_body}" "https://api.chatwork.com/v2/rooms/${_roomid}/messages"
    
    fi
    

    pythonはこちら

    import os
    import gitlab
    
    hostname = '%s' % os.uname()[1]
    
    gl = gitlab.Gitlab('https://git.sumito.com/', private_token='123456789')
    gl.auth()
    
    # your project ID
    project = gl.projects.get(123, lazy=True)
    
    mrs = project.mergerequests.list(state='opened', order_by='updated_at')
    mr_url = [mr.attributes['web_url'] for mr in mrs]
    print("{}".format("\n ".join(mr_url)))

    アカウントの棚卸し

    以下のように表示される

    この状態ではmerge requestが発行された状態なので、

    管理者はこのリクエストを確認し、最新の状態を確認。問題なければmergeする

    当然gitなので最新merge日は更新され、この日が棚卸し完了日と位置づけすることにより、最終棚卸し日がいつだったのかわかるようにしている。

     

  • Linuxでのswap解放

    Linuxでのswap解放

    はじめに

    気がついたらswapを喰っていることがある

    # top
    top - 10:39:58 up 26 days, 16:25,  1 user,  load average: 0.80, 0.31, 0.20
    Tasks: 132 total,   2 running, 130 sleeping,   0 stopped,   0 zombie
    %Cpu(s):  0.0 us,  0.7 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem :  1883152 total,    83772 free,  1363060 used,   436320 buff/cache
    KiB Swap:  1048572 total,   957948 free,    90624 used.   315320 avail Mem 

    この場合は90624 used.

    memoryに抱えきれなかった領域がストレージにdumpされてしまったようだ。ストレージがSSDだったとしても遅いのだが、これがHDDだったりすると阿鼻叫喚だ。

    まず先にやること

    一時的にswapをオフにして、再度オンにする。

    swapoff -a && swapon -a

    ただし、swap outしている領域よりもmemoryが十分に空きがある必要がある。

    他にもアプローチはあることはあるが、

    これで解放できなかったらOS再起動を考えた方が手っ取り早い。

     

  • Failed to Connect to MySQL at localhost: 3306 through SSH tunnel

    Failed to Connect to MySQL at localhost: 3306 through SSH tunnel

    はじめに

    MySQL Workbenchに備わっている sshトンネリング機能を使い、手元のPC/MacからリモートのサーバのDBに繋ぐ方法を紹介。

    やりたいこと

    手元の環境から、MySQL Workbenchがserverにつなぎに行き、そのサーバ内のMySQLに接続させたい。

    workbenchの設定

    Connection Methodを “` Stadard TCP/IP over SSH “` を選択。諸々入力する。

    問題発生

    つながらない

    原因と対処

    mysql内に作成したユーザの接続元を
    127.0.0.1ではなく、localhostとして登録していた。 意味的には同じように思えるが、mysqlの場合はこの辺厳密に区別されるらしい。

    対処

    接続元を127.0.0.1にしてユーザを再作成

    GRANT USAGE ON *.* TO 'tsukada'@'127.0.0.1' IDENTIFIED BY 'password';
    GRANT select ON `database`.* TO 'tsukada'@'127.0.0.1' ;
    
    MariaDB [(none)]> select user,host from mysql.user;
    +----------------+-----------+
    | user           | host      |
    +----------------+-----------+
    | tsukada | 127.0.0.1 |
    +----------------+-----------+
    14 rows in set (0.00 sec)
    
    MariaDB [(none)]> 

    問題なく接続できるようになった

    備考

    リモート接続の際、この本の第三章が非常に良くできている。

    第3章 一歩進んだOpenSSHの使い方
     3-1 TCPポートフォワード
     3-2 プロキシと多段SSH
     3-3 SSHのセッションをコントロールする

    第三章だけでも読む価値はある。とてもおすすめ。