CREMA ব্যবহার করে পাব/সাব কিউ ভলিউমের উপর ভিত্তি করে অটোস্কেল ক্লাউড রান কর্মী পুল

১. ভূমিকা

সংক্ষিপ্ত বিবরণ

এই টিউটোরিয়ালটি আপনাকে দেখাবে কীভাবে পাব/সাব মেসেজ প্রসেস করার জন্য একটি ক্লাউড রান ওয়ার্কার পুল (কনজিউমার) ডেপ্লয় করতে হয় এবং ক্লাউড রান এক্সটার্নাল মেট্রিক্স অটোস্কেলিং (CREMA) ব্যবহার করে কিউ ডেপথের উপর ভিত্তি করে আপনার কনজিউমার ইনস্ট্যান্সগুলোকে স্বয়ংক্রিয়ভাবে স্কেল করতে হয়।

আপনি যা শিখবেন

এই কোডল্যাবে আপনি যা শিখবেন:

  • একটি পাব/সাব টপিক ও সাবস্ক্রিপশন তৈরি করুন এবং সেই টপিকে মেসেজ পাঠান।
  • একটি ক্লাউড রান ওয়ার্কার পুল (কনজিউমার) স্থাপন করুন যা পাব/সাব থেকে মেসেজ গ্রহণ করে।
  • পাব/সাব সাবস্ক্রিপশনে থাকা মেসেজের সংখ্যার ওপর ভিত্তি করে আপনার ওয়ার্কার পুলকে স্বয়ংক্রিয়ভাবে স্কেল করতে, CREMA প্রজেক্টটিকে GitHub-এ একটি Cloud Run সার্ভিস হিসেবে ডিপ্লয় করুন।
  • স্থানীয়ভাবে একটি পাইথন স্ক্রিপ্ট চালিয়ে লোড তৈরি করে আপনার অটোস্কেলিং কনফিগারেশন পরীক্ষা করুন।

২. পরিবেশ ভেরিয়েবল কনফিগার করুন

যেহেতু এই কোডল্যাব জুড়ে অনেক এনভায়রনমেন্ট ভেরিয়েবল ব্যবহার করা হয়েছে, আমরা চালানোর পরামর্শ দিচ্ছি

set -u

যা আপনাকে সতর্ক করবে যদি আপনি এমন কোনো এনভায়রনমেন্ট ভ্যারিয়েবল ব্যবহার করার চেষ্টা করেন যা এখনও সেট করা হয়নি। এই সেটিংটি বাতিল করতে, set +u চালান।

প্রথমে, নিম্নলিখিত ভেরিয়েবলটি আপনার প্রজেক্ট আইডি দিয়ে পরিবর্তন করুন।

export PROJECT_ID=<YOUR_PROJECT_ID>

এবং তারপর এটিকে এই কোডল্যাবের প্রজেক্ট হিসেবে সেট করুন।

gcloud config set project $PROJECT_ID

এরপর, এই কোডল্যাবে ব্যবহৃত এনভায়রনমেন্ট ভেরিয়েবলগুলো সেট করুন।

export REGION=us-central1
export TOPIC_ID=crema-pubsub-topic
export SUBSCRIPTION_ID=crema-pubsub-sub
export CREMA_SA_NAME=crema-service-account
export CONSUMER_SA_NAME=consumer-service-account
export CONSUMER_WORKER_POOL_NAME=worker-pool-consumer
export CREMA_SERVICE_NAME=my-crema-service

এই কোডল্যাবের জন্য একটি ডিরেক্টরি তৈরি করুন

mkdir crema-pubsub-codelab
cd crema-pubsub-codelab

এপিআই সক্ষম করুন

gcloud services enable \
        artifactregistry.googleapis.com \
        cloudbuild.googleapis.com \
        run.googleapis.com \
        parametermanager.googleapis.com

সবশেষে, নিশ্চিত করুন যে আপনার gcloud সর্বশেষ সংস্করণটি ব্যবহার করছে।

gcloud components update

৩. পাব/সাব সেটআপ

আপনার ওয়ার্কার পুল যে টপিক এবং পুল সাবস্ক্রিপশনটি প্রসেস করবে, সেটি তৈরি করুন। ব্যাশ

বিষয়টি তৈরি করুন।

gcloud pubsub topics create $TOPIC_ID

সাবস্ক্রিপশনটি তৈরি করুন।

gcloud pubsub subscriptions create $SUBSCRIPTION_ID --topic=$TOPIC_ID

৪. আইএএম এবং সার্ভিস অ্যাকাউন্ট

প্রতিটি ক্লাউড রান রিসোর্সের জন্য একটি সার্ভিস অ্যাকাউন্ট তৈরি করার পরামর্শ দেওয়া হয়। এই কোডল্যাবে, আপনি নিম্নলিখিতগুলি তৈরি করবেন:

  • কনজিউমার এসএ: পাব/সাব মেসেজ প্রসেসকারী ওয়ার্কার পুলের পরিচয়।
  • CREMA SA: CREMA অটোস্কেলার পরিষেবার পরিচিতি।

পরিষেবা অ্যাকাউন্ট তৈরি করুন

কর্মী পুল গ্রাহক SA তৈরি করুন:

gcloud iam service-accounts create $CONSUMER_SA_NAME \
  --display-name="PubSub Consumer Service Account"

ওয়ার্কার পুল CREMA সার্ভিস SA তৈরি করুন:

gcloud iam service-accounts create $CREMA_SA_NAME \
  --display-name="CREMA Autoscaler Service Account"

কনজিউমার এসএ-কে অনুমতি প্রদান করুন

সাবস্ক্রিপশন থেকে মেসেজ পুল করার জন্য ওয়ার্কার পুল কনজিউমার SA-কে অনুমতি প্রদান করুন।

gcloud pubsub subscriptions add-iam-policy-binding $SUBSCRIPTION_ID \
  --member="serviceAccount:$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/pubsub.subscriber"

CREMA SA-কে অনুদানের অনুমতি

প্যারামিটার পড়তে, ওয়ার্কার পুল স্কেল করতে এবং পাব/সাব মেট্রিক্স নিরীক্ষণ করতে CREMA-এর অনুমতি প্রয়োজন।

  1. অ্যাক্সেস প্যারামিটার ম্যানেজার (কনফিগারেশন রিডার):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/parametermanager.parameterViewer"
  1. ওয়ার্কার পুলের পরিধি বৃদ্ধি করুন (ক্লাউড রান ডেভেলপার):
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/run.developer"
  1. মনিটর পাব/সাব:

মনিটরিং ভিউয়ার ভূমিকাটি মঞ্জুর করুন।

gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/monitoring.viewer"

CREMA পরিষেবা SA দেখার জন্য সাবস্ক্রিপশনে একটি পলিসি যোগ করুন।

gcloud pubsub subscriptions add-iam-policy-binding $SUBSCRIPTION_ID \
  --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/pubsub.viewer"

CREMA SA-এর জন্য সার্ভিস অ্যাকাউন্ট ইউজারও প্রয়োজন, যা ইনস্ট্যান্স সংখ্যা পরিবর্তন করার জন্য দরকারি:

gcloud iam service-accounts add-iam-policy-binding \
    $CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com \
    --member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
    --role="roles/iam.serviceAccountUser"

৫. SA-এর অনুমতি যাচাই করুন

কোডল্যাব শুরু করার আগে, যাচাই করে নিন যে CREMA সার্ভিস SA-এর সঠিক প্রজেক্ট-স্তরের রোলগুলো আছে।

gcloud projects get-iam-policy $PROJECT_ID \
  --flatten="bindings[].members" \
  --format="table(bindings.role)" \
  --filter="bindings.members:serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com"

এর ফলে নিম্নলিখিত বিষয়গুলো হওয়া উচিত:

roles/monitoring.viewer
roles/parametermanager.parameterViewer
roles/run.developer

যাচাই করুন যে পাব/সাব সাবস্ক্রিপশনটিতে এমন একটি পলিসি আছে যা CREMA সার্ভিস SA-কে এটি দেখার অনুমতি দেয়।

gcloud pubsub subscriptions get-iam-policy $SUBSCRIPTION_ID \
  --flatten="bindings[].members" \
  --filter="bindings.members:serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --format="table(bindings.role)"

এর ফলে হওয়া উচিত

roles/pubsub.viewer

এবং যাচাই করুন যে CREMA SA-এর সার্ভিস অ্যাকাউন্ট ইউজার রোল আছে।

gcloud iam service-accounts get-iam-policy \
  $CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com \
  --flatten="bindings[].members" \
  --filter="bindings.members:serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com"

এর ফলে নিম্নলিখিত বিষয়গুলো হওয়া উচিত

bindings:
  members: serviceAccount:crema-service-account@<PROJECT_ID>.iam.gserviceaccount.com
  role: roles/iam.serviceAccountUser

এবং ওয়ার্কার পুল কনজিউমার SA-এর পাব/সাব সাবস্ক্রাইবার ভূমিকা রয়েছে।

gcloud pubsub subscriptions get-iam-policy $SUBSCRIPTION_ID \
  --flatten="bindings[].members" \
  --filter="bindings.members:serviceAccount:$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --format="table(bindings.role)"

এর ফলে হওয়া উচিত

ROLE
roles/pubsub.subscriber

৬. কনজিউমার ওয়ার্কার পুল তৈরি এবং স্থাপন করুন

আপনার কনজিউমার কোডের জন্য একটি ডিরেক্টরি তৈরি করুন এবং সেটি প্রবেশ করান।

mkdir consumer
cd consumer
  1. একটি consumer.py ফাইল তৈরি করুন
import os
import time
from google.cloud import pubsub_v1
from concurrent.futures import TimeoutError

# Configuration
PROJECT_ID = os.environ.get('PROJECT_ID')
SUBSCRIPTION_ID = os.environ.get('SUBSCRIPTION_ID')

subscription_path = f"projects/{PROJECT_ID}/subscriptions/{SUBSCRIPTION_ID}"

print(f"Worker Pool instance starting. Watching {subscription_path}...")

subscriber = pubsub_v1.SubscriberClient()

def callback(message):
    try:
        data = message.data.decode("utf-8")
        print(f"Processing job: {data}")
        time.sleep(5)  # Simulate work
        print(f"Done {data}")
        message.ack()
    except Exception as e:
        print(f"Error processing message: {e}")
        message.nack()

streaming_pull_future = subscriber.subscribe(subscription_path, callback=callback)
print(f"Listening for messages on {subscription_path}...")

# Wrap subscriber in a 'with' block to automatically call close() when done.
with subscriber:
    try:
        # When `timeout` is not set, result() will block indefinitely,
        # unless an exception is encountered first.
        streaming_pull_future.result()
    except TimeoutError:
        streaming_pull_future.cancel()  # Trigger the shutdown.
        streaming_pull_future.result()  # Block until the shutdown is complete.
    except Exception as e:
        print(f"Streaming pull failed: {e}")
  1. একটি Dockerfile তৈরি করুন
FROM python:3.12-slim
RUN pip install google-cloud-pubsub
COPY consumer.py .
CMD ["python", "-u", "consumer.py"]
  1. কনজিউমার ওয়ার্কার পুল স্থাপন করুন

এই কোডল্যাবটি শুরুতে ওয়ার্কার পুলটি ০টি ইনস্ট্যান্স দিয়ে ডেপ্লয় করার পরামর্শ দেয়, যাতে সাবস্ক্রিপশনে পাব/সাব মেসেজ শনাক্ত করার পর CREMA কীভাবে ওয়ার্কার পুলটিকে স্কেল করে তা আপনি দেখতে পারেন।

gcloud beta run worker-pools deploy $CONSUMER_WORKER_POOL_NAME \
  --source . \
  --region $REGION \
  --service-account="$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
  --instances=0 \
  --set-env-vars PROJECT_ID=$PROJECT_ID,SUBSCRIPTION_ID=$SUBSCRIPTION_ID

৭. CREMA কনফিগার করুন

  1. আপনার প্রোজেক্টের রুট ডিরেক্টরিতে ফিরে যান।
cd ..
  1. কনফিগারেশন ফাইল তৈরি করুন। crema-config.yaml নামে একটি ফাইল তৈরি করুন।
apiVersion: crema/v1
kind: CremaConfig
spec:
  pollingInterval: 30
  triggerAuthentications:
    - metadata:
        name: adc-trigger-auth
      spec:
        podIdentity:
          provider: gcp
  scaledObjects:
    - spec:
        scaleTargetRef:
          name: projects/PROJECT_ID_PLACEHOLDER/locations/REGION_PLACEHOLDER/workerpools/CONSUMER_WORKER_POOL_NAME_PLACEHOLDER
        triggers:
          - type: gcp-pubsub
            metadata:
              subscriptionName: "SUBSCRIPTION_ID_PLACEHOLDER"
              # Target number of undelivered messages per worker instance
              value: "10"
              mode: "SubscriptionSize"
            authenticationRef:
              name: adc-trigger-auth
  1. বিকল্প চলক
sed -i "s/PROJECT_ID_PLACEHOLDER/$PROJECT_ID/g" crema-config.yaml
sed -i "s/REGION_PLACEHOLDER/$REGION/g" crema-config.yaml
sed -i "s/CONSUMER_WORKER_POOL_NAME_PLACEHOLDER/$CONSUMER_WORKER_POOL_NAME/g" crema-config.yaml
sed -i "s/SUBSCRIPTION_ID_PLACEHOLDER/$SUBSCRIPTION_ID/g" crema-config.yaml
  1. আপনার crema-config.yaml সঠিক কিনা তা যাচাই করুন।
if grep -q "_PLACEHOLDER" crema-config.yaml; then
  echo "❌ ERROR: Validations failed. '_PLACEHOLDER' was found in crema-config.yaml."
  echo "Please check your environment variables and run the 'sed' commands again."
else
  echo "✅ Config check passed: No placeholders found."
fi
  1. প্যারামিটার ম্যানেজারে আপলোড করুন

প্যারামিটার ম্যানেজারের জন্য অতিরিক্ত পরিবেশ ভেরিয়েবল সেট করুন

export PARAMETER_ID=crema-config
export PARAMETER_REGION=global
export PARAMETER_VERSION=1

প্যারামিটার রিসোর্স তৈরি করুন

gcloud parametermanager parameters create $PARAMETER_ID \
  --location=$PARAMETER_REGION \
  --parameter-format=YAML

প্যারামিটার সংস্করণ ১ তৈরি করুন

gcloud parametermanager parameters versions create $PARAMETER_VERSION \
  --parameter=crema-config \
  --project=$PROJECT_ID \
  --location=$PARAMETER_REGION \
  --payload-data-from-file=crema-config.yaml

প্যারামিটারটি সফলভাবে যোগ করা হয়েছে কিনা তা যাচাই করুন।

gcloud parametermanager parameters versions list \
  --parameter=$PARAMETER_ID \
  --location=$PARAMETER_REGION

আপনার এরকম কিছু দেখা উচিত

projects/<YOUR_PROJECT_ID>/locations/global/parameters/crema-config/versions/1

৮. CREMA পরিষেবা স্থাপন করুন

এই অংশে, আপনি CREMA অটোস্কেলার সার্ভিসটি ডেপ্লয় করবেন। এর জন্য আপনি পাবলিকলি অ্যাভেইলেবল ইমেজটি ব্যবহার করবেন।

  1. CREMA-এর জন্য প্রয়োজনীয় এনভায়রনমেন্ট ভেরিয়েবল সেট করুন।
CREMA_CONFIG_PARAM_VERSION=projects/$PROJECT_ID/locations/$PARAMETER_REGION/parameters/$PARAMETER_ID/versions/$PARAMETER_VERSION
  1. সংস্করণ নামের পথ যাচাই করুন
echo $CREMA_CONFIG_PARAM_VERSION

এটা দেখতে হওয়া উচিত এইরকম

projects/<YOUR_PROJECT>/locations/global/parameters/crema-config/versions/1
  1. CREMA ইমেজের জন্য এনভায়রনমেন্ট ভেরিয়েবল সেট করুন।
IMAGE=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0
  1. এবং CREMA পরিষেবাটি স্থাপন করুন

মনে রাখবেন, মূল ছবিটি আবশ্যক।

gcloud beta run deploy $CREMA_SERVICE_NAME \
  --image=$IMAGE \
  --region=${REGION} \
  --service-account="${CREMA_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
  --no-allow-unauthenticated \
  --no-cpu-throttling \
  --labels=created-by=crema \
  --base-image=us-central1-docker.pkg.dev/serverless-runtimes/google-24/runtimes/java25 \
  --set-env-vars="CREMA_CONFIG=${CREMA_CONFIG_PARAM_VERSION},OUTPUT_SCALER_METRICS=True,ENABLE_CLOUD_LOGGING=True"

৯. লোড টেস্টিং

  1. এমন একটি স্ক্রিপ্ট তৈরি করুন যা পাব/সাব টপিকে মেসেজ প্রকাশ করবে।
touch load-pubsub.sh
  1. load-pubsub.sh ফাইলে নিম্নলিখিত কোডটি যোগ করুন।
#!/bin/bash
TOPIC_ID=${TOPIC_ID} 
PROJECT_ID=${PROJECT_ID}
NUM_MESSAGES=100

echo "Publishing $NUM_MESSAGES messages to topic $TOPIC_ID..."

for i in $(seq 1 $NUM_MESSAGES); do
  gcloud pubsub topics publish $TOPIC_ID --message="job-$i" --project=$PROJECT_ID &
  if (( $i % 10 == 0 )); then
    wait
    echo "Published $i messages..."
  fi
done
wait
echo "Done. All messages published."
  1. লোড টেস্ট চালান
chmod +x load-pubsub.sh
./load-pubsub.sh
  1. স্কেলিং নিরীক্ষণ করুন এবং ৩-৪ মিনিট অপেক্ষা করুন। নতুন authenticationRef কনফিগারেশনের উপর ভিত্তি করে ইনস্ট্যান্স সুপারিশ করা হচ্ছে কিনা তা দেখতে CREMA লগ দেখুন।
gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=$CREMA_SERVICE_NAME AND textPayload:SCALER" \
  --limit=20 \
  --format="value(textPayload)" \
  --freshness=5m
  1. প্রসেসিং নিরীক্ষণ করুন: কনজিউমারটি চালু হচ্ছে কিনা তা দেখতে এর লগগুলো দেখুন।
gcloud beta run worker-pools logs tail $CONSUMER_WORKER_POOL_NAME --region=$REGION

আপনার এই ধরনের লগ দেখা উচিত

Done job-100

১০. সমস্যা সমাধান

প্রথমে, আপনাকে নির্ধারণ করতে হবে যে সমস্যাটি CREMA পরিষেবা কনফিগারেশনের সাথে সম্পর্কিত, নাকি PubSub কনজিউমার কনফিগারেশনের সাথে।

PubSub কনজিউমার অটোস্কেলারকে 0-এর পরিবর্তে 1-এ সেট করুন। যদি এটি সাথে সাথে পাবসাব মেসেজ প্রসেস করা শুরু করে, তাহলে সমস্যাটি CREMA-এর। আর যদি এটি পাবসাব মেসেজ প্রসেস না করে, তাহলে সমস্যাটি পাবসাব কনজিউমারের।

১১. অভিনন্দন!

কোডল্যাবটি সম্পন্ন করার জন্য অভিনন্দন!

আমরা ক্লাউড রান ডকুমেন্টেশন পর্যালোচনা করার পরামর্শ দিই।

আমরা যা আলোচনা করেছি

  • কিভাবে একটি পাব/সাব টপিক ও সাবস্ক্রিপশন তৈরি করতে হয় এবং সেই টপিকে মেসেজ পাঠাতে হয়।
  • Pub/Sub থেকে মেসেজ গ্রহণ করে এমন একটি Cloud Run ওয়ার্কার পুল (কনজিউমার) কীভাবে ডেপ্লয় করবেন।
  • পাব/সাব সাবস্ক্রিপশনে থাকা মেসেজের সংখ্যার ওপর ভিত্তি করে আপনার ওয়ার্কার পুলকে স্বয়ংক্রিয়ভাবে স্কেল করার জন্য CREMA প্রজেক্টটিকে GitHub-এ ক্লাউড রান সার্ভিস হিসেবে কীভাবে ডেপ্লয় করবেন।
  • স্থানীয়ভাবে একটি পাইথন স্ক্রিপ্ট চালিয়ে লোড তৈরি করার মাধ্যমে আপনার অটোস্কেলিং কনফিগারেশন কীভাবে পরীক্ষা করবেন।

১২. পরিষ্কার করুন

এই টিউটোরিয়ালে ব্যবহৃত রিসোর্সগুলোর জন্য আপনার গুগল ক্লাউড অ্যাকাউন্টে চার্জ হওয়া এড়াতে, আপনি এই কোডল্যাবে তৈরি করা রিসোর্সগুলো মুছে ফেলতে পারেন অথবা পুরো প্রজেক্টটিই মুছে ফেলতে পারেন।

এই কোডল্যাবে ব্যবহৃত রিসোর্সগুলো মুছে ফেলুন

  1. Cloud Run CREMA পরিষেবাটি মুছে ফেলুন
gcloud run services delete $CREMA_SERVICE_NAME --region=$REGION --quiet
  1. ক্লাউড রান ওয়ার্কার পুল কনজিউমারটি মুছে ফেলুন
gcloud beta run worker-pools delete $CONSUMER_WORKER_POOL_NAME --region=$REGION --quiet
  1. পাব/সাব সাবস্ক্রিপশন এবং টপিকটি মুছে ফেলুন
gcloud pubsub subscriptions delete $SUBSCRIPTION_ID --quiet
gcloud pubsub topics delete $TOPIC_ID --quiet
  1. প্যারামিটার ম্যানেজার কনফিগারেশনটি মুছে ফেলুন

প্যারামিটারের ভিতরে থাকা সংস্করণটি মুছে ফেলুন

gcloud parametermanager parameters versions delete $PARAMETER_VERSION \
  --parameter=$PARAMETER_ID \
  --location=$PARAMETER_REGION \
  --quiet

এখন খালি প্যারামিটারটি মুছে ফেলুন

gcloud parametermanager parameters delete $PARAMETER_ID \
  --location=$PARAMETER_REGION \
  --quiet
  1. পরিষেবা অ্যাকাউন্টগুলি মুছে ফেলুন
gcloud iam service-accounts delete "$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" --quiet
gcloud iam service-accounts delete "$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" --quiet

অথবা পুরো প্রজেক্টটি মুছে ফেলুন

সম্পূর্ণ প্রজেক্টটি ডিলিট করতে, 'Manage Resources'- এ যান, ধাপ ২-এ তৈরি করা প্রজেক্টটি সিলেক্ট করুন এবং 'Delete' বেছে নিন। প্রজেক্টটি ডিলিট করলে, আপনাকে আপনার Cloud SDK-তে প্রজেক্ট পরিবর্তন করতে হবে। gcloud projects list চালিয়ে আপনি সমস্ত উপলব্ধ প্রজেক্টের তালিকা দেখতে পারেন।