Ağ iletişimini optimize etme

Cloud Functions'nın basitliği, kodu hızlı bir şekilde geliştirmenize ve sunucusuz bir ortamda çalıştırmanıza olanak tanır. Orta ölçekte işlev çalıştırmanın maliyeti düşüktür ve kodunuzu optimize etmek yüksek öncelikli bir görev gibi 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ğ iletişimi optimizasyonunun nasıl yapılacağı açıklanmaktadır. Ağ optimizasyonunun bazı avantajları şunlardır:

  • Her işlev çağrısında yeni giden bağlantılar oluşturmak için harcanan CPU süresini azaltın.
  • 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 fonksiyonda kalıcı bağlantıların nasıl korunacağına dair örnekler verilmektedir. Bu yapılmadığı takdirde bağlantı kotaları hızlıca 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'inde, her işlev çağrısında yeni bir bağlantı oluşturmak yerine kalıcı bağlantıların nasıl korunacağı gösterilmektedir:

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 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 kümesini döndürür.

Google API'lerine erişme

Aşağıdaki örnekte Cloud Pub/Sub kullanılmaktadır ancak bu yaklaşım diğer istemci kitaplıkları için de geçerlidir. Örneğin, Cloud Natural Language veya Cloud Spanner. Performans iyileştirmelerinin, belirli istemci kitaplıklarının mevcut uygulamasına bağlı olabileceğini unutmayın.

Pub/Sub istemci nesnesi oluşturmak, her çağırmada bir bağlantı ve iki DNS sorgusuyla sonuçlanır. Gereksiz bağlantıları ve DNS sorgularını önlemek için aşağıdaki örnekte gösterildiği gibi genel kapsamda Pub/Sub istemci nesnesi 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. İstek 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 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, bunu işlev dağıtımında belirttiğinizden emin olun. Ortam değişkenlerini yapılandırma başlıklı makaleyi inceleyin.

Giden bağlantılar

Giden istek zaman aşımları

İşlevinizden VPC ağına yapılan istekler için 10 dakika boşta kalma süresinden sonra zaman aşımı gerçekleşir. İşlevinizin internete yaptığı isteklerde 20 dakikalık boşta kalma süresinden sonra zaman aşımı oluşur.

Giden bağlantı sıfırlamaları

Temel altyapı yeniden başlatıldığında veya güncellendiğinde işlevinizden hem VPC ağına hem de internete giden bağlantı akışları zaman zaman sonlandırılıp değiştirilebilir. Uygulamanız uzun süreli bağlantıları yeniden kullanıyorsa ölü bağlantıların yeniden kullanılmasını önlemek için uygulamanızı bağlantıları yeniden oluşturacak şekilde yapılandırmanızı öneririz.

İşlevinizi Yük Testine Tabi Tutma

İşlevinizin ortalama olarak kaç bağlantı gerçekleştirdiğini ölçmek için işlevinizi bir HTTP işlevi olarak dağıtın ve belirli bir sorgu/saniye hızında çağırmak için bir performans testi çerçevesi kullanın. Olası bir seçenek olan Artillery'yi tek bir satırla çağırabilirsiniz:

$ 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 Cloud Console'daki Cloud Functions API kotası sayfasında bağlantı kotanızın kullanımını kontrol edin. Kullanım sürekli olarak 30 civarında (veya 30'un katları) ise her çağrıda bir (veya birkaç) bağlantı oluşturuyorsunuz demektir. Kodunuzu optimize ettikten sonra, testin yalnızca başında birkaç (10-30) bağlantı oluştuğunu görmeniz gerekir.

Aynı sayfadaki CPU kotası grafiğinde optimizasyondan önceki ve sonraki CPU maliyetini de karşılaştırabilirsiniz.