1

我正在尝试使用免费的 Google App Engine 作为我的下一个 Android 应用程序的 Google Cloud Messages 的后端,但是当我“完成”编写服务器时,它已经使用了几乎 100% 的免费前端实例小时数。我的问题是我是否以及如何改善这一点?

该应用程序是一个 servlet,每 15 分钟从 cron 作业调用一次,servlet 下载并解析 3 个 RSS 提要并检查自上次调用以来是否有任何更改,将日期保存到数据库(JDO 和 memcache,3 次调用)以知道上次运行是什么时候,以及自上次呼叫将信息发送到连接的手机后是否发生了任何变化,现在有 3 部手机已连接,这只是对 Google 服务器的一次呼叫。servlet 不返回任何数据。

这是代码

public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException
{
    boolean sendMessage = false;

    String eventsFeedUrl = "http://rss.com";
    String newsFeedUrl = "http://rss2.com";
    String trafficFeedUrl = "http://rss3.com";

    response.setContentType("text/plain");
    Message.Builder messageBuilder = new Message.Builder();
    String messageData = getFeedMessageData(eventsFeedUrl);
    if (!messageData.equals(StringUtils.EMPTY))
    {
        messageBuilder.addData("event", messageData);
        sendMessage = true;
    }
    messageData = getFeedMessageData(newsFeedUrl);
    if (!messageData.equals(StringUtils.EMPTY))
    {
        messageBuilder.addData("news", messageData);
        sendMessage = true;
    }
    messageData = getFeedMessageData(trafficFeedUrl);
    if (!messageData.equals(StringUtils.EMPTY))
    {
        messageBuilder.addData("traffic", messageData);
        sendMessage = true;
    }
    if (sendMessage)
    {
        sendMessage(messageBuilder.build(), response, debug);
    }
}

private void sendMessage(Message message, HttpServletResponse response, boolean debug)
    throws IOException
{
    SendResult sendResult = GCMService.send(message, Device.list());
    int deleteCount = 0;
    for (MessageResult errorResult : sendResult.getErrorResults())
    {
        if (deleteCount < 200 && (errorResult.getErrorName().equals(Constants.ERROR_NOT_REGISTERED) || errorResult.getErrorName().equals(Constants.ERROR_INVALID_REGISTRATION)))
        {
            Device.delete(errorResult.getDeviceId());
            deleteCount++;
        }
    }
}

private String getFeedMessageData(String feedUrl)
{
    String messageData = StringUtils.EMPTY;
    FeedHistory history = FeedHistory.getFeedHistoryItem(feedUrl);
    Feed feedContent = RssParser.parse(feedUrl);
    if (feedContent != null && feedContent.getFeedItems().size() > 0)
    {
        if (history == null)
        {
            history = new FeedHistory(feedUrl);
            history.setLastDate(new Date(0));
            history.save();
        }
        for (FeedItem item : feedContent.getFeedItems())
        {
            if (item.getDate().after(history.getLastDate()))
            {
                messageData += "|" + item.getCountyId();
            }
        }
        if (!messageData.equals(StringUtils.EMPTY))
        {
            messageData = new SimpleDateFormat("yyyyMMddHHmmssZ").format(history.getLastDate()) + messageData;
        }
        history.setLastDate(feedContent.getFeedItem(0).getDate());
        history.save();
    }
    return messageData;
}

调用 Device.list() 使用 memcache,因此在一次调用后它将被缓存,RSS 解析器是一个简单的解析器,它使用org.w3c.dom.NodeListjavax.xml.parsers.DocumentBuilder. 根据日志文件,我使用同一个实例好几天了,所以实例启动和占用资源没有问题。对 servlet 的正常调用在日志中如下所示,

ms=1480 cpu_ms=653 api_cpu_ms=0 cpm_usd=0.019673

我对接下来要尝试什么有了一些想法,尝试异步执行 RSS 下载调用以最小化请求时间。将 RSS 解析移至后台作业。还有什么可以做的?感觉就像我的代码在这里犯了一些基本错误,因为如果不能在 24 小时内调用 100 次 servlet 而不会消耗 100% 的前端时间,那么普通的 Web 应用程序如何工作。

/维克托

4

1 回答 1

5

您的空闲实例会在自行关闭之前停留一段时间。我不知道这是多长时间,但我猜它在 5-15 分钟范围内。如果它实际上是 15 分钟,那么您的 cron 作业每 15 分钟点击一次它会使其无限期地保持活动状态,因此您最终将每天使用 24 个实例小时。

您可以通过将您的 cron 作业设置为每 30 分钟运行一次来​​测试这个理论,并查看它是否将您的实例小时使用量减半。

于 2012-07-24T02:23:53.407 回答