MySQLにmemcachedプラグインを入れる
1.libevent-develをインストール
# yum -y install libevent-devel
2. my.cnfにmemcacheの設定を追加
daemon_memcached_option = "-p11211"
daemon_memcached_engine_lib_name = innodb_engine.so
daemon_memcached_r_batch_size = 1
daemon_memcached_w_batch_size = 1
3.memcachedプラグインをインストールする
mysql> INSTALL PLUGIN daemon_memcached soname "libmemcached.so";
mysql> show plugins;
daemon_memcached というプラグインが入ったことを確認
4.テスト用のテーブルを作成する
mysql> use test
mysql> create table user (id varchar(16), passwd varchar(256), primary key(id)) engine=InnoDB;
mysql> insert into user (id, passwd) values ('user01', '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8');
※insertしたpasswdカラムの値は"password"をsha256したもの
5.memcache経由でアクセスできるようにする
mysql> insert into innodb_memcache.containers (`name`,`db_schema`,`db_table`,`key_columns`,`value_columns`,`flags`,`cas_column`,`expire_time_column`,`unique_idx_name_on_key`) VALUES ('user', 'test', 'user', 'id', 'passwd',0,0,0,'PRIMARY');
mysql> UNINSTALL PLUGIN daemon_memcached;INSTALL PLUGIN daemon_memcached soname "libmemcached.so";
@@(innodb_memcache.containersのnameカラムの値).keyとしてアクセス可能
$ telnet 127.0.0.1 11211 して get @@user.user01 とタイプした時にsha256の文字列が返ってくればOK
6.Java側を実装する
↓あたりからspymemcachedをダウンロードするhttp://www.java2s.com/Code/Jar/s/Downloadspymemcached27jar.htm
※もちろんMavenで対応してもOK
今回はID,PassをJSONでPOSTした際に、ユーザ登録があった場合には200、無かった(ID,Passが一致しない)場合には401が返ってくるRestAPIをJavaEEのJAX-RSで作成してみた。
package memcached;
import java.net.InetSocketAddress;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import net.spy.memcached.MemcachedClient;
@RequestScoped
@Path("/auth")
@Produces("application/json")
@Consumes("application/json")
public class Memcache {
@POST
public Response auth (Map<String, String> param) {
ResponseBuilder response = null;
try {
MemcachedClient memcachedClient = new MemcachedClient (new InetSocketAddress("192.168.56.102", 11211));
if ( sha256( param.get("password") ).equals( memcachedClient.get( "@@user." + param.get("id") ).toString() ) ) {
response = Response.status(200);
} else {
response = Response.status(401);
}
} catch (Exception e) {
response = Response.status(400);
}
return response.build();
}
private String sha256(String plaintext) throws Exception{
MessageDigest md = MessageDigest.getInstance("SHA-256");
StringBuilder sb = new StringBuilder();
md.update(plaintext.getBytes());
for (byte b : md.digest()) {
String hex = String.format("%02x", b);
sb.append(hex);
}
return sb.toString();
}
}
「value_columns: CHAR、VARCHAR、または BLOB カラムにマップされる必要があります」とのことで、JSON型のフィールドをそのままmemcachedで扱うことは不可能(telnetしてみると応答はあるけど中身ぐちゃぐちゃ)
→ https://dev.mysql.com/doc/refman/5.6/ja/innodb-memcached-internals.html
CASTすれば大丈夫なのか不明だが、何もせずとも対応できるようにしてくださいな。>Oracleさん
(追記)
generated columnを使って、JSON型のカラムからTEXT型のカラムを生成してvalue_columnsに指定してみた。
mysql> create table userinfo (id varchar(16), infojson json, userinfo text as (cast(infojson as char) engine=InnoDB;
mysql> insert into innodb_memcache.containers (`name`,`db_schema`,`db_table`,`key_columns`,`value_columns`,`flags`,`cas_column`,`expire_time_column`,`unique_idx_name_on_key`) VALUES ('userinfo', 'test', 'userinfo', 'id', 'userinfo',0,0,0,'PRIMARY');
mysql> UNINSTALL PLUGIN daemon_memcached;INSTALL PLUGIN daemon_memcached soname "libmemcached.so";
結果、NG!
逆(text型からjson型をgenerated column)なら出来るんだろうけど、json関数使った更新系クエリ使えないから美味しさ半減。。