CRUD スタイルの API に加え、バッチ API を使用すると、エンティティのグループに対するマイクロサービスのパフォーマンスを高めることができます。たとえば、単一のユーザーを取得する GET API メソッドを公開する代わりに、一連のユーザー ID を取得して対応するユーザーのディクショナリを返す API を使用できます。
API 呼び出しの認証に何度もやり取りが必要になるようなセキュリティ メカニズムは、パフォーマンスに悪影響を及ぼします。たとえば、アプリケーションから受け取ったチケットを検証するためにマイクロサービスからアプリケーションにコールバックしなければならない場合、データを取得するために複数回のラウンドトリップが発生することになります。
[[["わかりやすい","easyToUnderstand","thumb-up"],["問題の解決に役立った","solvedMyProblem","thumb-up"],["その他","otherUp","thumb-up"]],[["わかりにくい","hardToUnderstand","thumb-down"],["情報またはサンプルコードが不正確","incorrectInformationOrSampleCode","thumb-down"],["必要な情報 / サンプルがない","missingTheInformationSamplesINeed","thumb-down"],["翻訳に関する問題","translationIssue","thumb-down"],["その他","otherDown","thumb-down"]],["最終更新日 2025-09-04 UTC。"],[[["\u003cp\u003eRegion ID is an abbreviated code assigned by Google based on the region selected during app creation, and it's included in App Engine URLs for apps created after February 2020, while being optional for older apps.\u003c/p\u003e\n"],["\u003cp\u003eMicroservices are well-suited for entities accessed with CRUD patterns, typically involving single entity operations that require a single microservice call.\u003c/p\u003e\n"],["\u003cp\u003eBatch APIs should be provided to efficiently handle groups of entities, such as retrieving multiple users via a single request with multiple IDs.\u003c/p\u003e\n"],["\u003cp\u003eAsynchronous requests, supported by the \u003ccode\u003eUrlfetch\u003c/code\u003e library, enable parallel calls to multiple microservices, improving performance by fetching independent data simultaneously.\u003c/p\u003e\n"],["\u003cp\u003eUsing \u003ccode\u003eREGION_ID\u003c/code\u003e.r.appspot.com instead of custom domains, setting \u003ccode\u003efollow_redirects\u003c/code\u003e to \u003ccode\u003eFalse\u003c/code\u003e, and using services within a single project can optimize performance when making microservice calls.\u003c/p\u003e\n"]]],[],null,["# Best Practices for Microservice Performance\n\n### Region ID\n\nThe \u003cvar translate=\"no\"\u003eREGION_ID\u003c/var\u003e is an abbreviated code that Google assigns\nbased on the region you select when you create your app. The code does not\ncorrespond to a country or province, even though some region IDs may appear\nsimilar to commonly used country and province codes. For apps created after\nFebruary 2020, \u003cvar translate=\"no\"\u003eREGION_ID\u003c/var\u003e`.r` is included in\nApp Engine URLs. For existing apps created before this date, the\nregion ID is optional in the URL.\n\nLearn more\n[about region IDs](/appengine/docs/legacy/standard/php/how-requests-are-routed#region-id). \nOK\n\nSoftware development is all about tradeoffs and microservices are no exception.\nWhat you gain in code deployment and operation independence, you pay for in\nperformance overhead. This section provides some recommendations for steps that\nyou can take to minimize this impact.\n\nTurn CRUD operations into microservices\n---------------------------------------\n\nMicroservices are particularly well-suited to entities that are accessed with\nthe create, retrieve, update, delete (CRUD) pattern. When working with such\nentities, you typically use only one entity at a time, such as a user, and you\ntypically perform only one of the CRUD actions at a time. Therefore,\nyou only need a single microservice call for the operation. Look for\nentities that have CRUD operations plus a set of business methods that could be\nutilized in many parts of your application. These entities make good\ncandidates for microservices.\n\nProvide batch APIs\n------------------\n\nIn addition to CRUD-style APIs, you can still provide good microservice\nperformance for groups of entities by providing batch APIs. For example, rather\nthan only exposing a GET API method that retrieves a single user, provide an API\nthat takes a set of user IDs and returns a dictionary of corresponding users:\n\n**Request:** \n\n /user-service/v1/?userId=ABC123&userId=DEF456&userId=GHI789\n\n**Response:** \n\n {\n \"ABC123\": {\n \"userId\": \"ABC123\",\n \"firstName\": \"Jake\",\n ... },\n \"DEF456\": {\n \"userId\": \"DEF456\",\n \"firstName\": \"Sue\",\n ... },\n \"GHI789\": {\n \"userId\": \"GHI789\",\n \"firstName\": \"Ted\",\n ... }\n }\n\nThe App Engine SDK supports many batch APIs, such as the ability to fetch many\nentities from Cloud Datastore through a single RPC, so servicing these types of batch\nAPIs can be very efficient.\n\nUse asynchronous requests\n-------------------------\n\nOften, you will need to interact with many microservices to compose a response.\nFor example, you might need to fetch the logged-in user's preferences as well as\ntheir company details. Frequently, these pieces of information are not dependent\non one another and you could fetch them in parallel. The `Urlfetch` library in\nthe App Engine SDK supports asynchronous requests,\nallowing you to call microservices in parallel.\n\nUse the shortest route\n----------------------\n\nDepending on how you invoke `Urlfetch`, you can cause different infrastructure\nand routes to be used. In order to use the best-performing route, consider the\nfollowing recommendations:\n\nUse\n\u003cvar translate=\"no\"\u003e\u003ca href=\"#appengine-urls\" style=\"border-bottom: 1px dotted #999\" class=\"devsite-dialog-button\" data-modal-dialog-id=\"regional_url\" track-type=\"progressiveHelp\" track-name=\"modalHelp\" track-metadata-goal=\"regionalURL\"\u003eREGION_ID\u003c/a\u003e\u003c/var\u003e`.r.appspot.com`, not a custom domain\n: A custom domain causes a different route to be used when routing through the\n Google infrastructure. Since your microservice calls are internal, it's easy\n to do and performs better if you use\n `https://`\u003cvar translate=\"no\"\u003ePROJECT_ID\u003c/var\u003e`.`\u003cvar translate=\"no\"\u003e\u003ca href=\"#appengine-urls\" style=\"border-bottom: 1px dotted #999\" class=\"devsite-dialog-button\" data-modal-dialog-id=\"regional_url\" track-type=\"progressiveHelp\" track-name=\"modalHelp\" track-metadata-goal=\"regionalURL\"\u003eREGION_ID\u003c/a\u003e\u003c/var\u003e`.r.appspot.com`.\n\nSet `follow_redirects` to `False`\n: Explicitly set `follow_redirects=False` when calling `Urlfetch`, as it avoids a\n heavier-weight service designed to follow redirects. Your API endpoints should\n not need to redirect the clients, because they are your own microservices, and\n endpoints should only return HTTP 200-, 400-, and 500-series responses.\n\nPrefer services within a project over multiple projects\n: There are good reasons to use multiple projects when building a\n microservices-based application, but if performance is your primary goal,\n use services within a single project. Services of a project are hosted in\n the same datacenter and even though throughput on Google's inter-datacenter\n network is excellent, local calls are faster.\n\nAvoid chatter during security enforcement\n-----------------------------------------\n\nIt's bad for performance to use security mechanisms that involve lots of back\nand forth communication to authenticate the calling API. For example, if your\nmicroservice needs to validate a ticket from your application by calling back to\nthe application, you've incurred a number of roundtrips to get your data.\n\nAn OAuth2 implementation can amortize this cost over time by using refresh\ntokens and caching an access token between `Urlfetch` invocations. However, if\nthe cached access token is stored in memcache, you will need to incur memcache\noverhead to fetch it. To avoid this overhead, you might cache the access token\nin instance memory, but you will still experience the OAuth2 activity\nfrequently, as each new instance negotiates an access token; remember that App\nEngine instances spin up and down frequently. Some hybrid of memcache and\ninstance cache will help mitigate this issue, but your solution starts to become\nmore complex.\n\nAnother approach that performs well is to share a secret token between\nmicroservices, for example, transmitted as a custom HTTP header. In this\napproach, each microservice could have a unique token for each caller.\nTypically, shared secrets are a questionable choice for security\nimplementations, but since all the microservices are in the same application, it\nbecomes less of an issue, given the performance gains. With a shared secret, the\nmicroservice only needs to perform a string comparison of the incoming secret\nagainst a presumably in-memory dictionary, and the security enforcement is\nvery light.\n\nIf all of your microservices are on App Engine, you can also inspect the\nincoming\n[`X-Appengine-Inbound-Appid` header](/appengine/docs/legacy/standard/php/appidentity).\nThis header is added by the `Urlfetch` infrastructure when making a request to\nanother App Engine project and cannot be set by an external party. Depending on\nyour security requirement, your microservices could inspect this incoming header\nto enforce your security policy.\n\nTrace microservice requests\n---------------------------\n\nAs you build your microservices-based application, you begin to accumulate\noverhead from successive `Urlfetch` calls. When this happens, you can use\n[Cloud Trace](/cloud-trace)\nto understand what calls are being\nmade and where the overhead is. Importantly, Cloud Trace can also help identify\nwhere independent microservices are being serially invoked, so you can\nrefactor your code to perform these fetches in parallel.\n\nA helpful feature of Cloud Trace kicks in when you use multiple services\nwithin a single project. As calls are made between microservice services in your\nproject, Cloud Trace collapses all the calls together into a single call graph\nto allow you to visualize the entire end-to-end request as a single trace.\n\nNote that in the above example, the calls to the `pref-service` and the\n`user-service` are performed in parallel by using an asynchronous `Urlfetch`,\nso the RPCs appear scrambled in the visualization.\nHowever this is still a valuable tool for diagnosing latency.\n| When designing your API responses, it's helpful to include the\n| unique request ID in the boilerplate response that you give back to the\n| caller. This approach can tie client requests together with\n| microservice responses and help with debugging and diagnosis.\n| Other helpful items are the hostname, path, instance ID, and the version\n| that served the response. All of this information can be found on the\n| request environment so it is inexpensive to include in the response.\n|\n| For example (in pseudo-code): \n|\n| response = {\n| 'status': 200,\n| 'apiVersion': '1.2', # helpful to show the formal minor version to the client\n| 'hostname': os.environ.get('HTTP_HOST'),\n| 'path': os.environ.get('PATH_INFO'),\n| 'instanceId': os.environ.get('INSTANCE_ID'),\n| 'codeVersion': os.environ.get('CURRENT_VERSION_ID'),\n| 'requestId': os.environ.get('REQUEST_LOG_ID'),\n| 'data': {\n| # your actual API response goes here\n| }\n| }\n|\n| \u003cbr /\u003e\n|\nWhat's next\n-----------\n\n- Get an overview of [microservice architecture on App Engine](/appengine/docs/legacy/standard/php/microservices-on-app-engine).\n- Understand how to [create and name dev, test, qa, staging, and production environments with microservices in App Engine](/appengine/docs/legacy/standard/php/creating-separate-dev-environments).\n- Learn the [best practices for designing APIs to communicate between microservices](/appengine/docs/legacy/standard/php/designing-microservice-api).\n- Learn how to [Migrate an existing monolithic application to one with microservices](/appengine/docs/legacy/standard/php/microservice-migration)."]]