<![CDATA[Google-此编manbetx手机版登陆程生活]]> 谷歌-这个编程生命manbetx手机版登陆 //www.djindien.com/ 鬼0.11 结婚,2019年2月6日13:53:19格林尼治标准时间 六十 <![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型 群众或部队的集合 java 数据仓库 谷歌 应用程序引擎 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 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一样出现在谷歌云上的辅助服务,BigQuery,文件存储…名单还在继续。<p>by using google app engine,你可以在世界上最好的基础设施之上运行你的应用程序。同时,您可以获得开箱即用的功能,这些功能至少需要第三方在Heroku上提供12个插件,如果您自己完成,则需要几个星期的设置。<em>This</em> is GAE's appeal.</p><p>Noteworthy applications that run on GAE include <a href="https://www.snapchat.com">Snapchat</a> and <a href="https://www.khanacademy.org">Khan Academy</a>.</p><h2 id="development">Development</h2><p>The web app I was working on all this time is a single,大型Java应用程序。App Engine也支持Python,PHP和走。现在你可能想知道为什么选择如此有限。一个原因是为了拥有一个完全管理的环境,谷歌需要将平台与环境集成起来。您可以说环境和平台是紧密耦合的。这需要大量的努力和投资,一旦您开始为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,它都有一个存根,您可以针对它进行开发。首先,这意味着,当你在本地运行你的应用程序时,你会得到<em>相当</em>接近它在生产中的表现。其次,您可以轻松地根据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。主要限制包括写入文件系统,certain methods of <code>java.lang.System</code> and using the Java Native Interface (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年App Engine邮件列表上的一篇文章,说明工程师们正在积极地进行这项工作。好吧,对你有好处。<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.这使得很难找到开发人员。整体应用安全受到威胁,。谷歌支持告诉我们,我们仍然会收到JDK 7产品的安全补丁。但最终,像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</code>。对于典型的Java应用程序,上传可以花费<em>相当</em>一段时间,你最好有一个快速的互联网连接。一旦过程完成,您可以在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 > /code>访问。但哪一个实际上是<em>live?<p><p>You can mark a version as<code>default.<code>。这意味着当您访问<code>https://<app-id>.appspot.com</code>(或您为该应用程序指定的域名)时,这将是接收所有请求的版本。将版本切换到<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似乎很适合微服务。有一些<a href=" https://cloud.google.com/appengine/docs/java/microservices-onapp-engine ">详细的文档</a>,。</p><p>原因稍后会讲清楚,我们决定将应用程序分为两个服务:前端(面向用户)和后端(后台工作)。但要做到这一点,实际上,我们并没有将整块巨石一分为二——这需要几个月的时间。我们只部署了同一个应用程序两次,只将用户发送到一个服务,将后台工作发送到另一个服务。<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)。幸运的是,有一个库叫做<a href="https://github.com/atteo/classindex">classindex</a>。它将带有特殊注释的类的完全限定路径写入文本文件。只需从文本文件中读取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报头:对于每一个传入的用户请求,谷歌添加包含用户国家的标题,区域,城市及其经纬度。这可以是<em>非常</em>有用,例如,预先填写电话号码、国家代码或检测不寻常的帐户登录位置。从我们的观察来看,精确度似乎也相当高。从第三方API或数据库以这种精确度获取此类信息通常非常麻烦和/或昂贵。因此免费获得应用程序引擎是一个不错的奖励。<p><h3 id=“background work”>background work<h3><h4 id=“threads”>threads<h4><p>as provided early,使用Java线程有限制。虽然可以启动一个新线程,尽管通过自定义GAE <code>ThreadManager</code>,它不能“活过”创建它的请求。这在实践中可能很烦人,因为第三方库不遵循App Engine的限制,当然可以。为了找到一个兼容的库或修改一个看起来不兼容的库,这些年来我们付出了很多汗水和眼泪。例如,我们无法使用<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,您可以在实例级别应用分而治之的方法。通过使用<a href="https://cloud.google.com/appengine/docs/java/taskqueue/">任务队列</a>,您可以将工作编入队列以供稍后处理。例如,当需要发送电子邮件时,您可以使用有效负载(例如收件人,和<em>push</em>队列上的URL。然后,其中一个实例将作为对指定端点的HTTP POST请求接收负载。如果失败了,a p p engine将重试此操作。<p><p>当您有大量工作要处理时,此模式真的很亮。只需将一批独立运行的任务排队即可。App引擎将负责故障处理。不需要自定义重试代码。Just imagine how awkward it would be without it: running hundreds of tasks at once you either need to stop and start from scratch when an error occurs or carefully track which have failed and enqueue them again for another attempt.</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:</ p>这是GAE独特的卖点。它将根据请求速率和响应延迟等指标来衡量实例的数量。所以如果有很多流量或者你的应用程序响应缓慢,more instances spin up.</li><li><strong>Manual:</strong> Basically like your good old virtual private servers.你告诉谷歌你想要多少实例,谷歌提供。如果您知道要获得什么流量,这个固定的实例大小很有用。<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>。引用App Engine文档:</p><blockquote> <p> App Engine scheduler决定是否使用现有实例(空闲实例或接受并发请求的实例)来服务每个新请求,将请求放入挂起的请求队列中,或者为该请求启动一个新实例。该决定考虑到可用实例的数量,应用程序服务请求的速度(延迟时间)有多快,以及每次我们试图调整这些数字时,旋转一个新实例所需的时间。<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(托管MySQL)和谷歌云存储(如Amazon的S3),取代了Blobstore。从一开始,应用引擎就提供了一个托管的memcache,同样。.<p><p>由于您只能使用HTTP进行通信,因此很难连接到第三方数据库。但通常数据库需要原始TCP。这种情况在几年前Socket API发布时才有所改变。但在beta中仍然是<em>still<em>这使得它成为关键任务使用的可疑选择。所以数据库方面,仍然有很多供应商锁定。无论如何,P>一开始,只有数据存储。<p><h3 id=“datastore”>datastore<h3><p>The datastore is a proprietary nosql database,完全由谷歌管理。这和我以前用过的任何东西都不一样。它是一种巨大的鳞状动物,具有非常独特的特征,guarantees and restrictions.</p><p>In the early days,数据存储基于主从设置,具有强一致的读取功能。几年之后,在它遭受了几次严重的割伤之后,Google <a href="http://googleappengine.blogspot.ca/2011/01/announcing-high-replication-datastore.html">introduced a new configuration option</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>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,准确地说)在实践中,最多每秒一次</li></ul><p>,这可能是个问题。我们很少达到尺寸限制-但当我们做到了,这是痛苦的。客户数据可能会丢失。当您达到写速率限制时,下次试穿通常都可以。但是当然,您必须设计应用程序来最小化这种可能性。例如,像定期更新计数器这样的东西需要大量的工作才能正常工作。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数据库那样在后台自动运行。索引还将增加写操作的时间和成本(稍后将详细讨论)。</p><p>如果查询涉及多个属性,它需要一个多索引。必须在名为<code>datastore indexes.xml的配置文件中指定。这里有一个例子:</p><pre><code class="language-xml"><datastore-index kind="Employee" origin ="false"> <property name="lastName" direction="asc" /> <property name="hireDate" direction="desc"</datastore-index> </code></pre><p>与其他数据库相比,缺少多个索引不仅会导致效率低下,慢速查询——它将立即失败。数据存储尽力执行性能查询。不等式滤波器,例如,仅支持单个属性。当然,射击自己的脚总是有办法的——但是很少。</p><p>还有其他几个功能我现在还不能讲,例如分页,预测查询和事务。转到<HeRF=“http://x.com,AppEngine /DOPCs/Stimult/Java/DATASOR/API概览”>数据存储文档</A>以了解更多信息,与其他数据库相比,读写操作非常慢。根据我的观察,按键读取平均需要10-20ms。很少有明显的偏差。我的最佳猜测是,谷歌序列化实体,实际上只有索引保存在内存中。<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应用程序,都无法绕过<a href="https://github.com/objectify/objectify">Objectify</a>。这是一个由Jeff Schnitzer编写的库。如果谷歌还没有这样做,他们应该给他开一张巨额支票,感谢他让应用引擎变得更好。他写这本书是为了自己的事业,但多年来他孜孜不倦的奉献,他在论坛上提供的大量文档和支持令人震惊。与物化使用数据存储是非常有趣的。< /P> < P>这里是一个例子,从文档:</P><Prime>代码类=“语言Java”> @ Entityclass CAR{@ ID字符串VIN;string color;ofy().save().entity(新车(“123123”,“红色”(现在);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切换之后),尽管我对此进行了测试。在与支持部门取得联系后,他们承认了这一监督,并承诺将予以纠正——一年多之后,他们仍然没有。><h4 id="backup "> backup </h4><p>对数据存储进行备份是一个非常糟糕的过程。有手动和自动两种方式。当然,当您有生产应用程序时,您希望有定期备份。官方的方式是在2012年推出的一个功能,仍然是阿尔法!<p><p>by adding an entry to your<code>cron.xml</code>you can initiate the backup process.条目将包括要备份的实体的名称以及要将它们保存到的谷歌云存储桶。当时间到了,它将用备份代码启动一些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年。感觉还是分开的,standalone service - but its integration into Google Cloud Console is improving.</p><p>Let's look at the capabilities one by one.</p><h3 id="logging">Logging</h3><p>It is crucial to access an application's logs quickly and with ease.这是一开始在App Engine上非常痛苦的事情。它过去非常繁琐,因为它无法搜索应用程序的所有版本。这意味着当你在找东西的时候,你必须知道当时哪个版本是在线的——或者尝试几个,逐一地。它几乎不能用了。再加上它非常慢。<p><p>从那时起,他们添加了有用的过滤器,只显示特定的模块,版本,日志级别,用户代理或状态代码。它非常强大。仍然没有< em > < / em >,但与早期相比,现在的情况要好得多。它看起来是这样的:</p><p><img src=" //www.djindien.com/content/images/2017/02/screen - shot-2017-02-27 -20.26.16.png" alt="谷歌Cloud Console - Logging"></p><p>你可以在这里看到一个非常独特的想法,日志总是按请求分组。在我遇到的所有其他工具中,例如,基巴纳,您将只获得与搜索匹配的日志行。通过始终显示与搜索匹配的所有其他日志行,它提供了更多的上下文。在调查日志中的问题时,我发现这非常有用,因为它可以立即帮助您更好地理解所发生的事情。我真的很怀念我使用的每一个其他日志查看器中的这个特性。<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>页面提供了更详细的数据。It allows to search for the latency distribution of certain requests.</p><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><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 -08.14.16.png" alt="谷歌Cloud Console - Analysis detail view "></p><p>它甚至不包括更新实体的名称。这是一个巨大的烦恼,可以使整个屏幕几乎无用。只有一件事可以帮助你:点击右上角的“显示日志”按钮。它将包括请求的日志语句<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可能已经进入测试版的时候,不过。不管怎样,应用程序的一部分停止工作,我们不知道为什么。幸运的是,我们订阅了<a href="https://cloud.google.com/support/">谷歌Cloud Support</a>。他们通知我们有关所述配额的信息,我们必须重写应用程序的一部分以使其再次工作。<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,<a href="https://cloud.google.com/appengine/docs/flexible/">flexible environment</a>。目前它还处于测试阶段。它的目标是提供两个世界中最好的:应用程序引擎运行的轻松和舒适,以及谷歌计算引擎的灵活性和强大功能。它允许使用任何编程平台(如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>。But let's see where Google is taking this.</p><h2 id="designforscale">Design for Scale</h2><p>Now,你可以将应用引擎对你的应用程序施加的限制视为烦恼。不过,请稍等片刻。App Engine是由谷歌创建的。这些人知道如何构建可扩展的系统。这些限制只是必要的。它们迫使你使你的应用程序适应云计算的方式。这是一件好事,应该被接受。如果你觉得自己在和应用引擎较劲,那你就是在与云的“新”规则作斗争。这当然是我在Google应用程序引擎上从三年中学到的一个教训。<p>一些限制和烦恼是Google忽略的结果,不过。感觉他们只投资了最低限度。事实上,过去两年我一直有这种感觉。使用古老的技术堆栈是令人沮丧的,没有任何改善的希望。如果存在已知的问题,但这些问题没有得到解决,那是令人愤怒的。接收到的关于平台走向的信息太少,真令人沮丧。你觉得被困住了。<p>All in all,我喜欢应用引擎如何让开发团队专注于实际构建应用程序,让用户快乐并赚钱。谷歌从运营工作中解决了很多麻烦。但“旧”的应用程序引擎即将过时。我不认为在它上面再开始新的项目是一个好主意。另一方面,如果应用引擎灵活的环境能够真正解决其前身的主要问题,它可能成为开发应用程序的一个非常有趣的平台。<p>