忍者ブログ
  ちゃんとカテゴリ分けされておりませんので、 記事をお探しならブログ内検索が便利です。 ご活用くださいませー+.(≧∀≦)゚+.゚
Admin*Write*Comment
[1]  [2]  [3]  [4]  [5]  [6

とある案件でAPIを実装することになりました。
クライアント側とサーバ側でベンダー異なるのですが、サーバ側の実装を待たずしてクライアント側でテスト的にモックが欲しいとのこと。
Google先生に聞いてみたらRESTfulなAPIをサクッと作れるミドルウェアがあると聞いて!
nodeで実装されたJSON形式のファイルを取り扱えるみたい。
早速試してみました!!

# OSの確認
$ uname -a
Linux localhost 4.4.0-128-generic #154-Ubuntu SMP Fri May 25 14:15:18 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/debian_version
stretch/sid
# まず、環境を整えます
sudo apt install -y npm
sudo npm install -g json-server
ln -s /usr/bin/nodejs /usr/bin/node
npm install -g n
n stable
json-server -v
# ダミーデータを投入
cat << __ > db.json
{
    "prefecture": [
            {"id":1, "name": "北海道", "yomi": "ホッカイドウ"},
            {"id":2, "name": "青森県", "yomi": "アオモリケン"}
        ]
}
__
# そしてサーバを起動
json-server db.json --watch --port 80 --host 192.168.3.91&
# GETのテスト
curl http://192.168.3.91/prefecture
curl http://192.168.3.91/prefecture/1

# POSTのテスト
curl http://192.168.3.91/prefecture -d 'name=岩手県&yomi=イワテケン'
curl http://192.168.3.91/prefecture -d 'name=宮城県&yomi=ミヤギケン'

# DELETEのテスト
curl http://192.168.3.91/prefecture/3  -X DELETE
curl http://192.168.3.91/prefecture -d 'name=岩手県&yomi=イワテケン'
curl http://192.168.3.91/prefecture

# IDのインクリメントの法則を試してみる
curl http://192.168.3.91/prefecture/4  -X DELETE
curl http://192.168.3.91/prefecture/5  -X DELETE
curl http://192.168.3.91/prefecture

# 再びPOST
curl http://192.168.3.91/prefecture -d 'name=岩手県&yomi=イワテケン'
curl http://192.168.3.91/prefecture -d 'name=宮城県&yomi=ミヤギケン'
curl http://192.168.3.91/prefecture

なるほど、これなら簡単ね(*^^*)
ただ、POSTが必ずしも登録ではなく、リクエストの一環としてやってくることも多いのが少し悩ましいところね。

以上、JSON-Serverでした。

拍手

PR



多くのデータを分散処理したいことが多々あります。
並列化は一筋縄でいかないことはシステムを組んでみようと考えたことがある人なら難易度は低くないことは容易に想像がつくと思います。
特に処理をプロセス間で重複させないためのシリアライズは手を焼く仕組みの一つです。
この話をメンバに相談すると必ずキューイングがやり玉にあがるのです。

そうキューイング信者が社内にいるのです…
何かとキューキュー騒ぐので、何もたいそれたシステムを導入しなくても実現できるんじゃない?
と思いまして、調べたところ、DBで簡単に実現できそうでした♪

参考:
https://lightgauge.net/database/sqlserver/962/

まず、キューとなるテーブルを作成します。
psql
DROP TABLE mq ;
CREATE TABLE mq (
    id serial, 
    message text, 
    primary key(id)
);
\q

次に、テスト用にキューを貯めていきましょう。
for i in $(seq 1000)
do
    value=''
    for i in $(seq 10)
    do
        value="$value ,('hoge')"
    done
    psql -c "INSERT INTO mq(message) VALUES('hoge') $value "
done


キューを払い出しつつ、キューを削除していきます。
DELETE FROM mq WHERE id = (SELECT id FROM mq WHERE pg_try_advisory_lock(tableoid::int, id) LIMIT 1) returning *;

ターミナルをいくつか立ち上げて、下記コマンドを投げまくってみます。
\rm /tmp/hoge
for i in $(seq 600)
do
    psql -c"DELETE FROM mq WHERE id = (SELECT id FROM mq WHERE pg_try_advisory_lock(tableoid::int, id) LIMIT 1) returning 'hoge', *;" >> /tmp/hoge
done

結果を確認します。
うまくシリアライズされていました。
grep DELETE hoge | sort | uniq -dc
   1189 DELETE 1


行ロックを取得しない版も投げてみます。
\rm /tmp/hoge
for i in $(seq 600)
do
    psql -c"DELETE FROM mq WHERE id = (SELECT id FROM mq LIMIT 1) RETURNING 'hoge', *;" >> /tmp/hoge
done

処理がシリアライズできていないので二重処理してしまい、後から処理したものは削除ができず、0件になっています。
grep DELETE hoge | sort | uniq -dc
     37 DELETE 0
   1138 DELETE 1

これでPythonのQueueクラスのようなキューイングシステムができました。

小~中規模程度にしか通用しなさそうですが、やれ、ミドルウェアが必要だの、
OSのバージョンアップが必要だの、大げさな話になるくらいならこれくらいライトに初めてもいいのではないでしょうか^^

拍手




Python2でもおおよそ動くと思うけどね。
もう2018年だし、そろそろね?2系は卒業しよう。
と、いうことで、loggingでーす。
すぐ忘れるのでMyめもです。
今までは雑にルートロガーを使うことが多かったですが、Windowsで作業していると出力がSJISになっちゃうので。。。
慣れる意味でもちゃんとLoggerを使いましょう、という教訓。

import sys
from logging import getLogger, FileHandler, Formatter, DEBUG

APP_PATH = os.path.dirname(sys.argv[0])
TMP_PATH = os.path.join(APP_PATH, "tmp")
LOG_FILE_PATH = os.path.join(TMP_PATH, "logs")
LOG_FILE_NAME = "{}.log".format(datetime.datetime.today().strftime("%y%m%d%H%M%S"))
LOG_FILE = os.path.join(LOG_FILE_PATH, LOG_FILE_NAME)
LOG_FORMAT = ("\t".join(['"%(asctime)s"',
                         '"%(levelname)s"',
                         '"%(thread)d"',
                         '"%(module)s"',
                         '"%(funcName)s"',
                         '"%(lineno)d"',
                         '"%(message)s"',
                         ]))

logger = getLogger(__name__)
handler = FileHandler(filename=LOG_FILE, encoding='utf-8')
handler.setLevel(DEBUG)
handler.setFormatter(Formatter(LOG_FORMAT))
logger.setLevel(DEBUG)
logger.addHandler(handler)



拍手




yum -y update
yum -y upgrade
yum -y install vim wget make gcc-c++ perl

# https://launchpad.net/ufw/
ufw=ufw-0.35
ufw_url=https://launchpad.net/ufw/0.35/0.35/+download/ufw-0.35.tar.gz


cd /usr/local/src
wget $ufw_url

tar xzf ${ufw}.tar.gz
cd $ufw
sudo python ./setup.py install
cd ../
sudo rm -rf $ufw
sudo chmod -R g-w /etc/ufw /lib/ufw /etc/default/ufw /usr/sbin/ufw

sudo service iptables stop
sudo service ip6tables stop
sudo chkconfig --del iptables
sudo chkconfig --del ip6tables

ufw disable
yes y | ufw reset
ufw default deny incoming
ufw default allow outgoing
ufw allow from 192.168.0.0/24 to any port 22
yes y | ufw enable
ufw status

拍手




Linuxサーバのiptablesがきちんと設定できているか不安だったので、外部からポートチェックをしようと思いました。
そんなサービスいまどき溢れているかと思いきや、セキュリティの観点からか、あまりないんですね。
もちろん1ポートあたりのチェックはいっぱいあるのですが、65536ポート全部舐めるようなサービスはおいそれと見つかりませんでした。

ならば、自前で作成してしまえ、というわけです。
もちろん外部サーバがあればね(笑)

python

import csv
import traceback
from telnetlib import Telnet

host = 'check.your.host'

with open("result.tsv", "w") as f:
    w = csv.writer(f, delimiter="\t")
    for port in range(1, 65535):
        res = ""
        try:
            Telnet(host, port, timeout=2)
        except Exception as e:
            res = str(e)
        w.writerow([port, res])
        print(port, res)

拍手




Python3.5 * Django1.9 with Postgresql9.5 構成のバッチプログラムが見たこともないエラーを出力しました。

psycopg2.DatabaseError: lost synchronization with server: got message type ",", length 539107884

何だろう・・・これ?
ググってもなかなか答えが出てこない…
このバッチ自体は2か月以上運用実績があるのに…

近そうだったのが、これ。
https://www.postgresql.org/message-id/2164.1435070683%40sss.pgh.pa.us
どうも、OOM(Out of memory)のようです。

PostgresqlはキャッシュデータをOSと共有するので、Shared Memory(shared_buffur)は少ない方がよい。
というのを見て、initdbのまま(128MB)で運用していたのが原因みたい。
SELECTの対象となったデータは数十MB程度だったのだけど、並列処理していたので、合計でこの値を上回ってしまったみたい。

ではなぜ、運用開始直後から出なかったかというと、じつは直近でDBサーバをSSDに変えたのがありました。
浅はかな知識で理解する限りPostgresqlはクラスタから引き出したデータは一度共有メモリに展開します。
その後クライアントに送られます。
クラスタから引き出されたデータは順次クライアントに送られます。
ですが、データが大きく引き出す速度が転送速度を極度に上回った場合、共有メモリを圧迫します。
その結果OOMが発生し、lost synchronizationが発生したと思われます。
シンクロナイゼーション、すなわち、共有バッファとクライアントの同期が失われた。
共有バッファ上のデータがクライアントに到達する前にロストしたってことみたい。

うーん、DBチューニングは奥が深いわねぇ…

検索タグ
Postgresql9.5.3
Python3.5.0
Django1.9

拍手




たまにやらかすのが、実行時間が長いバッチをバックグランドで実行しようとして、普通に起動しちゃうこと。

# 想定
./long_time_running.sh &

# 実際にやりがち
./long_time_running.sh 

Ctrl+Cでやり直せるなら早いけど、強制的に止めると不都合のあることはよくあります。。。
何とか対処ができないかなーと思ったらやっぱりありました。

# 間違えて起動
$ ./long_time_running.sh

# Ctrl+Zで停止
^Z
[2]+  停止                  ./long_time_running.sh

# jobsコマンドで状況を確認、停止中になっている
$ jobs
[1]+  停止                  ./long_time_running.sh

# job番号をしてしてバックグランドで実行させる
$ bg 1
[1]+ ./long_time_running.sh &

# もう一度job一覧を確認、実行できてる
$ jobs
[1]+  実行中               ./long_time_running.sh &

# 念のため&を付けたときの挙動
$ ./long_time_running.sh &
[1] 22062

# jobの確認、同じね
$ jobs
[1]+  実行中               ./long_time_running.sh &

拍手




144万行あるCSVの中から4列目と7列目のデータを抽出したい。
ごくごく簡単なお仕事ね。
そう思っていつものようにさくっとコーディング。

t = r"C:\Temp\all.txt"
import csv

results = []
c = {}
with open(t) as f:
    reader = csv.reader(f, delimiter="\t")
    for i, row in enumerate(reader):
        if not row[6]:
            continue
        res = [row[3], row[6]]
        results.append(res)

with open(r"E:\output.csv", "wb") as f:
    writer = csv.writer(f, delimiter="\t")
    writer.writerows(results)

するとどうでしょう?
なぜか結果には41,128行しかデータがない。。
なぜ?と多少不安になりながらもデバッグしてみると、本当にループが41,128回で止まっているみたい。
あれこれ試行錯誤するものの解決できず…
かくなる上はPython3.4に書き下ろす…

t = r"C:\Temp\all.txt"
import csv

results = []
c = {}
with open(t, encoding='utf-8') as f:
    reader = csv.reader(f, delimiter="\t")
    for i, row in enumerate(reader):
        if not row[6]:
            continue
        res = [row[3], row[6]]
        results.append(res)

with open(r"E:\output.csv", "w", encoding='cp932') as f:
    writer = csv.writer(f, delimiter="\t")
    writer.writerows(results)

するとどうでしょう?
問題なく動くじゃない><M
2系のバグでしょうか?
うーん、3系デフォルトで使おうかなー
なんて思った出来事でした。

検索タグ
Python2.7
Python3.4

拍手




久しぶりにPHPでバッチを書かなければならない要件ができましたー。
でもURLを連結する(カレントURLとhrefを使って遷移先URLを作成する)のって、PHPだとすごくめんどうなの・・・;;
私が知る限りそのような関数はPHPにはありません。
※ PECLにはあるかもしれないけどねーu

いいやー、もうPythonにやらしちゃおう!
そうしよう!!!
ということで下記のようなコーディングをしました♪

$current_url = "https://www.ec_site.jp/shop/search"; $href = "?page=2"; $cmd_base = <<<___ python2 -c "import urlparse; print urlparse.urljoin('%s', '%s')" ___; $cmd = sprintf(trim($cmd_base), $current_url, $href); var_dump($cmd);

するとどうでしょう?
こんな結果になったのです。

https://www.ec_site.jp/shop/?page=2

「search」が・・・ない・・・ガクゼン
なぜ?
物は試しに3.4の環境で試すと、想定通りの結果が返ってきました。
2系のバグ?
課と思ったのですが、どうも2.7では出ない模様・・・
実行したサーバのPythonのバージョンをみてみたら、2.4でした。
えー?っと思って念のため確認・・・

$ cat /etc/redhat-release
CentOS release 5.10 (Final)

古い…
あーうーとか音を上げつつ、「parse_url()」で頑張ることにしたのでした…
みなさん気をつけてくださいね^^


---- 検索タグ ----
PHP < 5.4
Python3.4
Python2.7
Python2.4

拍手




過去にもちょこちょこっとお世話になったことがあるsqlite3さん。
でも本格的にプログラムで使用したことがないから、一時的にちょこっと使用したときとかに便利。
というより、その程度しか使用したことがないのよねー。
な・の・で・・・すぐに忘れてしまう鳥頭のためのいつもの落書きです^^;

# sqlite3 の入手
https://www.sqlite.org/download.html

# 実行
# sqlite3.exe をダブルクリックで起動

-- データベースの作成
-- 作成しなかった場合はin-memoryで作成されている
-- (つまり必要がない)
.open dbname.sqlite3

-- テーブルの作成、普通にIF EXISTS も使える
-- 型は以下の通り
-- http://www.sqlite.org/datatype3.html
--    TEXT
--    NUMERIC
--    INTEGER
--    REAL
--    BLOB

CREATE TABLE IF NOT EXISTS tbl_test(t text, n numeric, i integer, r real ,b blob);
INSERT INTO tbl_test VALUES('hoge"ho''ge', 1234.567890, 1234.567890, 1234.567890, 'blob');

-- いまひとつ数字系とtext, blobの違いが判りません・・・
SELECT * FROM tbl_test;

-- INDEXも作れます!
CREATE INDEX tbl_test_i ON tbl_test(i);
CREATE UNIQUE INDEX tbl_test_t ON tbl_test(t);

-- 日付系
SELECT date('now');
SELECT datetime('now');

-- テーブルダンプ(標準出力)
.dump

-- 出力先きりかえ、そしてダンプ(バックアップ)
.output ./db_test.dmp
.dump

-- 標準出力へ戻す
.output

-- テーブル破棄
-- これもEXISTS使えました^^
DROP TABLE IF EXISTS tbl_test;

-- リストア
.read ./db_test.dmp

-- メタコマンド一覧
.help

-- データベースの一覧
.databases

-- テーブルの一覧
.tables

-- INDEXの一覧
.indexes

-- VACUUM
VACUUM;

-- SELECTの表示を少しでも見やすく
.mode column
SELECT * FROM tbl_test;

-- CSV形式
.mode csv
SELECT * FROM tbl_test;
-- ファイル出力
.output tbl.test.csv
SELECT * FROM tbl_test;
.output

-- TSV形式
.mode tabs
SELECT * FROM tbl_test;
-- ファイル出力
.output tbl.test.tsv
SELECT * FROM tbl_test;
.output

-- INSERT形式
-- 主に別システム移行用ではないかと
.mode insert
SELECT * FROM tbl_test;
-- ファイル出力
.output tbl.test.sql
SELECT * FROM tbl_test;
.output

拍手



ブログ内検索
カレンダー
05 2018/06 07
S M T W T F S
1 2
3 4 5 6 7 8 9
10 11 13 14 15 16
17 19 20 21 22 23
24 25 26 27 28 29 30
カウンター
最新コメント
最新トラックバック
プロフィール
+ハンドル+
y_ayamori(purple)
+職業+
IT系エンジニア
+すまい+
さいたま
バーコード
ブログパーツ
アバター
Copyright © アナログを愛するデジタル生活館 All Rights Reserved.
photo by Kun material by Atelier Black/White Template by Kaie
忍者ブログ [PR]