リソースのmemcache化で効果が有ったのでクラスのロードでも 同じ効果が無いか試して見ることにした。

やり方としては自前のクラスローダからServletを生成して 以下は自前のクラスローダからクラスを読み込ませる。 memcacheにはクラスを byte[] で保存して置く。

但し、java.* や com.google.* のパッケージは自前のクラスローダ からの読み込みを許可されないので避ける必要がある。

実験結果:

  • 標準
     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 
    

  • memcache付き自前クラスローダ
     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 側に何らかのチューニング が入っていると言うことだろうか。
    まぁそうで有っても全然不思議じゃ無い。

    効果無かったけど一応実験ソースは置いておく。

  • 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; } }

    関連記事: