2011/02/27
GAE/Jのspinupとmemcache:クラスのキャッシュ化
リソースのmemcache化で効果が有ったのでクラスのロードでも
同じ効果が無いか試して見ることにした。
やり方としては自前のクラスローダからServletを生成して
以下は自前のクラスローダからクラスを読み込ませる。
memcacheにはクラスを byte[] で保存して置く。
但し、java.* や com.google.* のパッケージは自前のクラスローダ
からの読み込みを許可されないので避ける必要がある。
実験結果:
標準
memcache付き自前クラスローダ
まぁそうで有っても全然不思議じゃ無い。 効果無かったけど一応実験ソースは置いておく。 MemcacheClassLoader.java: memcacheを使うクラスローダ
package org.kotemaru.test;
import java.io.*;
import com.google.appengine.api.memcache.*;
public class MemcacheClassLoader extends ClassLoader {
private static final String NS_MEMCACHE = "MemcacheClassLoader";
private static MemcacheService memcache =
MemcacheServiceFactory.getMemcacheService(NS_MEMCACHE);
public MemcacheClassLoader(ClassLoader parent) {
super(parent);
}
protected synchronized Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
if (
name.startsWith("java")
|| name.startsWith("com.google.")
|| name.startsWith("org.xml.sax.")
|| name.startsWith("org.w3c.")
|| name.startsWith("sun.")
|| name.startsWith("org.mortbay.")
) {
try {
return getParent().loadClass(name);
} catch (ClassNotFoundException e) {
return loadClass0(name, resolve);
}
}
return loadClass0(name, resolve);
}
private Class loadClass0(String name, boolean resolve)
throws ClassNotFoundException
{
Class clazz = findLoadedClass(name);
if (clazz != null) return clazz;
clazz = findClass(name);
if (resolve) resolveClass(clazz);
return clazz;
}
protected Class findClass(String name) throws ClassNotFoundException {
try {
String path = name.replace('.','/')+".class";
//System.out.println("->"+path);
InputStream in = null;
try {
byte[] data = (byte[]) memcache.get(name);
if (data == null) {
in = getParent().getResourceAsStream(path);
data = readBytes(in);
memcache.put(name, data);
}
Class clazz = defineClass(name, data, 0, data.length);
return clazz;
} finally {
if (in != null) in.close();
}
} catch (Throwable t) {
throw new ClassNotFoundException(name, t);
}
}
private static byte[] readBytes(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buff = new byte[4096];
int n;
while ((n=in.read(buff)) > 0) {
out.write(buff, 0, n);
}
return out.toByteArray();
}
}
MemcacheCLServlet.java: MemcacheClassLoaderを使わせる為のラッパーServlet
package org.kotemaru.test;
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class MemcacheCLServlet extends HttpServlet {
private static final String ORIGIN = "org.kotemaru.test.Test2Servlet";
private HttpServlet origin;
public void init(ServletConfig config) throws ServletException {
try {
System.out.println("Initialize MemcacheCLServlet.");
MemcacheClassLoader ccl = new MemcacheClassLoader(this.getClass().getClassLoader());
origin = (HttpServlet) Class.forName(ORIGIN, true, ccl).newInstance();
origin.init(config);
} catch (Exception e) {
throw new ServletException(e);
}
}
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
origin.service(request, response);
}
}
Test2Servlet.java: ターゲットのServlet
package org.kotemaru.test;
import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.mozilla.javascript.*;
public class Test2Servlet extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
try {
System.out.println("start init.");
Context cx = Context.enter();
try {
Scriptable scope = cx.initStandardObjects();
String src = "var x=1;";
Script script = cx.compileString(src, "test.js", 1, null);
script.exec(cx, scope);
} catch (RuntimeException e) {
e.printStackTrace();
throw e;
} finally {
Context.exit();
}
} catch (Exception e) {
e.printStackTrace();
throw new ServletException(e);
}
}
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.getWriter().write("test");
return;
}
}
関連記事:
3602ms 2290cpu_ms 38834ms 2290cpu_ms 1442ms 1586cpu_ms 7532ms 2163cpu_ms 17550ms 2364cpu_ms 13556ms 2273cpu_ms 3111ms 2200cpu_ms 1224ms 1633cpu_ms 5620ms 2346cpu_ms 6169ms 2530cpu_ms
8000ms 4490cpu_ms 3946ms 4435cpu_ms 21187ms 4362cpu_ms 7975ms 4215cpu_ms 6042ms 3978cpu_ms 3722ms 3996cpu_ms 5941ms 4656cpu_ms 7032ms 4362cpu_ms 13031ms 4106cpu_ms 14204ms 4070cpu_ms 15714ms 4307cpu_msう、変わって無いと言うか逆に遅くなってる。 コード自体かなり余分な処理が処理が入るのでCPU時間が 増えるのは仕方無いが I/O 待ちを減らすメリットは 出ていないみたいだ。 さすがにクラスロードに関しては GAE 側に何らかのチューニング が入っていると言うことだろうか。
まぁそうで有っても全然不思議じゃ無い。 効果無かったけど一応実験ソースは置いておく。
この投稿へのコメント

コメント・フォーム