<![CDATA[数据存储-此编程寿命]]manbetx手机版登陆> 数据存储-此编程寿命manbetx手机版登陆 //www.djindien.com/ 幽灵0.11 结婚,2019年2月06日13:53:41格林尼治时间 60 <![CDATA[在Google应用程序引擎上工作3年。史诗审查。]]> <p>在过去的3年里,我一直在开发一个运行在谷歌App Engine上的应用程序。这是一个迷人的,谷歌在这里提供独一无二的服务。不像你在别处能找到的任何东西。这是我的深度,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 举办 java 数据存储 谷歌 应用程序引擎 manbetx万博体育 妈,2017年3月13日格林尼治标准时间15:23:59 <p>在过去的3年里,我一直在开发一个运行在谷歌App Engine上的应用程序。这是一个迷人的,谷歌在这里提供独一无二的服务。不像你在别处能找到的任何东西。这是我的深度,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 href = " https://aws.amazon.com " > AWS < / >。但不同。让我解释一下。<p>Google在2008年推出了GAE,那时云计算还处于起步阶段。自从他们在2006年开始出租IT基础设施以来,亚马逊就走在了他们的前面。但随着GAE,谷歌很早就提供了一个成熟的平台即服务(paas),亚马逊将在2011年将其与弹性豆茎服务相匹配。盖伊有什么特别之处?<p><p>it is a<em>fully managed.<em>application platform.到目前为止,我不知道有一个平台可以接近GAE的完整包:日志管理,邮件发送,缩放、memcache,图像处理,分布式Cron作业,负载均衡,版本管理,任务队列,搜索,性能分析,云调试,内容交付网络——这甚至没有提到像SQL一样出现在谷歌云上的辅助服务,BigQuery,文件存储……名单还在继续。</p><p>使用谷歌App引擎,你可以在世界上最好的基础设施上运行你的应用。同时,您可以获得开箱即用的功能,这些功能至少需要第三方在Heroku上提供12个插件,如果您自己完成,则需要几个星期的设置。<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应用程序。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_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上发挥作用。在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 > < 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和版本以及一些附加设置,如。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</code>。对于典型的Java应用程序,上传可以花费<em>相当</em>一段时间,你最好有一个快速的互联网连接。一旦过程完成,您可以在谷歌云控制台中看到您新部署的版本:</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。谷歌将直接提供这些文件,而不必点击你的应用程序。它不是完全的</em> a Content Delivery Network (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/BlueGreenDeployment.html">蓝绿色部署</a>的完美平台。每次由于新版本的错误,我们需要回滚时,这是毫不费力。通过编写一个有点智能的部署脚本,也可以实现连续交付。每个版本都可以运行任意数量的实例(唯一的限制是您的信用卡)。实际数量是传入流量和应用程序的缩放配置的结果;我们稍后再看。谷歌将在该版本的所有运行实例之间分发传入的请求。您可以看到实例列表,包括一些基本的指标,如请求和延迟,在谷歌云控制台:</p><p><img src=" //www.djindien.com/content/images/2017/01/screen - shot-2017-01-22 -15.28.57.png" alt="谷歌云控制台-实例"></p><p>上运行这些实例的硬件选项是-让我们坦率地说-可悲的。App Engine基本上提供了4种不同的<a href="https://cloud.google.com/appengine/docs/about-the-standard-environment#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似乎非常适合微服务。有一些<a href=" https://cloud.google.com/appengine/docs/java/microservices-onapp-engine ">详细的文档</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)。幸运的是,有一个库叫做<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> deadlineexcededexception </code> .</p><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,谷歌添加包含用户国家的标题,区域,城市以及该城市的经纬度。这可以是<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,您可以在实例级别上应用分治方法。通过使用<HeRF=“http://Loop.com /AppEngine /DOCS/Java/TaskQue/”>任务队列</A>,您可以排队等待以后的处理。例如,当需要发送电子邮件时,您可以使用有效负载(例如收件人,和<em>push</em>队列上的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"><队列>< 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条目时,App Engine将开始向一个端点发送请求,该端点在活动(但较旧)版本中不存在——为我们的生产错误报告生成噪声。我想,当使用应用引擎托管微服务时,这肯定会更加痛苦。<p>also,Cron作业不在本地运行。我可以理解为什么会这样:很多工作通常安排在通常繁忙的时间之外,因此在正常工作日甚至不会触发。但是<em>有些</em>每隔几分钟或几小时就会运行一次——观察这些真的很有趣。它们可能触发通知,为例。你想在当地看到这些。因为最终您将引入一个导致不良行为的变更(在我们的项目中已经发生过多次),并且在本地查看它可能会阻止您将其发布。但是在本地模拟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独特的卖点。它将根据请求率和响应延迟等指标来扩展实例的数量。如果流量很大或者你的应用反应很慢,更多实例启动。<li><li><strong>manual:<strong>基本上喜欢您的旧虚拟专用服务器。你告诉谷歌你想要多少个实例,谷歌提供。如果您知道要获得什么流量,这个固定的实例大小很有用。<li><li><strong>basic:<strong>本质上与手动缩放模式相同,但是当实例变为空闲时,这里最有用和最有趣的当然是<em>automatic mode</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“>面向用户的请求永远不会锁定到冷实例上。它甚至没有引起google的任何评论,除了状态更改为“已接受”(听起来像是此时的悲伤阶段之一)。<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的特点之一是能够即时启动应用程序。这使得App Engine成为了一个完美的组合,比如蝙蝠侠和罗宾。一起,它们体现了自我了解到云以来我个人所期望的一切。它可以真正地适应工作负载,而且很容易做到。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,您仅有的数据库选项是用于结构化数据的谷歌数据存储和用于二进制数据的谷歌Blobstore。从那时起,他们添加了谷歌云SQL(托管MySQL)和谷歌云存储(如Amazon的S3),取代了Blobstore。从一开始App Engine就提供了一个托管的Memcache,同样。.<p><p>由于您只能使用HTTP进行通信,因此很难连接到第三方数据库。但通常数据库需要原始TCP。这种情况在几年前Socket API发布时才有所改变。但还是<em> </em>,这使得它成为关键任务使用的可疑选择。所以database-wise,目前仍存在很大程度上的供应商锁定问题。< / p > < 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>实体</em>。它们被归类到特定的<em>类型</em>。实体由<em>属性</em>组成。属性具有名称和具有特定类型的值。类似于<code>string<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>一个实体可能总共只有1MB,包含编码实体</li><li>的附加元数据,您只能写入一个实体(组,准确地说)在实践中,最多每秒一次</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数据库那样在后台自动运行。索引还将增加写入操作的时间和成本(稍后将详细介绍)。如果查询涉及多个属性,它需要一个多索引。必须在名为<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>there are some other features I cannot go into now,例如分页,投影查询和事务。访问<a href="https://cloud.google.com/appengine/docs/standard/java/datastore/api-overview">Datastore documentation</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应用程序,都无法绕过<a href="https://github.com/objectify/objectify">Objectify</a>。这是杰夫·施尼策写的图书馆。如果谷歌还没有这样做,他们应该给他开一张大支票,让应用引擎变得更好。他写这篇文章是为了自己的事业,但多年来他孜孜不倦的奉献精神,他在论坛上提供的大量文档和支持令人震惊。客观化,使用数据存储是非常有趣的。< /P> < P>这里是一个例子,从文档:</P><Prime>代码类=“语言Java”> @ Entityclass CAR{@ ID字符串VIN;string color;ofy().save().entity(新车(“123123”,“红色”)等();.load汽车c = ofy()().type(Car.class).id(“123123”),现在();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>不</em>保存它,下一次读取将产生相同的缓存,修改的对象。这会导致HeisenBugs。<p><h4 id=“development testing”>development&testing<h4><p>因为应用引擎是一个专有云数据库,你不能在本地启动它。当您在计算机上运行应用程序时,模拟数据存储由SDK启动。它的行为非常接近生产环境。只是性能好得多,这可能会产生误导。</p><p>用于对数据存储运行测试,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.我用过几次,不幸的是,并非总是成功的。对于<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 -19.58.46.png" alt="谷歌云控制台- Monitoring"></p><p>这是<a href="https://techcrunch.com/2014/05/07/google-acquires-cloud- monitoring-servicstackdriver/ ">谷歌收购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.在我遇到的所有其他工具中,例如,Kibana您将只得到与您的搜索匹配的日志行。始终显示与搜索匹配的日志行周围的所有其他日志行,它给你更多的背景。在研究日志中的问题时,我发现这非常有用,因为它可以立即帮助您更好地理解</em>发生了什么。我真的很怀念我使用的每一个其他日志查看器中的这个特性。<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 >这是一个示例应用程序的请求数量:< / p > < p > < img src = " //www.djindien.com/content/images/2017/01/screen -射- 2017 - 01 - 22 -在- 15.44.06.png“alt =“谷歌云控制台-图形”> < / p > < h3 id = "跟踪" > < / h3 > < p >跟踪由于app Engine实例是一个黑盒,您不能使用其他工具来诊断其性能。如果日志控制台不够,<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 -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可能已经进入测试版的时候,虽然。不管怎么说,我们的应用程序的一部分停止工作,我们不知道为什么。幸运的是,我们订阅了谷歌云支持。他们通知我们有关所述配额的信息,我们必须重写应用程序的一部分以使其再次工作。<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>。目前它还处于测试阶段。它的目标是提供两个世界中最好的:在App Engine上运行的便利性和舒适性,以及谷歌计算引擎的灵活性和强大功能。它允许使用任何编程平台(如Java 9!)在任何强大的谷歌计算引擎机器上(比如416GBRAM!)同时让Google负责维护服务器并确保应用程序运行良好。<p>他们已经为此工作多年了。自然地,我们很想试一试。到目前为止,<a href="https://tech.small- innovvements.com/2016/09/12/runningour -app-engine-application in the flex -environment-java-8/"但是,让我们看看Google是从哪里开始的。<p><h2 id=“DesignForscale”>Design for scale<h2><p>now,你可以将应用引擎对你的应用程序施加的限制视为烦恼。不过,请稍等片刻。应用引擎是由谷歌创建的。这些家伙知道如何构建可伸缩的系统。这些限制仅仅是必要的。它们迫使你使你的应用程序适应云计算的方式。这是一件好事,应该被接受。如果你觉得自己在和应用引擎较劲,那么你就是在与云计算的“新”规则作斗争。这当然是我在Google应用程序引擎上从三年中学到的一个教训。<p>一些限制和烦恼是Google忽略的结果,虽然。感觉他们只投资最低限额了。事实上,过去两年我一直有这种感觉。使用古老的技术堆栈是令人沮丧的,看不到任何改善的希望。如果存在已知的问题,但这些问题没有得到解决,那是令人愤怒的。令人沮丧的是,关于该平台走向的信息如此之少。你觉得被困住了。<p>All in all,我喜欢App Engine让开发团队专注于实际构建应用程序的方式,让用户快乐并赚钱。谷歌从运营工作中省去了很多麻烦。但“老”应用程序引擎正在退出。我不认为在它上面开始新的项目是一个好主意。另一方面,如果App Engine的灵活环境可以解决其前身的主要问题,它可能会成为一个非常有趣的平台来开发应用程序