<![CDATA[主持-此节目生活]]manbetx手机版登陆> 托管-此编程寿命manbetx手机版登陆 //www.djindien.com网站/ 幽灵0.11 结婚,2019年2月6日13:53:14格林尼治标准时间 六十 <![CDATA[在Google应用程序引擎上工作3年。史诗般的评论。]]> <p>在过去的3年里,我在一个运行在谷歌应用引擎上的应用程序上工作。这是一个迷人的,谷歌在这里提供的独特服务。不像其他地方的任何东西。这是我的深度,个人体验。<p><img src=“//www.djindien.com/content/images/2017/01/google-app-engine-logo.png”alt><p><h2 id=“googlescloudest2008”>google's cloud(est)。2008)<h2><p>First of all,什么是</P> //www.djindien.com/3-years-on-google-app-engine-an-epic-review网站/ CE13C232-987C-4382-BA01-48B806AC99CD型 群众或部队的集合 爪哇 数据仓库 谷歌 应用程序引擎 manbetx万博体育 周一,2017年3月13日格林尼治标准时间15:23:59 <p>在过去的3年里,我在一个运行在谷歌应用引擎上的应用程序上工作。这是一个迷人的,谷歌在这里提供的独特服务。不像其他地方的任何东西。这是我的深度,个人体验。<p><img src=“//www.djindien.com/content/images/2017/01/google-app-engine-logo.png”alt><p><h2 id=“googlescloudest2008”>google's cloud(est)。2008)<h2><p>First of all,Google应用引擎实际上是什么?它是一个运行Web应用程序的平台。比如<a href=“https://www.heroku.com”>heroku</a>。但当你仔细看的时候就不同了。它也是一个多功能的云计算平台。比如<a href=“https://aws.amazon.com”>aws</a>。但不同。让我解释一下。<p>Google在2008年推出了GAE,当云计算还处于初级阶段时。亚马逊早在2006年就开始出租其IT基础设施。但与盖伊谷歌很早就提供了一个成熟的平台即服务(paas),亚马逊将在2011年将其与弹性豆茎服务相匹配。盖伊有什么特别之处?<p><p>it is a<em>fully managed.<em>application platform.到目前为止,我不知道一个平台可以接近GAE的完整包:日志管理,邮件投递,缩放比例,内存缓存图像处理,分布式cron作业,负载均衡,版本管理,任务队列,搜索,性能分析,云调试,内容交付网络——这甚至没有提到像SQL一样出现在谷歌云上的辅助服务,BigQu疑问,文件存储…名单还在继续。<p>by using google app engine,你可以在世界上最好的基础设施之上运行你的应用程序。也,您可以从Heroku上的第三方获得至少十几个附加组件,如果您自己完成,则需要几个星期的安装。<em>这是GAE的吸引力。<p><p>在GAE上运行的值得注意的应用程序包括<a href=“https://www.snapchat.com”>snapchat<a>和<a href=“https://www.khanacolademy.org”>khan academy<a><p><h2 id=“development”>development<h2><p>web a p p i was working on all this time i s a single,大型Java应用程序。应用引擎也支持python,PHP和GO。现在你可能想知道为什么选择如此有限。一个原因是为了拥有一个完全管理的环境,谷歌需要将这个平台与环境结合起来。您可以说环境和平台是紧密耦合的。这需要大量的努力和投资,一旦您开始为GAE开发,这一点就变得非常清楚了。<p><h3 id=“sdk”>sdk<h3><p>每个应用程序都需要使用一个特殊的sdk(软件开发工具包)来使用GAE提供的API。SDK是巨大的。例如,Java SDK下载大约是190 MB。授予,其中的一些jar对于大多数用例来说是不需要的,有些只是在开发过程中——但仍然是,它当然不是轻量级的(甚至对于Java来说,也就是)。<p><p>The sdk is not just your bridge to the world of google app engine but also services as its simulation on your local machine.对于几乎每一个GAE API,它都有一个存根,您可以针对它进行开发。首先,这意味着当你在本地运行你的应用程序时,你会非常接近它在生产中的表现。其次,您可以轻松地针对API编写集成测试。通常这会让你走得很远;生产和存根行为之间的不匹配很小。</P> < H3ID=“JavaAPI”> JAVA API < /H3> < API >当你使用某些Java API时,你会感到惊讶。因为gae在某种类型的<a href=“https://cloud.google.com/appengine/docs/java/runtime”中运行应用程序?csw=1 The The诳Sandbox“>Sandbox</a>,它禁止使用特定的Java API。主要限制包括写入文件系统,<代码> java. Lang.Stase<代码>和使用Java本机接口(JNI)的某些方法。使用线程和套接字也有一些特殊之处,但稍后将详细介绍。一个有趣的事情是,Java SDK实际上确保您不在本地使用这些受限API。当你运行你的应用或者只是一个集成测试时,它使用一个监视每个方法调用的Java代理。它会立即对任何检测到的违规抛出异常。这有助于尽早发现违规行为,不仅在生产中,而且会产生令人讨厌的副作用。当你分析你的应用程序的性能时,代理商将进行大量的违规检查。最后,很难判断你的应用程序的实际性能,因为你做的方法调用越多,代理生成的开销越大。</P> < H3ID=“JavaDevelopment KITJDK”> Java开发工具包(JDK)</H3>< P>在开发过程中,您可能注意到的下一件事是,可以使用< 8】。即使Java 7的生命终结在2015,它仍然是非常活跃和踢同性恋。在GAE的问题跟踪程序上,第三大投票问题是<a href=“https://code.google.com/p/googleappengine/issue s”>a>is<a href=“https://code.google.com/p/googleappengine/issue s/detail?Id=9537“>支持Java 8 </a>(第二个最高值是对Python 3的支持)。创建于2013年。从那时起,关于这件事进展的唯一消息就是2016年发布在应用引擎邮件列表上。说明工程师们正在积极地进行这项工作。好,对你有好处。<p>显然,这个限制对于任何开发人员都是一个主要的麻烦。就我个人而言,缺失的lambda支架很重。当然,可以迁移到许多JVM语言中的一种,比如groovy,Scala或Kotlin,它们都提供了比Java 8更多的特性。但这是一项昂贵且风险很大的投资。对我们的项目来说太昂贵和冒险了。我们还调查了逆行lambda的可行性。LAMBDAS到Java 7的后端,但是还没有追求它,尽管它在第一次测试中看起来很有前途。.<p>Having to stay with a old version is also a responsibility for the business.这使得很难找到开发人员。整个应用程序安全受到威胁,也。谷歌支持告诉我们,我们仍然会收到生产JDK7的安全补丁。但最终,像Spring这样的所有主要图书馆都将停止支持它。最终,您将被卡在部署中。您需要创建一个<code>appengine web.xml<code>configuration file。在那里,指定应用程序ID和版本以及一些附加设置,例如将应用程序标记为<代码> THeRealStaby<代码>,以同时接收多个实例的请求。</P> < H3ID=“上载”>上载</H3> < P> AppEngine,希望接收Java应用程序作为打包的WAR文件。您可以使用SDK中的<code>appcfg<code>script将其上载到服务器。可选地,Maven和Gradle有插件,这使得编写<code>mvn appengine:update更容易。对于典型的Java应用程序,上传可以采用<e> > </e>你最好有一个快速的互联网连接。一旦过程完成,您可以在Google云控制台中看到您新部署的版本:<p><p><img src=“//www.djindien.com/content/images/2017/01/screen-shot-2017-01-22-at-15.15.45-2.png”alt=“Google云控制台-版本”><p><h3 id=“static files”>static files<h3><p>static files like images,样式表和脚本是当今任何Web应用程序的一部分。在<code>appengine web.xml中,文件可以标记为static。谷歌将直接提供这些文件,而不必点击你的应用程序。它不是内容交付网络(cdn),因为它不分布到数百个边缘节点,但它有助于减少服务器上的负载。<p><h3 id=“versions”>versions<h3><p>The nice thing in a p p engine is that everything you deploy has a specific version.每个版本都可以在<code>https://<version>-dot-<app id>.appspot.com上访问。但哪一个实际上是<em>live?<p><p>You can mark a version as<code>default.<code>。这意味着当您转到<code>https://<app id>.appspot.com时(或您为应用程序指定的域名),会这将是接收所有请求的版本。将版本切换到<code>default<code>非常简单:只需单击按钮或简单的终端命令。GAE可以立即切换或增量迁移您的流量,以防止压倒新版本。<p>还有一个选项(我们从未使用过)允许您将流量分布到多个版本。这就允许在每个人都可以使用新版本之前,只将其提供给一小部分用户群,从而逐步推出新版本。<p>Since it is so easy to create new versions and switch production traffic between them,GAE是一个完美的实践平台<a href=“https://martinfowler.com/bliki/blue green deployment.html”>blue-green deployment<a>。每次我们因为新版本中的错误而需要回滚时,这是不费吹灰之力的。通过编写一个有点智能的部署脚本,也可以实现连续交付。<p><h3 id=“instances”>instances<h3><p>every version can run any number of instances(the only limit is your credit card).实际数量是传入流量和应用程序的缩放配置的结果;我们稍后再看。Google将在该版本的所有运行实例之间分发传入的请求。您可以看到实例列表,包括一些基本指标,比如请求和延迟,在google cloud console中:<p><img src=“//www.djindien.com/content/images/2017/01/screen-shot-2017-01-22-at-15.28.57.png”alt=“google cloud console-instances”><p><p>The hardware options you can choose from to run these instances on are-let's be frank here-pathetic.app engine基本上提供了四种不同的<a href=“https://cloud.google.com/app engine/docs/about the standard environment instance _classes“>instance classes<a>范围从128MB和600MHz cpu(正确读取)到1024MB和2.4GHz cpu。对,再一次,那是真的。真的很伤心。在开发人员的笔记本电脑上,我们的应用程序的启动速度几乎是生产中的两倍。<p><h3 id=“services”>services<h3><p>so far,我只谈过单身,单片应用。但是,如果您的服务由多个服务组成,您会怎么做?应用引擎为您提供服务。每个应用程序都是一项服务。如果你只有一个,它被简单地称为<code>default<code>。您可以通过<code>https:/<version>-dot-<service>-dot-<app id>.appspot.com直接访问每个应用程序。<code><p><img src=“//www.djindien.com/content/images/2017/02/screen-shot-2017-02-20-at-21.36.57.png”alt=“app engine application,服务,版本和实例“><p><p>You can easyly deploy multiple versions of each service,分别缩放和监控。因为每项服务都是独立的,您可以运行受支持语言的任意组合。但不幸的是,某些配置设置在所有服务之间共享。因此,它们并不是完全孤立的。不过,总而言之,gae似乎很适合微服务。这里有一些< HeRF=“http://vult./com/AppEngine /DOCS/Java/MauleService AppEngine”>关于谷歌主题的详细文档</A>,也。<p>for reasons that will been clear later,<p>for reasons that will been clear,我们决定将应用程序分为两个服务:前端(面向用户)和后端(后台工作)。但要做到这一点,实际上,我们并没有将整块巨石一分为二——这需要几个月的时间。我们只部署了同一个应用程序两次,只将用户发送到一个服务,将后台工作发送到另一个服务。<p><h2 id=“operations”>operations<h2><p>let's talk about what it means to<em>run<em>your application on app engine.如你所见,它对你施加了许多限制。但这并不都是悲观的。最后,您将了解为什么。<p><h3 id=“applicationStartup”>application startup<h3><p>when a p p engine starts a new instance,应用程序需要初始化。它将直接从用户向应用程序发送HTTP请求,或者(如果配置和缩放环境允许)发送一个所谓的预热请求。不管怎样,第一个请求称为加载请求。你可以想象,快速启动很重要。<p>The instance self on the other hand is荒谬的fast to start.如果您以前在云中启动过服务器,你可能等了一分钟多。不是在盖伊上。实例几乎立即启动。我想谷歌有一个服务器池准备好了。瓶颈总是你自己的应用程序。我们的应用程序用了40多秒才开始生产。所以除非我们想把我们巨大的巨石分割成单独的服务,我们需要它来提高效率。<p>The app uses spring.Google甚至还有一个专门的文档条目用于此目的:<a href=“https://cloud.google.com/app engine/articles/spring_optimization”>optimizing spring framework for app engine applications<a>。在那里,我们找到了最重要的启动优化的灵感。<p>我们摆脱了Spring的类路径扫描。它在应用程序引擎上特别慢(可能是由于糟糕的CPU)。幸运的是,有一个名为classindex的库。它将具有特殊注释的类的完全限定路径写入文本文件。只需从文本文件中读取bean,Spring初始化下降了约8-10秒。<p><h3 id=“RequestHandling”>Request Handling<h3><p>The very first thing I have to notify here is the requirement of the a p p engine to handle a user request within 60 seconds and a background request in 10 minutes.当应用程序响应时间过长时,请求被中止,状态代码为500,异常情况为<code>deadlineexceedexception<code>is through.<p>通常,这不应该是个问题。如果您的应用程序响应时间超过60秒,很有可能用户早就不在了。但由于实例是通过HTTP请求启动的,这也意味着它必须在60秒内启动。在生产中,我们观察到启动时间变化达10秒。这意味着你现在有不到50秒的时间来启动你的应用程序。Java应用程序花这么长时间并不少见。</P> < P>一个很好的小功能,我想强调的是地理HTTP报头:对于每一个传入的用户请求,谷歌添加了包含用户国家的标题,区域,城市及其经纬度。这可能非常有用,例如,预填电话号码国家代码或检测异常帐户登录位置。从我们的观察结果来看,准确度也相当高。从第三方API或数据库中获得这样高精度的信息通常非常麻烦和/或昂贵。因此免费获得应用程序引擎是一个不错的奖励。<p><h3 id=“background work”>background work<h3><h4 id=“threads”>threads<h4><p>as provided early,使用Java线程有限制。虽然可以启动一个新线程,尽管通过自定义GAE<code>threadmanager<code>,它不能“超过”在中创建的请求。这在实践中可能很烦人,因为第三方库不遵守应用程序引擎的限制,当然。要找到一个兼容的库或修改一个看似不兼容的库,这些年来我们付出了很多汗水和眼泪。例如,我们无法使用<a href=“https://github.com/dropwizard/metrics”>dropwizard metrics<a>library out of the box,因为它依赖于使用后台线程。<p><h4 id=“queue”>queue<h4><p>但是还有其他方法来执行后台工作:in the spirit of the cloud,您可以在实例级别应用分而治之的方法。通过使用<HeRF=“http://Loop.com /AppEngine /DOCS/Java/TaskQue/”>任务队列</A>,您可以排队等待以后的处理。例如,当需要发送电子邮件时,您可以使用有效负载(例如收件人,subject和body)和一个url。然后,其中一个实例将作为对指定端点的HTTP POST请求接收负载。如果失败了,a p p engine将重试此操作。<p><p>当您有大量工作要处理时,此模式真的很亮。只需将一批独立运行的任务排队即可。应用程序引擎将负责处理故障。不需要自定义重试代码。想象一下没有它会有多尴尬:一次运行数百个任务,当发生错误时,您要么需要停止并从头开始,要么仔细跟踪哪些任务失败了,然后再次将它们排队进行另一次尝试。<p>and just like the rest of the app engine,任务队列的规模非常庞大。队列可以接收几乎无限的任务。缺点是有效负载最多只能达到1 MB,不过。但我们通常只需将对数据的引用传递到队列。但是,在处理数据时,您需要格外小心,因为很容易在您将任务排队到实际执行该任务的时间之间,会有一些东西消失。<p><p>The queues are configured in a<code>queue.xml.<code>file.下面是一个推送队列的示例,该队列每秒最多触发一个任务,最大重试次数为两次:<p><pre><code class=“language xml”><queue><name>my push queue<name><rate>1/s<rate><retry parameters><task retry limit>2<task retry limit><retry parameters><queue><code><pre><h4 id=“cron”>cron<h4><p>another extreme valible工具是分布式cron。在<code>cron.xml中,您可以告诉GAE以特定的时间间隔发出请求。这些只是简单的HTTP GET请求,您的一个实例将接收这些请求。可能的最小间隔是每分钟一次。它对定期报告非常有用,电子邮件和清理。<p><p>This is what an entry in<code>cron.xml</code>looks like:<p><pre><code class=“language xml”><cron><url>/tasks/summary<url><schedule>every 24 hours.<schedule><cron><code><p>a cron job can also be combined with<em>pull<em>queues:they allow to activitive fetch a batch of tasks from a queue.取决于用例,使一个实例在一个批处理中拉取大量任务比单独将它们推送到实例中效率更高。<p><p>like all other a p p engine configuration files,在应用程序的所有服务和版本之间共享<code>cron.xml。这可能很烦人。在我们的例子中,有时,当我们部署一个版本,其中添加了一个新的cron条目时,应用程序引擎将开始向一个端点发送请求,该端点在活动(但较旧)版本上不存在,从而为我们的生产错误报告生成噪音。我想,当使用应用引擎托管微服务时,这肯定会更加痛苦。<p>also,cron作业不在本地运行。我可以理解为什么会这样:很多工作通常安排在通常繁忙的时间之外,因此在正常工作日甚至不会触发。但是,每隔几分钟或几小时运行一次,这些都是非常有趣的观察。它们可能触发通知,例如。你想在当地看看。因为最终您将引入一个导致不良行为(在我们的项目中多次发生)的变更,并且在本地看到它可能会阻止您装运它。但是在本地模拟cron作业是很棘手的(我们不费心,不幸的是)可能需要编写一个外部工具来解析cron.xml<code>cron.xml,然后ping相应的端点(yuck!).<p><h3 id=“scaling”>scaling<h3><p>app engine will care of scaling the number of instances based on the traffic.怎么用?好,取决于您如何配置应用程序。有三种模式:<p><ul><li><strong>automatic:<strong>this is gae's unique selling point.它将根据请求率和响应延迟等指标来扩展实例的数量。所以如果有很多流量或者你的应用程序响应缓慢,更多实例启动。<li><li><strong>manual:<strong>基本上喜欢您的旧虚拟专用服务器。你告诉谷歌你想要多少实例,谷歌提供。如果您知道要获得什么流量,这个固定的实例大小很有用。<li><li><strong>basic:<strong>本质上与手动缩放模式相同,但是当实例变为空闲时,它是关闭的。<li>><ul>><p>这里最有用和最有趣的一个当然是<em>自动模式</em>。它有几个参数,有助于阐明其内部工作方式:<code>max_concurrent_requests<code>,<code>max_idle_instances<code>,<code>min_idle_instances<code>and<code>max_pending_latency<code>。引用应用引擎文档:<p><blockquote><p>The app engine scheduler decides when to service each new request with an existing instance(either one that is idle or accepts concurrent requests),将请求放入挂起的请求队列,或者为该请求启动一个新实例。该决定考虑了可用实例的数量,应用程序服务请求的速度(延迟时间)有多快,以及每次我们试图调整这些数字时,旋转一个新实例所需的时间。<p>.<blockquote><p>感觉像是在练习黑魔法。实际上很难在这里推断出一个好的设置。然而,这些数字决定了你的应用程序的真实性能,并极大地影响你的每月账单。<p>but all in all,自动缩放非常糟糕。它特别适合处理背景工作(例如生成报告,发送电子邮件),因为它通常比用户请求更大,突然爆发。<p><p>但是事情是,Java是一个可怕的适合这种类型的自动缩放,因为其启动时间慢。更糟的是,调度程序通常会将请求分配给一个启动的<em>(cold)实例。然后,所有进入亚秒休息反应的努力都被抛到了窗外。自2012年以来,有关于<a href=“https://code.google.com/p/googleappengine/issues/detail的问题吗?id=7865“>面向用户的请求永远不会锁定到冷实例上。它甚至没有引起google的任何评论,除了状态更改为“已接受”(听起来像是此时的悲伤阶段之一)。<p><p>This also explains why we split our app into two services.以前,我们经常发现,随着后台请求的激增,用户请求会受到影响。这是因为应用引擎极大地扩展了实例,由于请求在实例之间均匀路由,这导致更多的用户请求命中冷实例。通过拆分应用程序,我们显著减少了这种情况的发生。也,我们能够为这两个服务应用不同的扩展策略。<p>One last thing:in a side project,我使用了Go-on应用程序引擎,在应用程序引擎上发现了一个新的视角。Go的特点之一是能够即时启动应用程序。这使得应用引擎成为完美的组合,像蝙蝠侠和罗宾。一起,它们体现了自我了解到云以来我个人所期望的一切。它可以真正地适应工作负载,而且很容易做到。即使是糟糕的硬件选项似乎也不会给Go带来真正的问题,因为它是如此高效。<p><h2 id=“data”>data<h2><p>when a p p engine launched,唯一的数据库选项是用于结构化数据的google datastore和用于二进制数据的google blobstore。从那时起,他们添加了谷歌云SQL(ManagedMySQL)和谷歌云存储(如亚马逊的S3),取代了blobstore。从一开始,应用引擎就提供了一个托管的memcache,同样。.<p><p>由于您只能使用HTTP进行通信,因此很难连接到第三方数据库。但通常数据库需要原始TCP。这只是在几年前SocketAPI发布时发生的变化。但在beta中仍然是<em>still<em>这使得它成为关键任务使用的可疑选择。所以数据库方面,仍然有很多供应商锁定。<p>anythy,一开始,只有数据存储。<p><h3 id=“datastore”>datastore<h3><p>The datastore is a proprietary nosql database,完全由谷歌管理。这和我以前用过的任何东西都不一样。它是一种巨大的鳞状动物,具有非常独特的特征,保证和限制。<p>数据存储基于主从设置,具有强一致的读取功能。几年后,在经历了几次严重的外泄之后,google<a href=“http://googleappengine.blogspot.ca/2011/01/announcing high replication datastore.html”>引入了新的配置选项</a>:high replication。API保持不变,但写入延迟增加,一些读取最终变为<em>一致(稍后详细介绍)。其好处是显著提高了可用性。它甚至拥有99.95%的正常运行时间SLA。自从我和它合作以来,我从未遇到过数据存储可用性的单一问题。这只是您不必考虑的事情。<p><h4 id=“Entities”>Entities<h4><p>The basics of the datastore are simple.您可以读写实体。它们被分类为特定的类型。实体由<em>属性组成。属性具有名称和具有特定类型的值。类似于<code>string<code>,<code>boolean<code>,<code>float<code>或<code>integer<code>。每个实体也有一个唯一的<em>键</em><p><h4 id=“writing”>writing<h4><p>there is no schema anythy,不过。具有相同类型的实体看起来完全不同。这使得开发非常容易:只需添加一个新属性,保存它,它就会在那里。另一方面,您需要编写自定义迁移代码来重命名属性。原因是无法就地更新实体-必须加载该实体,已更改并再次保存。根据实体的数量,这可以成为一个非常重要的任务,因为您可能需要使用任务队列来规避请求时间要求。根据我的经验,这会导致整个地方出现旧的属性名,因为重构成本高且危险。<p>There are a some<a href=“https://cloud.google.com/datastore/docs/concepts/limits”>limits for working with entities.<a>。两个最关键的是:<p><ul><li>an entity may only be 1MB in total,包括编码实体的附加元数据<<li>You can only write to an entity(group,准确地说)每秒最多一次这可能是个问题。我们很少达到尺寸限制-但当我们做到了,很痛苦。客户数据可能会丢失。当您达到写速率限制时,下次试穿通常都可以。但当然,您必须设计应用程序,以最小化这种可能性。例如,像一个定期更新的计数器需要很多工作才能正确。Google甚至在<a href=“https://cloud.google.com/appengine/articles/sharding_counters”>using sharding to build a counter<a><p><h4 id=“reading”>reading<h4><p>an entity can be fetched by using its key or via query.按键读取是强一致的,也就是说,即使在获取实体之前更新了它,您也将收到最新的数据。然而,对于查询,这不是真的。它们最终是一致的。因此,写入并不总是立即反映出来。这会导致问题,可能需要缓解,例如,通过智能数据建模(例如使用助记键或利用特殊的数据存储功能(例如实体组)。<p><p>a query always specify an entity kind and optional filters and/or sort orders.必须索引筛选器或排序键中使用的每个属性。添加索引只能作为常规写入操作的一部分完成。不会像大多数SQL数据库那样在后台自动运行。索引还将增加写入操作的时间和成本(稍后将详细介绍)。如果查询涉及多个属性,它需要一个多索引。必须在名为<code>datastore indexes.xml的配置文件中指定。这里有一个例子:<p><pre><code class=“language xml”><datastore index kind=“employee”ancestor=“false”><property name=“lastname”direction=“asc”/><property name=“hiredate”direction=“desc”<datastore index><code><pre><p>in contrast to other databases,缺少多个索引不仅会导致效率低下,慢速查询-它将立即失败。数据存储尽其所能地强制执行性能查询。不等式滤波器,例如,仅支持单个属性。当然,总是有办法射自己的脚-但他们是罕见的。<p>there are some other features I cannot go into now,例如分页,预测查询和事务。转到<HeRF=“http://x.com,AppEngine /DOPCs/Stimult/Java/DATASOR/API概览”>数据存储文档</A>以了解更多信息,与其他数据库相比,读写操作非常慢。根据我的观察,按键读取平均需要10-20毫秒。很少有明显的偏差。我的最佳猜测是,谷歌序列化实体,实际上只有索引保存在内存中。<p>The pricing model appears to support that:You pay for stored data,读,写入和删除操作。就是这样。请注意,数据库内存不在该列表中。这些业务本身也很便宜:读取10万个实体的成本为0.06美元,10万写操作成本0.18美元-一个写操作可以是实际的实体写操作,也可以是每个索引写操作。如果你什么都不写,你什么都不付。但在一分钟内,您就可以写入千兆字节的数据。更重要的是:对于没有实体或十亿的数据库,读写性能基本上是相同的。它像疯了一样伸缩。<p><h4 id=“api”>api<h4><p>The api to the datastore feels<em>very<em>low-level.因此,对于任何严肃的Java应用程序,都没有办法绕过<HReF=“http://Github.com/Objyf/ObjyFy”> ObjyFix/A>。这是杰夫·施尼策写的图书馆。如果谷歌还没有这样做,他们应该给他开一张大支票,让应用引擎变得更好。他写这篇文章是为了自己的事业,但多年来他孜孜不倦的奉献精神,他在论坛上提供的大量文档和支持令人震惊。客观化,使用数据存储是非常有趣的。< /P> < P>这里是一个例子,从文档:</P><Prime>代码类=“语言Java”> @ Entityclass CAR{@ ID字符串VIN;string color;ofy().save().entity(新车(“123123”,“红色”)).now();car c=ofy().load().type(car.class).id(“123123”).now();ofy().delete().entity(c);<code><pre><p>objectify makes it really easy to declare entities as simple classes and then takes care of all the mapping between the datastore.<p><p>it also have a some tricks up its sleeve.例如,它带有一级缓存。这意味着,每当您通过键请求实体时,它首先检查请求范围的缓存是否已提取实体。这有利于提高性能。然而,它也可能会令人困惑,因为当您提取实体并修改它时,但是不要<em>保存它,下一次读取将产生相同的缓存,修改的对象。这会导致HeisenBugs。<p><h4 id=“development testing”>development&testing<h4><p>因为应用引擎是一个专有云数据库,你不能只在本地启动它。在计算机上运行应用程序时,模拟数据存储由SDK启动。它的行为非常接近生产环境。只有性能好得多,这可能会产生误导。<p>for running tests against the datastore,SDK还可以为您启动本地数据存储。然而,这必须是一个不同的实现,因为它的行为与运行应用程序的行为不同。当您意识到丢失的多索引将在本地执行应用程序时抛出错误,而不是在测试同一查询时,这一点就会变得明显。多年来,我不小心将几个索引缺失的查询发布到了生产环境中(通常仍处于beta切换之后),尽管我对此进行了测试。在与支持部门取得联系后,他们承认了这一监督,并承诺将予以纠正——一年多之后,他们仍然没有。<p><h4 id=“backups”>backups<h4><p>making backups of the datastore is an atrocious process.有手动和自动两种方式。当然,当您有生产应用程序时,您需要定期备份。官方的方式是在2012年推出的一个功能,仍然是阿尔法!<p><p>by adding an entry to your<code>cron.xml</code>you can initiate the backup process.条目将包括要备份的实体的名称,以及保存它们的Google云存储桶。当时间到了,它将用备份代码启动一些python实例,迭代数据存储并以某种专有的备份格式保存到您的bucket中。有趣的是,一个bucket可以包含多少个文件,所以你最好偶尔用一个新桶。<p><p>This is the absolute worst thing about the data store.<p><h3 id=“memcache”>memcache<h3><p>The other critical way to store data on app engine is memcache.默认情况下,你会得到一个共享的memcache。这意味着,它是在尽最大努力的基础上工作的,无法保证它将有多少能力。还有每GB每小时0.06美元的专用memcache。<p>Objectify is able to use this as a second level cache.只需用<code>>@cache->code>注释一个实体,它将在数据存储之前询问memcache,并首先将每个实体保存在那里。这会对性能产生巨大影响。通常Memcache会在5毫秒内响应,比数据存储快得多。我不知道我们可能有什么过时的缓存问题。因此,这在生产中非常有效。<p>当memcache关闭时,它的好处实际上非常明显。这种情况每年发生一次,持续了一两个小时。我们的网站几乎不可用,速度很慢。<p><h3 id=“big query”>big query<h3><p><a href=“https://cloud.google.com/big query/”>big query<a>is a data warehouse as a service,由谷歌管理。您可以导入数据(可以是千兆字节),并且可以通过自定义查询语言运行分析。<p>It integrated some well with the datastore because it allows to import datastore backup files from google cloud storage.我用过几次了,不幸的是,并非总是成功的。对于我们实体的某些实体,我收到了一个神秘的错误。我一直搞不清楚出了什么问题。但有些实体确实起了作用。在处理了一点查询语言文档之后,我能够产生我的第一个见解。所有的考虑,这是一种运行简单分析的好方法。如果不编写自定义代码,我肯定无法做到这一点。但我并没有充分利用这项服务的全部潜力。我所做的所有查询都可以直接在任何SQL数据库中完成,我们的数据集很小。只有因为数据存储的工作方式,我才不得不首先求助于BigQuery服务。<p><h2 id=“monitoring”>monitoring<h2><p>Google Cloud控制台带来了许多功能来诊断应用程序在生产中的行为。只需看看谷歌云控制台导航:<p><p><img src=“//www.djindien.com/content/images/2017/02/screen-shot-2017-02-27-at-19.58.46.png”alt=“google cloud console-monitoring”><p>this is the result of<a href=“https://techcrunch.com/2014/05/07/google acquires cloud monitoring service stackdriver/”>google's acquisition of StackDriver</a>2014年。感觉还是分开的,独立服务-但其与Google云控制台的集成正在改进。<p><p>让我们逐个查看功能。<p><h3 id=“logging”>logging<h3><p>it is critical to access an application's logs quickly and with ease.这是一个真正痛苦的应用程序引擎开始。它过去非常繁琐,因为它无法搜索应用程序的所有版本。这意味着当你在找东西的时候,你必须知道当时哪个版本是在线的-或者尝试几个版本,逐一地。它几乎不能用了。再加上它非常慢。<p><p>从那时起,他们添加了有用的过滤器,只显示特定的模块,版本,日志级别,用户代理或状态代码。它非常强大。仍然不快速但现在比早期好多了。以下是它的外观:<p><p><img src=“//www.djindien.com/content/images/2017/02/screen-shot-2017-02-27-at-20.26.16.png”alt=“google cloud console-logging”><p><p>one very unique idea you can see here is that logs are always grouped by request.在我遇到的所有其他工具中,例如,基巴纳,您将只获得与搜索匹配的日志行。始终显示与搜索匹配的日志行周围的所有其他日志行,它给你更多的背景。在调查日志中的问题时,我发现这非常有用,因为它可以立即帮助您更好地理解所发生的事情。我真的很怀念我使用的每一个其他日志查看器中的这个特性。<p>应用引擎的另一个有趣特性是,每个HTTP请求都自动分配了一个请求ID。它被添加到传入的HTTP请求中并唯一地标识它。这可以方便地将请求与其日志关联起来。例如,我们在发送电子邮件时,发生了一个未捕获的异常并包含了请求ID——这使得查找日志变得很简单。前端错误跟踪也可以这样做。<p><h3 id=“metrics”>metrics<h3><p>The cloud console gives access to a few basic application metrics.这包括请求量和延迟,交通量,内存使用情况,实例数和错误计数。当您调查一个问题以及想要快速获得应用程序一般状态的第一印象时,它作为一个起点非常有用。<p><p>here is an example with the a p p's request volume:<p><img src=“//www.djindien.com/content/images/2017/01/screen-shot-2017-01-22-at-15.44.06.png”alt=“google cloud console-graphs”><p><h3 id=“tracing”>tracing<h3><p>since the a p p engine instance is a black box,不能使用其他工具来诊断其性能。如果日志控制台不够,<em>trace<em>页面提供了更详细的数据。它允许搜索特定请求的延迟分布。<p><img src=“//www.djindien.com/content/images/2017/02/screen-shot-2017-02-20-at-22.31.44.png”alt=“google cloud console-trace”><p>when you select a specific request,它打开了一个时间线。在这里,它显示在日志中看不到的远程过程调用(RPC)。另外,侧边按类型列出的每个RPC的摘要。单击一个RPC,更多细节,例如响应大小,显示。<p><p>这对于查找缓慢请求的原因非常有用。在下面的示例中,您可以看到请求进行了一些快速memcache调用和非常缓慢的数据存储写入操作。<p><img src=“//www.djindien.com/content/images/2017/02/screen-shot-2017-02-20-at-22.32.49.png”alt=“google cloud console-analysis”><p>唯一的问题是rpcs不包括足够的信息去弄清楚到底发生了什么。例如,数据存储写入操作的详细视图如下所示:<p><p><img src=“//www.djindien.com/content/images/2017/02/screen-shot-2017-02-21-at-08.14.16.png”alt=“google cloud console-analysis detail view”><p>it does not even include the name of the updated entity.这是一个巨大的烦恼,可以使整个屏幕几乎毫无用处。只有一件事可以帮助您:单击右上角的“显示日志”按钮。它将包括请求的日志语句<em>inline</em>interleaved with the rpcs.这样,您就可以从上下文中推断出更多的详细信息。<p><h2 id=“resources”>resources<h2><p>it is also important to point out that pricing is completely usage based.这意味着你的应用程序的成本几乎是一个字节一个字节地扩展,按小时和按操作操作。它也意味着,这是非常负担得起的开始。没有固定成本。如果几乎没有人使用你的应用程序-因为有一个免费配额-你不支付任何东西。<p>The maximum item on the bill will most certainly be for the instances,在我上一个项目中贡献了大约80%。下一大块可能是数据存储读/写成本,我们总成本的15%。<p><p>google cloud console中有一个很好的界面来跟踪所有配额:<p><p><img src=“//www.djindien.com/content/images/2017/03/screen-shot-2017-03-13-at-11.33.20.png”alt=“google cloud console-quotas”><p>to be more specific,当我说“所有配额”时,我是指谷歌告诉你的所有配额。我们实际上遇到了一个问题,我们遇到了一个不可见的配额。我认为在API可能已经进入测试版的时候,不过。不管怎样,应用程序的一部分停止工作,我们不知道为什么。幸运的是,我们订阅了谷歌云支持。他们通知我们有关所述配额的信息,我们必须重写应用程序的一部分以使其再次工作。<p>We also have one minor interrupt due to the mizzle pricing setup.有一次,我们的一个应用程序突然停止工作,只是用默认的错误页面回复。我们花了十分钟才发现我们达到了我们设定的预算限额。在我们提出之后,一切都重新开始工作。<p><h2 id=“support”>support<h2><p>关于google cloud support有很多话要说。首先,如果没有它,我们有时会遇到严重的麻烦。因此,在我看来,任何关键任务应用程序都必须拥有它。例如,大约一年一次,我们的应用程序将停止服务请求。我们什么也没做。在联系谷歌支持之后,我们会发现他们将我们的应用程序转移到了“不同的集群”。它又开始工作了。这是一个非常可怕的情况。除了“向谷歌之神祈祷”,你什么都不能做。<p>second of all,根据支持人员的判断,这是一次命中或未命中。质量变化很大。有时我们需要交换一打信息,直到他们最终理解我们。像任何支持一样,这会让人恼火。但最终,他们通常会解决我们的问题,或者至少给我们提供足够的信息来帮助我们自己解决问题。<p><h2 id=“anehavage”>a new age<h2><p>google is working on a new type of a p p engine,灵活的环境。目前正在测试中。它的目标是提供两个世界中最好的:应用程序引擎运行的轻松和舒适,以及谷歌计算引擎的灵活性和强大功能。它允许使用任何编程平台(如Java 9!)在任何强大的谷歌计算引擎机器上(比如416GBRAM!)同时让Google负责维护服务器并确保应用程序运行良好。<p>他们已经为此工作多年了。自然地,我们渴望尝试一下。到目前为止,<a href=“https://tech.small-improvements.com/2016/09/12/running-our-app-engine-application-in-the-flexible-environment-java-8/”>我们没有那么兴奋</a>。但是,让我们看看Google是从哪里开始的。<p><h2 id=“DesignForscale”>Design for scale<h2><p>now,你可以将应用引擎对你的应用程序施加的限制视为烦恼。但请容我一会儿。应用引擎是由谷歌创建的。这些人知道如何构建可扩展的系统。这些限制仅仅是必要的。它们迫使你使你的应用程序适应云计算的方式。这是一件好事,应该接受。如果你觉得自己在和应用引擎作斗争,那你就是在与云的“新”规则作斗争。这当然是我在Google应用程序引擎上从三年中学到的一个教训。<p>一些限制和烦恼是Google忽略的结果,不过。感觉他们只投资最低限额了。事实上,过去两年我一直有这种感觉。与一个古老的科技堆合作是令人沮丧的,没有任何改善的希望。如果有已知的问题但没有得到解决,那将是令人恼火的。接收到的关于平台走向的信息太少,真令人沮丧。你觉得被困住了。<p>All in all,我喜欢应用引擎如何让开发团队专注于实际构建应用程序,让用户快乐并赚钱。谷歌从运营工作中解决了很多麻烦。但“老”应用程序引擎正在退出。我不认为在它上面再开始新的项目是一个好主意。另一方面,如果应用引擎灵活的环境能够真正解决其前身的主要问题,它可能成为开发应用程序的一个非常有趣的平台。<p>