Ağ iletişimini optimize etme

Cloud Functions'nin basitliği sayesinde hızlıca kod geliştirip sunucusuz bir ortamda çalıştırabilirsiniz. Orta ölçekte işlevleri çalıştırmanın maliyeti düşüktür ve kodunuzu optimize etmek yüksek öncelikli görünmeyebilir. Ancak dağıtımınız ölçeklendikçe kodunuzu optimize etmek giderek daha önemli hale gelir.

Bu belgede, işlevleriniz için ağ performansını nasıl optimize edeceğiniz açıklanmaktadır. Ağ optimizasyonunun avantajlarından bazıları şunlardır:

  • Her işlev çağrısında yeni giden bağlantılar oluşturmak için harcanan CPU süresini azaltma
  • Bağlantı veya DNS kotalarının tükenme olasılığını azaltır.

Kalıcı Bağlantıları Sürdürme

Bu bölümde, bir işlevde kalıcı bağlantıların nasıl sürdürüleceğine dair örnekler verilmiştir. Aksi takdirde bağlantı kotaları hızla tükenebilir.

Bu bölümde aşağıdaki senaryolar ele alınmaktadır:

  • HTTP/S
  • Google API'leri

HTTP/S İstekleri

Aşağıdaki optimize edilmiş kod snippet'i, her işlev çağrısında yeni bir bağlantı oluşturmak yerine kalıcı bağlantıların nasıl sürdürüleceğini gösterir:

Node.js

const http = require('http');
const functions = require('firebase-functions');

// Setting the `keepAlive` option to `true` keeps
// connections open between function invocations
const agent = new http.Agent({keepAlive: true});

exports.function = functions.https.onRequest((request, response) => {
    req = http.request({
        host: '',
        port: 80,
        path: '',
        method: 'GET',
        agent: agent, // Holds the connection open after the first invocation
    }, res => {
        let rawData = '';
        res.setEncoding('utf8');
        res.on('data', chunk => { rawData += chunk; });
        res.on('end', () => {
            response.status(200).send(`Data: ${rawData}`);
        });
    });
    req.on('error', e => {
        response.status(500).send(`Error: ${e.message}`);
    });
    req.end();
});

Python

from firebase_functions import https_fn
import requests

# Create a global HTTP session (which provides connection pooling)
session = requests.Session()

@https_fn.on_request()
def connection_pooling(request):

    # The URL to send the request to
    url = "http://example.com"

    # Process the request
    response = session.get(url)
    response.raise_for_status()
    return https_fn.Response("Success!")
    

Bu HTTP işlevi, HTTP istekleri göndermek için bir bağlantı havuzu kullanır. Bir istek nesnesi (flask.Request) alır ve yanıt metnini ya da make_response kullanılarak Response nesnesine dönüştürülebilen herhangi bir değer grubunu döndürür.

Google API'lerine erişme

Aşağıdaki örnekte Cloud Pub/Sub kullanılmaktadır ancak bu yaklaşım, Cloud Natural Language veya Cloud Spanner gibi diğer istemci kitaplıklarında da kullanılabilir. Performans iyileştirmelerinin, belirli istemci kitaplıklarının mevcut uygulamasına bağlı olabileceğini unutmayın.

Pub/Sub istemci nesnesi oluşturulduğunda her çağrı için bir bağlantı ve iki DNS sorgusu oluşturulur. Gereksiz bağlantıları ve DNS sorgularını önlemek için Pub/Sub istemci nesnesini aşağıdaki örnekte gösterildiği gibi global kapsamda oluşturun:

node.js

const PubSub = require('@google-cloud/pubsub');
const functions = require('firebase-functions');
const pubsub = PubSub();

exports.function = functions.https.onRequest((req, res) => {
    const topic = pubsub.topic('');

    topic.publish('Test message', err => {
        if (err) {
            res.status(500).send(`Error publishing the message: ${err}`);
        } else {
            res.status(200).send('1 message published');
        }
    });
});

Python

import os

from firebase_functions import https_fn
from google.cloud import pubsub_v1

# from firebase_functions import https_fn
# Create a global Pub/Sub client to avoid unneeded network activity
pubsub = pubsub_v1.PublisherClient()

@https_fn.on_request()
def gcp_api_call(request):

    project = os.getenv("GCP_PROJECT")
    request_json = request.get_json()

    topic_name = request_json["topic"]
    topic_path = pubsub.topic_path(project, topic_name)

    # Process the request
    data = b"Test message"
    pubsub.publish(topic_path, data=data)

    return https_fn.Response("1 message published")
    

Bu HTTP işlevi, işlev çağrısı başına gereken bağlantı sayısını azaltmak için önbelleğe alınmış bir istemci kitaplığı örneği kullanır. Bir istek nesnesi (flask.Request) alır ve yanıt metnini veya make_response kullanılarak Response nesnesine dönüştürülebilecek herhangi bir değer kümesini döndürür.

GCP_PROJECT ortam değişkeni, Python 3.7 çalışma zamanında otomatik olarak ayarlanır. Daha sonraki çalışma zamanlarında, işlev dağıtımında bunu belirttiğinizden emin olun. Ortam değişkenlerini yapılandırma bölümüne bakın.

Giden bağlantılar

Giden istek zaman aşımları

İşlevinizden VPC ağına gönderilen istekler için 10 dakikalık boşta kalma süresinden sonra zaman aşımı gerçekleşir. İşlevinizden internete gönderilen istekler için 20 dakikalık boşta kalma süresinden sonra zaman aşımı uygulanır.

Giden bağlantı sıfırlamaları

İşlevinizden hem VPC ağına hem de internete giden bağlantı akışları, temel altyapı yeniden başlatıldığında veya güncellendiğinde zaman zaman sonlandırılıp değiştirilebilir. Uygulamanız uzun süreli bağlantıları yeniden kullanıyorsa, bağlantıları yeniden kuracak şekilde yapılandırmanızı öneririz. Böylece, çalışmayan bir bağlantının yeniden kullanılmasını önleyebilirsiniz.

İşlevinizi yük testine tabi tutma

İşlevinizin ortalama kaç bağlantı gerçekleştirdiğini ölçmek için işlevi HTTP işlevi olarak dağıtın ve belirli bir QPS'de çağırmak için performans testi çerçevesi kullanın. Olası seçeneklerden biri, tek bir satırla çağırabileceğiniz Artillery'dir:

$ artillery quick -d 300 -r 30 URL

Bu komut, belirtilen URL'yi 300 saniye boyunca 30 QPS hızında getirir.

Testi gerçekleştirdikten sonra Google Cloud konsolundaki Cloud Functions API kotası sayfasında bağlantı kotanızın kullanımını kontrol edin. Kullanım sürekli olarak 30 (veya katları) civarındaysa her çağrıda bir (veya birkaç) bağlantı oluşturuyorsunuz demektir. Kodunuzu optimize ettikten sonra, yalnızca testin başında birkaç (10-30) bağlantı kurulduğunu görürsünüz.

Ayrıca aynı sayfadaki CPU kotası grafiğinde optimizasyondan önceki ve sonraki CPU maliyetini karşılaştırabilirsiniz.