<![CDATA[Java-此编manbetx手机版登陆程生命] ] > Java——编manbetx手机版登陆程人生 //www.djindien.com网站/ 幽灵0.11 结婚,2019年2月6日13:53:01格林尼治标准时间 60 <![CDATA[在Google应用程序引擎上工作3年。史诗审查。]]> <p>在过去的3年里,我在一个运行在谷歌应用引擎上的应用程序上工作。这是一个迷人的,谷歌在这里提供的独特服务。不像其他地方的任何东西。这是我的深度,personal take on it.</p><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 - 987 - c - 4382 ba01 - 48 - b806ac99cd 举办 爪哇 数据存储 谷歌 应用程序引擎 manbetx万博体育 周一,2017年3月13日格林尼治标准时间15:23:59 <p>在过去的3年里,我在一个运行在谷歌应用引擎上的应用程序上工作。这是一个迷人的,谷歌在这里提供的独特服务。不像其他地方的任何东西。这是我的深度,personal take on it.</p><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,实际上,<a href="https://cloud.google.com/appengine/docs">谷歌App Engine</a> (GAE)是什么?它是一个运行Web应用程序的平台。比如<a href=“https://www.heroku.com”>heroku</a>。但当你仔细观察时就会发现不同。它也是一个多功能的云计算平台。像< a href = " https://aws.amazon.com " > AWS < / >。但不同。让我解释一下。<p>Google在2008年推出了GAE,那时云计算还处于起步阶段。自从他们在2006年开始出租IT基础设施以来,亚马逊就走在了他们的前面。但随着GAE,谷歌很早就提供了一个成熟的平台即服务(paas),亚马逊将在2011年将其与弹性豆茎服务相匹配。Now what is so special about GAE?</p><p>It is a <em>fully-managed</em> application platform.到目前为止,我不知道有一个平台可以接近GAE的完整包:日志管理,邮件发送,缩放比例,memcache,图像处理,分布式cron作业,负载平衡、版本管理,任务队列搜索,性能分析,云调试,内容交付网络——这甚至没有提到像SQL一样出现在谷歌云上的辅助服务,BigQu疑问,文件存储…名单还在继续。</p><p>使用谷歌App引擎,你可以在世界上最好的基础设施之上运行你的应用程序。也,您可以从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_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的后端,but did not pursue it yet although it looked promising in first tests.</p><p>Having to stay with an old version is also a liability for the business.这使得很难找到开发人员。整个应用程序安全受到威胁,也。谷歌支持告诉我们,我们仍然会收到生产JDK7的安全补丁。但最终,像Spring这样的所有主要图书馆都将停止支持它。最终,您将被卡在部署中。您需要创建一个<code>appengine web.xml<code>configuration file。在那里,指定应用程序ID和版本以及一些其他设置,如。marking the app as <code>threadsafe</code> to be able to receive multiple requests per instance simultaneously.</p><h3 id="upload">Upload</h3><p>App Engine expects to receive your Java application as a packaged WAR file.您可以使用SDK中的<code>appcfg</code>脚本将其上传到他们的服务器。可选地,Maven和Gradle有插件,这使得编写<code>mvn appengine:update更容易。对于典型的Java应用程序,上传可以采用<e> > </e>你最好有一个快速的互联网连接。一旦过程完成,您可以在谷歌云控制台中看到您新部署的版本:</p><p><img src=" //www.djindien.com/content/images/2017/01/screen - shot-2017/01-22 -15.15.45-2.png" alt="谷歌云控制台- version "></p><h3 id="staticfiles">Static Files</h3><p>Static Files like images,样式表和脚本是当今任何web应用程序的一部分。在<code>appengine web.xml中,文件可以标记为static。谷歌将直接服务这些文件-不打击您的应用程序。它不是内容交付网络(cdn),因为它不分布到数百个边缘节点,but it helps to reduce the load on your servers.</p><h3 id="versions">Versions</h3><p>The nice thing in App Engine is that everything you deploy has a specific version.每个版本都可以在<code>https://<version>-dot-<app id>.appspot.com上访问。But which one is <em>actually</em> live?</p><p>You can mark a version as <code>default</code>.这意味着当您转到<code>https://<app id>.appspot.com时(或您为应用程序指定的域名),会这将是接收所有请求的版本。将版本切换到<code>default<code>非常简单:只需单击按钮或简单的终端命令。GAE can switch immediately or migrate your traffic incrementally to prevent overwhelming the new version.</p><p>There is also one option (which we never used) that allows you to distribute your traffic across multiple versions.这就允许在每个人都可以使用新版本之前,只将其提供给一小部分用户群,从而逐步推出新版本。<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>。每次由于新版本的错误,我们需要回滚时,这是不费吹灰之力的。通过编写某种智能的部署脚本,也可以实现持续交付。每个版本都可以运行任意数量的实例(唯一的限制是您的信用卡)。实际数量是传入流量和应用程序的缩放配置的结果;我们稍后再看。谷歌将在该版本的所有运行实例之间分发传入的请求。您可以看到实例列表,包括一些基本指标,比如请求和延迟,在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> -dot-< version>-dot-<service>-dot-< App -id>.appspot.com > /code>.</p><p><img src=" //www.djindien.com/content/images/2017/02/screen - shot -2017-02-20- 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.如果您以前在云中启动过服务器,你可能等了一分钟多。不是在GAE上。实例几乎立即启动。我想谷歌有一个服务器池准备好了。瓶颈总是你自己的应用程序。我们的应用程序用了40多秒才开始生产。所以除非我们想把我们巨大的巨石分割成单独的服务,我们需要它来提高效率。</p><p> app使用Spring谷歌甚至有专门的文档条目:<a href="https://cloud.google.com/appengine/articles/spring_optimization"> optimization Spring Framework for App Engine Applications</a>。在那里,我们找到了最重要的启动优化的灵感。<p>我们摆脱了Spring的类路径扫描。它在应用程序引擎上特别慢(可能是由于糟糕的CPU)。幸运的是,有一个名为classindex的库。它将具有特殊注释的类的完全限定路径写入文本文件。只需从文本文件中读取bean,the Spring initialization went down by about 8-10 seconds.</p><h3 id="requesthandling">Request Handling</h3><p>The very first thing I have to mention here is the requirement of the App 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秒的时间来启动你的应用程序。It is not uncommon for a Java app to take that long.</p><p>One nice little feature I'd like to highlight is the geographical HTTP headers: for each incoming user request,谷歌添加了包含用户国家的标题,区域,城市及其经纬度。这可能非常有用,例如,预填电话号码国家代码或检测异常帐户登录位置。从我们的观察来看,精确度似乎也相当高。从第三方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,虽然。但我们通常只是简单地将对数据的引用传递给队列。但是,you need to take extra good care in your data handling since it can easily happen that something vanishes between the time you enqueue a task and the time that task is actually executed.</p><p>The queues are configured in a <code>queue.xml</code> file.下面是一个推队列的示例,它每秒最多触发一个任务,最多两次重试:</p><pre><code class="language-xml"><队列>< name>my-push-queue</name> <rate>1/s</rate> <重试参数><任务重试限制>2</任务重试限制>0 </任务重试限制>0 </任务重试参数>1 </队列>2</ code >3 </pre >4 <h4 id="cron" >5 cron </h4 >6 <p >7。在<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>,<代码> min_idle_instances < /代码>和<代码> max_pending_latency > < /代码。引用应用引擎文档:<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>(冷)实例开始的<em>是非常常见的。然后,所有进入亚秒休息反应的努力都被抛到了窗外。自2012年以来,有关于<a href=“https://code.google.com/p/googleappengine/issues/detail的问题吗?id=7865“>面向用户的请求永远不会锁定到冷实例上。It has not even elicited the slightest comment by Google other than the status change to 'Accepted' (sounds like one of the stages of grief at this point).</p><p>This also explains why we split our app into two services.之前,我们经常发现,随着后台请求的激增,用户请求会受到影响。这是因为应用引擎极大地扩展了实例,由于请求在实例之间均匀路由,这导致更多的用户请求命中冷实例。通过拆分应用程序,我们大大减少了这种情况的发生。也,我们能够为这两个服务应用不同的扩展策略。<p>One last thing:in a side project,我使用了Go on App Engine,发现了一个关于App Engine的新视角。Go的特点之一是能够即时启动应用程序。这使得应用引擎成为完美的组合,像蝙蝠侠和罗宾。一起,自从我了解到云之后,它们就体现了我个人对云的所有期望。它可以真正地适应工作负载,而且很容易做到。Not even the abysmal hardware options seemed to pose a real problem for Go since it is that efficient.</p><h2 id="data">Data</h2><p>When App Engine launched,唯一的数据库选项是用于结构化数据的google datastore和用于二进制数据的google blobstore。从那时起,他们添加了谷歌云SQL(ManagedMySQL)和谷歌云存储(如亚马逊的S3),取代了blobstore。从一开始App Engine就提供了一个托管的Memcache,同样。.<p><p>由于您只能使用HTTP进行通信,因此很难连接到第三方数据库。但通常数据库需要原始TCP。这只是在几年前SocketAPI发布时发生的变化。但在beta中仍然是<em>still<em>这使得它成为关键任务使用的可疑选择。所以database-wise,仍然有很多供应商锁定。无论如何,P>一开始,只有数据存储。<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>最终</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><li>的附加元数据,您只能写入一个实体(组,准确地说)每秒最多一次这可能是个问题。我们很少达到尺寸限制——但是当我们达到的时候,这是痛苦的。客户数据可能会丢失。当您达到写速率限制时,下次再试通常没有问题。但当然,您必须设计应用程序,以最小化这种可能性。例如,像定期更新计数器这样的东西需要大量的工作才能正常工作。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”ancestor=“false”><property name=“lastname”direction=“asc”/><property name=“hiredate”direction=“desc”<datastore index><code><pre><p>in contrast to other databases,缺少多索引不仅会导致效率低下,慢速查询-它将立即失败。数据存储尽其所能地强制执行性能查询。不等式滤波器,例如,仅支持单个属性。当然,总是有办法射自己的脚-但他们是罕见的。</p><p>还有其他几个功能我现在还不能讲,例如分页,预测查询和事务。转到<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美元,100k写操作花费$0.18—写操作可以是实际的实体写,也可以是每个索引写。如果你什么都不写,你什么都不付。但在短短一分钟内,你就可以写下千兆字节的数据。更重要的是:对于没有实体或十亿的数据库,读写性能基本上是相同的。它像疯了一样伸缩。><h4 id="api"> api </h4><p>数据存储的api感觉<em>非常</em>底层。因此,对于任何严肃的Java应用程序,都没有办法绕过<HReF=“http://Github.com/Objyf/ObjyFy”> ObjyFix/A>。这是杰夫·施尼策写的图书馆。如果谷歌还没有这样做,他们应该给他开一张巨额支票,感谢他让应用引擎变得更好。他写这本书是为了自己的事业,但多年来他孜孜不倦的奉献,他在论坛上提供的大量文档和支持令人震惊。客观化,使用数据存储是非常有趣的。< /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 has a few tricks up its sleeve.例如,它带有一级缓存。这意味着,每当您通过键请求实体时,它首先检查请求范围的缓存是否已提取实体。这有助于提高性能。然而,它也可能会令人困惑,因为当您提取实体并修改它时,但是不要<em>保存它,下一次读取将产生相同的缓存,修改的对象。这会导致HeisenBugs。<p><h4 id=“development testing”>development&testing<h4><p>因为应用引擎是一个专有云数据库,你不能只在本地启动它。当您在计算机上运行应用程序时,模拟数据存储由SDK启动。它的行为非常接近于生产环境。只有性能好得多,这可能会产生误导。</p><p>用于对数据存储运行测试,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.条目将包括要备份的实体的名称,以及保存它们的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.我用过几次了,不幸的是,并非总是成功的。对于<em>,我们实体中的一些</em>,我收到了一个神秘的错误。我一直搞不清楚出了什么问题。但有些实体确实起了作用。在处理了一点查询语言文档之后,我能够产生我的第一个见解。所有的考虑,这是一种运行简单分析的好方法。如果不编写自定义代码,我肯定无法做到这一点。但我并没有充分利用这项服务的全部潜力。我所做的所有查询都可以直接在任何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.这是一个真正痛苦的应用程序引擎开始。它曾经非常麻烦,因为它无法跨<em>搜索应用程序的所有</em>版本。这意味着当你在找东西的时候,你必须知道当时哪个版本是在线的-或者尝试几个版本,逐一地。它几乎无法使用。再加上它非常慢。<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,它打开了一个时间线。在这里,它显示了在日志中看不到的远程过程调用(remote procedure call, rpc)。另外,侧边按类型列出的每个RPC的摘要。单击一个RPC,更多细节,如。响应大小,are shown.</p><p>This can be extremely helpful to find the cause of a slow request.在下面的示例中,您可以看到请求进行了一些快速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,灵活的环境。目前正在测试中。它的目标是提供两个世界中最好的:在App 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,我喜欢应用引擎如何让开发团队专注于实际构建应用程序,让用户快乐并赚钱。谷歌从运营工作中解决了很多麻烦。但“老”应用程序引擎正在退出。我不认为在它上面再开始新的项目是一个好主意。另一方面,如果App Engine的灵活环境可以解决其前身的主要问题,它可能会成为一个非常有趣的平台来开发应用程序