memcachedの使い方について簡単にメモします
動作環境は、Max OS X EI Captain 10.11.4, memcached 1.4.24 です。
memcachedのインストール
# http://qiita.com/makotok7/items/9998b15f79fc7a53af24 brew install memcached
localhostの11211ポートでmemcachedサーバを起動
$ memcached -p 11211 -d
詳しいオプションについては
- http://blog.nomadscafe.jp/2013/12/memcached-2.html
- http://gihyo.jp/dev/feature/01/memcached/0001?page=2
telnetでmemcachedサーバに接続
localhostの11211ポートでmemcachedサーバが動作しているとします。
$ telnet localhost 11211 Trying ::1... Connected to localhost. Escape character is '^]'.
memcachedサーバにデータを入れる
参考: https://www.tutorialspoint.com/memcached/memcached_set_data.htm http://l-w-i.net/t/memcached/command_001.txt
set [KVSのキー] [非圧縮/圧縮などのフラグ] [データの有効期限(秒). 0の場合は永続的に保存] [保存するデータのバイト数](return/enter) [KVSの値](return/enter) 123という3バイトの文字列をfooというキーに非圧縮で900秒保存させる set foo 0 900 3(return/enter) 123(return/enter) STORED
memcachedサーバにデータの取得と更新
参考: http://l-w-i.net/t/memcached/command_001.txt
get foo VALUE foo 0(非圧縮) 3(データ長:3バイト) 123 END gets foo VALUE foo 0(非圧縮) 3(データ長:3バイト) 2(cas ID) 123 END
getsで追加で表示されている最後の数字は、cas ID
といい、replace
コマンドでmemcached
上の同じキーに対する値を書き換えるたびに変化します。
replace foo 0 900 3 345 STORED gets foo VALUE foo 0 3 3 345 END
ユーザーAがmemcachedからデータを取得して処理したあとに保存しようとしたら、すでに他のユーザーBによって変更が加えられており、素直にユーザーAの計算結果を保存したらBの変更の履歴が消えてしまって困る、という場合があります。
それを避けるため、cas
コマンドを使って、データを取得した時のcas ID
をパラメータに与えて、「あの時からお変わりなかったら、変更したいんですけどー」という感じで変更コマンドを打ちます。
(ユーザーA) gets foo => VALUE foo 0 3 7 => 123 => END (ユーザーB) replace foo 0 0 3 abc => STORED ← 他のユーザーによりデータは更新されてcas IDは変化 (ユーザーA) cas foo 0 0 3 7 zzz => EXISTS 既に他のユーザがデータを書き換えたのでzzzは書き込めない
memcahcedサーバに入っているデータの状態について調べる
参考: http://taka512.hatenablog.com/entry/20100324/1269428213
stats STAT pid 8365 STAT uptime 2670 起動時間 STAT time 1476973152 STAT version 1.4.24 STAT libevent 2.0.22-stable STAT pointer_size 64 OSが32bit又は64bit STAT rusage_user 0.037374 プロセスがユーザモードで動作した累計時間?(秒.マイクロ秒) STAT rusage_system 0.061396 プロセスがカーネルモードで動作した累計時間?(秒.マイクロ秒) STAT curr_connections 10 現在のデータ数 STAT total_connections 11 STAT connection_structures 11 memcacheが確保したコネクション構造体数 STAT reserved_fds 20 STAT cmd_get 6 GETコマンド発行の累計 STAT cmd_set 7 SETコマンド発行の累計 STAT cmd_flush 0 STAT cmd_touch 0 STAT get_hits 5 リクエストでキーが見つかった数 STAT get_misses 1 リクエストでキーが見つからなかった数 STAT delete_misses 0 STAT delete_hits 0 STAT incr_misses 0 STAT incr_hits 0 STAT decr_misses 0 STAT decr_hits 0 STAT cas_misses 0 STAT cas_hits 0 STAT cas_badval 1 STAT touch_hits 0 STAT touch_misses 0 STAT auth_cmds 0 STAT auth_errors 0 STAT bytes_read 284 ネットワークから受信したバイト数 STAT bytes_written 292 ネットワークへ送信したバイト数 STAT limit_maxbytes 67108864 memcacheの最大容量(バイト) STAT accepting_conns 1 STAT listen_disabled_num 0 STAT threads 4 STAT conn_yields 0 STAT hash_power_level 16 STAT hash_bytes 524288 STAT hash_is_expanding 0 STAT malloc_fails 0 STAT bytes 71 STAT curr_items 1 STAT total_items 3 STAT expired_unfetched 1 STAT evicted_unfetched 0 STAT evictions 0 STAT reclaimed 1 STAT crawler_reclaimed 0 STAT crawler_items_checked 0 STAT lrutail_reflocked 0 END
MySQLで外部ホストのデータベースにクエリを送りたい
最近開発するために開発する環境を作っている私です。
MySQLで外部ホストにたいしてSQLを送るにはどうしたらいいのかなーと悩んでいたのですが、あっさり解決したのであっさりメモします。
まとめ
- MySQLにおいて基本的に外部ホストへはアクセスできないようになっている
- MySQLにおいてデータベースにどこのホストからアクセスするかはそのホストのmysqlデータベースのuserテーブルに入っているユーザー情報で管理
- 外部ホストにアクセスしたい場合は、アクセスしたいホストにアクセス元のサーバからのアクセスを許可したユーザーを作ってあげる
// 接続先のホストにて接続元のホスト(client_host)からアクセスするユーザーを作成 mysql> GRANT ALL PRIVILEGES ON target_database.* TO access_user@client_host IDENTIFIED BY 'pass'; mysql> SELECT host,user FROM mysql.user; +------------------------------------+---------------+ | host | user | +------------------------------------+---------------+ | client_host | access_user | +------------------------------------+---------------+ // client_host上から mysql -u access_user -h target_host target_database < request.sql // 省略してますが、パスワードの入力あり
参考
SPFってなんですか?
お仕事でSPFについて確認したのでブログにもメモを置きます。
参考: http://salt.iajapan.org/wpmu/anti_spam/admin/tech/explanation/spf/ 他
SPFについて
- メールの送信元の詐称を防ぐための認証技術
- 他に似た目的で「DomainKeys Identified Mail(DKIM)」、「Sender ID」など
SPFでメールを認証するとは
SMTPでメールを送信するときはメールの送信元に関する下記の3つのドメイン(あるいはドメインのIP)はすべて違っても良いそうです。
- a1. SMTPでメールサーバに接続してメールを送るという意味で、メール(SMTPが動いてるサーバ?)を送り出すサーバのIP
cf. example.jp は 192.0.2.1
- a2. SMTPの
MAIL FROM
コマンドの引数となる送信者のメールアドレスのドメイン(エンベローブに入ってるらしい)cf. MAIL FROM:<sender@exmaple.org>
- a3. 電子メールのヘッダ
cf. FROM: user1@exmaple.com
そうなると、なんだか電子メールのヘッダをちょこちょこといじってメール送信元詐称が簡単にできそうですね。
SPFではメールを受信したサーバが a2 のメールアドレスのドメインのSPFレコードのIPアドレスを見て、a1のサーバから送り出されたメールかどうか確認(認証)します。
SPFでメールを認証する手順
- b1. a2のドメインで利用している権威DNSに、a2のドメインでメールを送り出すときに使うサーバのIPはこれです、とa1のメールサーバのIPアドレスを登録する(SPFレコードの登録)
- b2. a2のドメインのアドレスがエンベローブのFROMには入っているメールを受け取ったメールサーバは、ドメインを見て、DNSに
example.org
のSPFレコードを問い合わせる - b3. b2の問い合わせの結果に、メールの送信元のサーバのIPが含まれていたら認証成功
認証に失敗したらどうなるの?
- SPFレコードの登録がなくて失敗した ... 認証結果: None
- 受け取り拒否にならず、迷惑メールフィルタでフィルタリングされるのに任せる場合が多いが、途中で受け取り拒否になる可能性もある
- SPFレコードの登録があって失敗した ... 認証結果: Fail
RFCにおいてはこの結果に従って通信中のSMTPセッションにおいて該当メールの受信拒否を行う場合、550番エラーの利用を勧めている
とあるので受け取り拒否になる可能性高そう
他にもありますが、参考元をご確認ください。
SPFでメールを送れなくなる理由
メールを送信するメールサーバのIPアドレスが、SMTPのMAIL FROM
コマンドの引数となる送信者のメールアドレスのドメインのSPFレコードに入っていない?
DNSサーバの種類とDNSサーバの受ける問い合わせの種類についてまとめました
参考のところに載せてるんですけど、DNSについて勉強する前に読みたかった資料です*1。もし、他の人がこの記事を見てDNSについてちょっと調べてみようと思ったら3分くらいは眺めてから調べ始めるとはかどると思います。
http://2014.seccon.jp/dns/dns_basics_in_30minutes.pdf
ただ、問い合わせの特徴によって覚えて区別つけるのもいいんですけど、基本的にどのプロトコルのアプリケーションやそれらのアプリケーションたるWebサービスなんかもサーバがクライアントから受けるリクエストによって挙動を変えるものだと考えると、上位から下位へ問い合わせを続ける過程で再帰的に動いて欲しいフルサービスリゾルバに飛んでくるリクエストが再帰問い合わせということになりわかりやすいのかな、と Webエンジニアは思いました。
特徴はどっちにしろ覚えないといけないんですけどね(苦笑)
DNS周りの情報は、後でDNSキャッシュポイズニングについて再帰問い合わせ周りの分も追加してやり直そうと思っているんですが、自分がググった限りJPRSの資料が一番はっきりしています。
ネットワークエンジニアとして(個人運営サイトらしいのですが、これでネットワーク勉強してました系のブログ記事とかでよく紹介されてた) => JPRSの資料(初心者網羅的な情報は多くないですが、専門家集団が出しているので概要であったり、個別トピックがすぱっとしてめっちゃわかりやすい) => @IT(個別の質問とかの記事がめっちゃ助かる) => BINDなど実装用ソフトのノウハウ系の記事、の順で巡回すると混乱が少ないのではないでしょうか。
*1:お約束としてある程度勉強してグーグル力が上がらないと当たれないんですね
DNSの概要と耐障害性、リソースレコードの読み方(BIND式)をまとめました
DNSキャッシュポイズニングについてまとめました
ネットワークの勉強をして色々挫折中。
とりあえず、外部連携するときにFTPとか色々クライアントかませるんだけど、そのトラブルシューティングや、サービスの中でつないでいる各種サーバへの接続設定にもこの辺の知識があると便利そうということだけわかってきた感じ。
ひとまず今日からノートに書いてあるよくわかってないことを1個ずつまとめていきますよっと。
スライドの中で紹介した Source port randomization
、最初に勉強したときの資料にはほとんど出てこなくて、それはもうベンダの方で対応してるから考えなくていいということなのか、とか、再帰的問い合わせ分からんとか壁にぶつかったりしていた。
あと、スライド中の偽造用、偽装用かもしれない...。
Support LibraryのNavigationViewでどこまでできるのか試してみる
久しぶりにサイドメニューのコードいじろうかと思ったのですが、デザインのカスタマイズ性の都合でサードパーティライブラリを使うのが辛く、ここから整理するよりSupport LibraryのNavigationViewを使って書き直した方が楽ではないか、と思ったので、どこまでできるのか試してみます。
内容
- ライブラリのバージョンについて
- 下記のコードを試す上で基本となるレイアウトなどのソースコード
- HeaderViewのレイアウトを変更する
- サイドメニューの項目を変更する場合
- サイドメニューの項目にバッジをつけたい場合
- 下に固定のfooterをつけたい場合
ライブラリのバージョンについて
gradleで指定していたバージョンは下記。
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:23.4.0' compile 'com.android.support:design:23.4.0' compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha3' }
下記のコードを試す上で基本となるレイアウトなどのソースコード
Android Studioに用意されているNavigation Drawer Activityのプロジェクトのものをほとんどそのまま利用しています。
一応見たいという方はこちらよりご確認ください。
HeaderViewのレイアウトを変更する
NavigationView.removeHeaderView(View view)
とNavigationView.addHeaderView(View view)
を使えば特に難しいことを考えずサクッと入れ替えられました。
fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // HeaderViewを変更できるテストとしてHeaderViewが1個以上あれば // HeaderViewを消すテスト if(navigationView.getHeaderCount() >= 1) { navigationView.removeHeaderView(navigationView.getHeaderView(0)); } else { navigationView.inflateHeaderView(R.layout.nav_header_main); } } });
サイドメニューの項目を変更する場合
一部の項目の表示/非表示にする場合。
boolean isMenuGroup1Visible = true; FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 一部のmenuの項目の表示/非表示を切り替えるテスト navigationView.getMenu().setGroupVisible(R.id.menu_group_1, !isMenuGroup1Visible); isMenuGroup1Visible = !isMenuGroup1Visible; } });
サイドメニューの項目をがらっと変えたい場合。
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // サイドメニューの項目をmenuリソースから生成し直す場合 navigationView.getMenu().clear(); navigationView.inflateMenu(R.menu.test); } });
<!-- test.xml --> <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/nav_gallery" android:icon="@drawable/ic_menu_gallery" android:title="Gallery" /> <item android:id="@+id/nav_slideshow" android:icon="@drawable/ic_menu_slideshow" android:title="Slideshow" /> <item android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage" android:title="Tools" /> </menu>
サイドメニューの項目にバッジをつけたい場合
menuリソースのitem要素の属性に、バッジの元となるWidgetのクラスとしてTextViewを指定して...とありましたが、この方法だと、どうも追加した要素の高さをうまく調整できなかったので、MenuItemCompat.setActionView(MenuItem menuItem, int layoutRes)
メソッドで、バッジ用に用意したレイアウトを与えて、そのレイアウトを変更してやる方がいじりやすそうでした。
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/nav_gallery" android:icon="@drawable/ic_menu_gallery" android:title="Gallery" /> <item android:id="@+id/nav_slideshow" android:icon="@drawable/ic_menu_slideshow" android:title="Slideshow" /> <item android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage" android:title="Tools" /> </menu>
<!-- nav_menu_badge.xml --> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:gravity="center" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:textColor="@android:color/white" android:id="@+id/badge_text" android:background="@color/colorAccent" android:padding="4dp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
MenuItem galleryItem = MenuItemCompat.setActionView(navigationView.getMenu().findItem(R.id.nav_gallery), R.layout.nav_menu_badge); TextView badgeText = (TextView) galleryItem.getActionView().findViewById(R.id.badge_text); badgeText.setText("99"); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // バッジを消したり、内容を変更したりするテスト LinearLayout galleryBadge = (LinearLayout) MenuItemCompat.getActionView(navigationView.getMenu().findItem(R.id.nav_gallery)); TextView badgeText = (TextView) galleryBadge.findViewById(R.id.badge_text); if(badgeText.getText() == "99+") { MenuItemCompat.setActionView(navigationView.getMenu().findItem(R.id.nav_gallery), null); } else { badgeText.setText("99+"); } } });
下に固定のfooterをつけたい場合
NavigationView
の中にandroid:layout_gravity="bottom"
の指定をつけて要素を追加したらよさそうでした。
<!-- activity_main.xml --> <?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:openDrawer="start"> <include layout="@layout/app_bar_main" android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header_main" app:menu="@menu/activity_main_drawer" > <TextView android:text="Footerのテスト" android:gravity="center" android:layout_gravity="bottom" android:background="@color/colorAccent" android:padding="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </android.support.design.widget.NavigationView> </android.support.v4.widget.DrawerLayout>
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.setDrawerListener(toggle); toggle.syncState(); }
追加したFooterとかぶった部分についてスクロールさせたいときはどうするかについては、対処が若干微妙で、アイコン透明なものを用意した選択不可能なメニューをその部分に追加するのが自分が探した中で綺麗な方の解決方法でした....^^;