实例之间的Google App Engine对象交换

时间:2014-06-26 21:13:21

标签: java google-app-engine cron

我正在运行GAE java应用程序并使用后端实例进行一些计算。 在计算之后,后端实例创建了一个映射,该映射应该在服务http请求时由前端使用。

最初我创建了静态地图,并使用在后端实例上运行的cron作业更新了地图值。但是当我尝试通过发送http请求来检索值时,我仍然得到旧值。这是我的代码

public class ServerServlet extends HttpServlet {

public static Map<String,String> highQualityMap;

protected void doGet( HttpServletRequest request,
        HttpServletResponse response)
                throws ServletException, IOException {
    try{
        String uri = request.getRequestURI();
        PrintWriter out = response.getWriter();

        if(uri.equalsIgnoreCase("/getstatus")){
            String id = request.getParameter("id");
            out.write(highQualityMap.get(id));
        }
        else if(uri.equalsIgnoreCase("/recacheAll")){
            System.out.println("recache all");
            buildData();
        }
        if(out!=null)
            out.close();
    }
    catch(Exception e){
        e.printStackTrace();
    }
}

private void buildData(){
    // here after some processing, data is populated in highQualityMap
}

}

这是我的cron.xml

<?xml version="1.0" encoding="UTF-8"?>
<cronentries>
  <cron>
    <url>/recacheAll</url>
    <description>Repopulate the cache every 3 hours</description>
    <schedule>every 3 hours</schedule>
    <target>backend</target>
  </cron>
</cronentries>

这是我的backends.xml

<?xml version="1.0" encoding="UTF-8"?>
<backends>
    <backend name="backend">
        <class>B1</class>
        <options>
            <dynamic>true</dynamic>
            <public>false</public>
        </options>
    </backend>
</backends>

我相信前端和后端实例分别运行并且不共享对象。当我在前端运行cron作业时,它会获取正确的数据。 所以我正在寻找一种方法,以便我可以在前端使用相同的计算映射。

Update1:​​在后端计算hashmap之后,我尝试将其保存在数据存储区中,但是我收到一条错误,指出“java.util.HashMap不是受支持的属性类型”。因此,我创建了列表并尝试将其存储在数据存储区中,而不是创建地图。但是由于对实体大小的限制(1mb),我无法将arraylist也存储在数据存储区中。

Update2:我将地图转换为列表,将其拆分为多个较小的列表,并将它们存储到数据存储的不同实体中。存储之后,我启动了一个应该在前端执行的任务。此任务从数据存储中读取较小的列表,从中创建一个大列表,最后创建一个我保留在内存中的映射。

1 个答案:

答案 0 :(得分:0)

您至少有五个选择:

  1. POST(我不确定App Engine的限制是什么,但我猜想最多10MB就可以了。)
  2. 数据存储区(无限制)。
  3. Google云端存储(无限制)。
  4. 专用内存(最多1MB)。
  5. 由数据存储区支持的常规内存缓存(最多1MB)。
  6. 假设您的对象适合Memcache,最后一个选项可能是最具成本效益的。您的后端实例创建一个映射,将其放入数据存储区并将其放入Memcache中。您的前端实例尝试从Memcache加载它。如果它在那里不可用,它会从数据存储区加载它并将其放入Memcache中以备它再次需要它。

    更新:

    虽然您的地图很大,但您仍然可以使用最后一个最有效的选项。在后端:

    ArrayList<Entity> batch = new ArrayList<Entity>(500);
    
    for (String key : map.keySet()) {
    
        memcache.put(key, map.get(key));
    
        Entity entity = new Entity("Entry", key);
        entity.setUnindexedProperty("value", map.getKey());
        /* or, if a value can be longer than 500 characters
         * entity.setUnindexedProperty("value", new Text(map.getKey()));
         */
    
        batch.add(entity);
        if (batch.size() == 500) {
             datastore.put(batch);
             batch.clear();
        }
    }
    datastore.put(batch);
    

    如果您不需要知道前端的所有按键,这将有效。如果这样做,那么检查你的keySet()是否小于1MB,这样你就可以把它作为一个对象放在Memcache中。如果它更大,则跳过memcache部分并简单地使用数据存储区:

    Query q = new Query("Entry");
    // etc.