হাই, আছে!
মাঝে মাঝে, দ্রুত লোড পরীক্ষার প্রয়োজন দেখা দেয়, তা স্থানীয় পরিবেশে হোক বা পরীক্ষার প্ল্যাটফর্মে হোক। সাধারণত, এই জাতীয় কাজগুলি বিশেষ সরঞ্জামগুলি ব্যবহার করে মোকাবেলা করা হয় যা পুঙ্খানুপুঙ্খ পূর্ব বোঝার দাবি রাখে। যাইহোক, এন্টারপ্রাইজ এবং স্টার্টআপের মধ্যে যেখানে দ্রুত সময়ে-টু-বাজার এবং প্রম্পট হাইপোথিসিস বৈধতা সর্বাগ্রে, অত্যধিক টুল পরিচিতি একটি বিলাসিতা হয়ে ওঠে।
এই নিবন্ধটির লক্ষ্য হল ডেভেলপার-কেন্দ্রিক সমাধানগুলিকে আলোকিত করা যা গভীর ব্যস্ততার প্রয়োজনীয়তা দূর করে, ডকুমেন্টেশনের পৃষ্ঠাগুলিতে না গিয়ে প্রাথমিক পরীক্ষার অনুমতি দেয়।
স্থানীয় চলমান
আপনার ইনস্টল করা উচিত::
ডকার - এর জন্য সমস্ত পরিষেবা এবং সরঞ্জাম প্রয়োজন।
জাভা 19+ — কোটলিন পরিষেবার জন্য। এছাড়াও, আপনি Java 8 সংস্করণ ব্যবহার করার চেষ্টা করতে পারেন; এটি কাজ করা উচিত, কিন্তু আপনাকে Gradle সেটিংস পরিবর্তন করতে হবে।
গোলং - একটি পরিষেবা হল গোলং পরিষেবা =)
পাইথন 3+ — ইয়ানডেক্স ট্যাঙ্কের জন্য।
আমাদের যাত্রা শুরু করার আগে, পরীক্ষার উদ্দেশ্যে দৃষ্টান্তমূলক উদাহরণ হিসাবে কাজ করতে পারে এমন কয়েকটি পরিষেবা তৈরি করার পরামর্শ দেওয়া হয়।
স্ট্যাক: কোটলিন + ওয়েবফ্লাক্স। r2dbc + postgres।
আমাদের পরিষেবা আছে:
- সমস্ত স্টক পান (সীমা 10) পান
- GET__ /api/v1/stock নামে স্টক পান
- স্টক পোস্ট সংরক্ষণ করুন /
এটি একটি সহজ পরিষেবা হওয়া উচিত কারণ আমাদের লোড পরীক্ষার উপর ফোকাস করতে হবে =)
এর ভিতরে কিছু মৌলিক যুক্তি সহ একটি ছোট পরিষেবা তৈরি করে শুরু করা যাক। আমরা এই উদ্দেশ্যে একটি মডেল প্রস্তুত করব:
@Table("stocks") data class Stock( @field:Id val id: Long?, val name: String, val price: BigDecimal, val description: String )
সহজ রাউটার:
@Configuration @EnableConfigurationProperties(ServerProperties::class) class StockRouter( private val properties: ServerProperties, private val stockHandler: StockHandler ) { @Bean fun router() = coRouter { with(properties) { main.nest { contentType(APPLICATION_JSON).nest { POST(save, stockHandler::save) } GET(find, stockHandler::find) GET(findAll, stockHandler::findAll) } } } }
এবং হ্যান্ডলার:
@Service class StockHandlerImpl( private val stockService: StockService ) : StockHandler { private val logger = KotlinLogging.logger {} private companion object { const val DEFAULT_SIZE = 10 const val NAME_PARAM = "name" } override suspend fun findAll(req: ServerRequest): ServerResponse { logger.debug { "Processing find all request: $req" } val stocks = stockService.getAll(DEFAULT_SIZE) return ServerResponse.ok() .contentType(MediaType.APPLICATION_JSON) .body(stocks, StockDto::class.java) .awaitSingle() } override suspend fun find(req: ServerRequest): ServerResponse { logger.debug { "Processing find all request: $req" } val name = req.queryParam(NAME_PARAM) return if (name.isEmpty) { ServerResponse.badRequest().buildAndAwait() } else { val stocks = stockService.find(name.get()) ServerResponse.ok() .contentType(MediaType.APPLICATION_JSON) .body(stocks, StockDto::class.java) .awaitSingle() } } override suspend fun save(req: ServerRequest): ServerResponse { logger.debug { "Processing save request: $req" } val stockDto = req.awaitBodyOrNull(StockDto::class) return stockDto?.let { dto -> stockService.save(dto) ServerResponse .ok() .contentType(MediaType.APPLICATION_JSON) .bodyValue(dto) .awaitSingle() } ?: ServerResponse.badRequest().buildAndAwait() } }
সম্পূর্ণ কোড এখানে:
একটি ডকার ফাইল তৈরি করুন:
FROM openjdk:20-jdk-slim VOLUME /tmp COPY build/libs/*.jar app.jar ENTRYPOINT ["java", "-Dspring.profiles.active=stg", "-jar", "/app.jar"]
তারপর, একটি ডকার ইমেজ তৈরি করুন এবং এটি টিউন করুন 🤤
docker build -t ere/stock-service . docker run -p 8085:8085 ere/stock-service
কিন্তু আপাতত, ডকার কন্টেইনারগুলির মাধ্যমে সবকিছু চালানোর ধারণার সাথে লেগে থাকা এবং আমাদের পরিষেবাটিকে একটি ডকার কম্পোজ সেটআপে স্থানান্তর করা ভাল।
version: '3.1' services: db: image: postgres container_name: postgres-stocks ports: - "5432:5432" environment: POSTGRES_PASSWORD: postgres adminer: image: adminer ports: - "8080:8080" stock-service: image: ere/stock-service container_name: stock-service ports: - "8085:8085" depends_on: - db
এগিয়ে যাওয়া: আমরা কীভাবে পরীক্ষা চালিয়ে যেতে পারি? বিশেষভাবে, কিভাবে আমরা আমাদের সাম্প্রতিক বিকশিত পরিষেবার জন্য একটি পরিমিত লোড পরীক্ষা শুরু করতে পারি? এটি অপরিহার্য যে পরীক্ষার সমাধানটি ইনস্টল করার জন্য সহজ এবং ব্যবহারকারী-বান্ধব উভয়ই।
আমাদের সময় সীমাবদ্ধতার প্রেক্ষিতে, বিস্তৃত ডকুমেন্টেশন এবং নিবন্ধগুলির মধ্যে অনুসন্ধান করা একটি কার্যকর বিকল্প নয়। সৌভাগ্যবশত, একটি কার্যকর বিকল্প আছে — Yandex ট্যাঙ্কে প্রবেশ করুন। ট্যাঙ্কটি পরীক্ষার জন্য একটি শক্তিশালী যন্ত্র এবং এর সাথে গুরুত্বপূর্ণ একীকরণ রয়েছে
ডক্স:
আমাদের পরীক্ষার জন্য একটি ফোল্ডার তৈরি করে শুরু করা যাক। একবার আমরা কনফিগারেশন এবং অন্যান্য প্রয়োজনীয় ফাইলগুলি রাখলে - সৌভাগ্যবশত, মাত্র কয়েকটি - আমরা প্রস্তুত হয়ে যাব।
আমাদের পরিষেবার জন্য, আমাদের "গেট-অল" এবং "সংরক্ষণ" পদ্ধতিগুলি পরীক্ষা করতে হবে। অনুসন্ধান পদ্ধতির জন্য প্রথম কনফিগারেশন।
phantom: address: localhost port: "8085" load_profile: load_type: rps schedule: line(100, 250, 30s) writelog: all ssl: false connection_test: true uris: - /api/v1/stocks overload: enabled: false telegraf: enabled: false autostop: autostop: - time(1s,10s) # if request average > 1s - http(5xx,100%,1s) # if 500 errors > 1s - http(4xx,25%,10s) # if 400 > 25% - net(xx,25,10) # if amount of non-zero net-codes in every second of last 10s period is more than 25
কনফিগারেশনের জন্য মূল সেটিংস:
ব্যাশ স্ক্রিপ্ট কপি এবং পেস্ট করুন (ট্যাঙ্ক sh):
docker run \ -v $(pwd):/var/loadtest \ --net="host" \ -it yandex/yandex-tank
এবং চালান!
এর ফলে আমরা কী দেখব? ইয়ানডেক্স ট্যাঙ্ক পরীক্ষার সময় যোগ্য বলে মনে করা সমস্ত কিছু লগ করবে। আমরা 99তম পার্সেন্টাইল এবং অনুরোধ প্রতি সেকেন্ড (আরপিএস) এর মতো মেট্রিকগুলি পর্যবেক্ষণ করতে পারি।
তাহলে, আমরা কি এখন টার্মিনালের সাথে আটকে আছি? আমি একটি GUI চাই! চিন্তা করবেন না, ইয়ানডেক্স ট্যাঙ্ক এর জন্যও একটি সমাধান রয়েছে। আমরা ওভারলোড প্লাগইনগুলির একটি ব্যবহার করতে পারি। এটি কীভাবে যুক্ত করবেন তার একটি উদাহরণ এখানে:
overload: enabled: true package: yandextank.plugins.DataUploader job_name: "save docs" token_file: "env/token.txt"
আমাদের টোকেন যোগ করা উচিত; শুধু এখানে যান এবং GitHub দ্বারা যুক্তি: https://overload.yandex.net
ঠিক আছে, একটি GET অনুরোধের সাথে মোকাবিলা করা সহজ, কিন্তু পোস্ট সম্পর্কে কী? আমরা কিভাবে অনুরোধ গঠন করব? ব্যাপারটা হল, আপনি শুধু অনুরোধটিকে ট্যাঙ্কে নিক্ষেপ করতে পারবেন না; আপনি এর জন্য নিদর্শন তৈরি করতে হবে! এই নিদর্শন কি? এটি সহজ — আপনাকে একটি ছোট স্ক্রিপ্ট লিখতে হবে, যা আপনি আবার ডকুমেন্টেশন থেকে আনতে পারেন এবং আমাদের প্রয়োজন অনুসারে কিছুটা পরিবর্তন করতে পারেন।
এবং আমাদের নিজেদের শরীর এবং শিরোনাম যোগ করা উচিত:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sys import json # http request with entity body template req_template_w_entity_body = ( "%s %s HTTP/1.1\r\n" "%s\r\n" "Content-Length: %d\r\n" "\r\n" "%s\r\n" ) # phantom ammo template ammo_template = ( "%d %s\n" "%s" ) method = "POST" case = "" headers = "Host: test.com\r\n" + \ "User-Agent: tank\r\n" + \ "Accept: */*\r\n" + \ "Connection: Close\r\n" def make_ammo(method, url, headers, case, body): """ makes phantom ammo """ req = req_template_w_entity_body % (method, url, headers, len(body), body) return ammo_template % (len(req), case, req) def generate_json(): body = { "name": "content", "price": 1, "description": "description" } url = "/api/v1/stock" h = headers + "Content-type: application/json" s1 = json.dumps(body) ammo = make_ammo(method, url, h, case, s1) sys.stdout.write(ammo) f2 = open("ammo/ammo-json.txt", "w") f2.write(ammo) if __name__ == "__main__": generate_json()
ফলাফল:
212 POST /api/v1/stock HTTP/1.1 Host: test.com User-Agent: tank Accept: */* Connection: Close Content-type: application/json Content-Length: 61 {"name": "content", "price": 1, "description": "description"}
এটাই! শুধু স্ক্রিপ্ট চালান, এবং আমাদের ammo-json.txt থাকবে। কনফিগার করার জন্য নতুন প্যারাম সেট করুন এবং URL গুলি মুছুন:
phantom: address: localhost:9001 ammo_type: phantom ammofile: ammo-json.txt
এবং এটি আরও একবার চালান!
এইচটিটিপি পদ্ধতি লোড করার সাথে পরিচিত হওয়ার পরে, জিআরপিসি-এর পরিস্থিতি বিবেচনা করা স্বাভাবিক। আমরা কি সৌভাগ্যবান যে GRPC-এর জন্য সমানভাবে অ্যাক্সেসযোগ্য টুল আছে, যা একটি ট্যাঙ্কের সরলতার মতো? উত্তরটি ইতিবাচক। আমাকে 'GHz' এর সাথে পরিচয় করিয়ে দেওয়ার অনুমতি দিন। একমূহুর্তের জন্য তাকাও:
কিন্তু আমরা তা করার আগে, আমাদের উচিত Go এবং GRPC-এর সাথে একটি ভাল পরীক্ষা পরিষেবা হিসাবে একটি ছোট পরিষেবা তৈরি করা।
একটি ছোট প্রোটো ফাইল প্রস্তুত করুন:
syntax = "proto3"; option go_package = "stock-grpc-service/stocks"; package stocks; service StocksService { rpc Save(SaveRequest) returns (SaveResponse) {} rpc Find(FindRequest) returns (FindResponse) {} } message SaveRequest { Stock stock = 1; } message SaveResponse { string code = 1; } message Stock { string name = 1; float price = 2; string description = 3; } message FindRequest { enum Type { INVALID = 0; BY_NAME = 1; } message ByName { string name = 1; } Type type = 1; oneof body { ByName by_name = 2; } } message FindResponse { Stock stock = 1; }
এবং এটি উৎপন্ন! (এছাড়াও, আমাদের প্রোটোক ইনস্টল করা উচিত)
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative stocks.proto
আমাদের ফলাফল:
পরবর্তী পদক্ষেপ: যত দ্রুত সম্ভব পরিষেবা তৈরি করুন।
dto তৈরি করুন (ডিবি স্তরের জন্য স্টক সত্তা)
package models // Stock – base dto type Stock struct { ID *int64 `json:"Id"` Price float32 `json:"Price"` Name string `json:"Name"` Description string `json:"Description"` }
সার্ভার বাস্তবায়ন
// Server is used to implement stocks.UnimplementedStocksServiceServer. type Server struct { pb.UnimplementedStocksServiceServer stockUC stock.UseCase } // NewStockGRPCService stock gRPC service constructor func NewStockGRPCService(emailUC stock.UseCase) *Server { return &Server{stockUC: emailUC} } func (e *Server) Save(ctx context.Context, request *stocks.SaveRequest) (*stocks.SaveResponse, error) { model := request.Stock stockDto := &models.Stock{ ID: nil, Price: model.Price, Name: model.Name, Description: model.Description, } err := e.stockUC.Create(ctx, stockDto) if err != nil { return nil, err } return &stocks.SaveResponse{Code: "ok"}, nil } func (e *Server) Find(ctx context.Context, request *stocks.FindRequest) (*stocks.FindResponse, error) { code := request.GetByName().GetName() model, err := e.stockUC.GetByID(ctx, code) if err != nil { return nil, err } response := &stocks.FindResponse{Stock: &stocks.Stock{ Name: model.Name, Price: model.Price, Description: model.Description, }} return response, nil }
সম্পূর্ণ কোড এখানে: ক্লিক করুন, দয়া করে!
এখন, আমাদের এটিকে কিছুটা পরিবর্তন করা উচিত:
প্রোটো ফাইল সহ ফোল্ডারে যান।
পদ্ধতি যোগ করুন: stocks.StocksService.Save .
সরল বডি যোগ করুন: '{“স্টক”: { “নাম”:”APPL”, “দাম”: “1.3”, “বিবরণ”: “আপেল স্টক”} }'।
20
গোরুটিন কর্মীদের মধ্যে 10
সংযোগ ভাগ করা হবে। 2
গোরুটিনের প্রতিটি জোড়া একটি একক সংযোগ ভাগ করবে৷
পরিষেবার পোর্ট সেট করুন
এবং ফলাফল:
cd .. && cd stock-grpc-service/proto ghz --insecure \ --proto ./stocks.proto \ --call stocks.StocksService.Save \ -d '{"stock": { "name":"APPL", "price": "1.3", "description": "apple stocks"} }' \ -n 2000 \ -c 20 \ --connections=10 \ 0.0.0.0:5007
চালাও এটা!
Summary: Count: 2000 Total: 995.93 ms Slowest: 30.27 ms Fastest: 3.11 ms Average: 9.19 ms Requests/sec: 2008.16 Response time histogram: 3.111 [1] | 5.827 [229] |∎∎∎∎∎∎∎∎∎∎∎ 8.542 [840] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎ 11.258 [548] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎ 13.973 [190] |∎∎∎∎∎∎∎∎∎ 16.689 [93] |∎∎∎∎ 19.405 [33] |∎∎ 22.120 [29] |∎ 24.836 [26] |∎ 27.551 [6] | 30.267 [5] | Latency distribution: 10 % in 5.68 ms 25 % in 6.67 ms 50 % in 8.27 ms 75 % in 10.49 ms 90 % in 13.88 ms 95 % in 16.64 ms 99 % in 24.54 ms Status code distribution: [OK] 2000 responses
এবং কি, আবার টার্মিনালে সবকিছু তাকান? না, GHz দিয়ে, আপনি একটি প্রতিবেদনও তৈরি করতে পারেন, কিন্তু Yandex-এর বিপরীতে, এটি স্থানীয়ভাবে তৈরি হবে এবং ব্রাউজারে খোলা যাবে। শুধু এটি সেট করুন:
ghz --insecure -O html -o reports_find.html \ ...
-O + html → আউটপুট ফরম্যাট
-o ফাইলের নাম
সংক্ষেপে, যখন প্রতি সেকেন্ডে 100+ অনুরোধের লোড পরিচালনা করার বা সম্ভাব্য দুর্বলতাগুলি সনাক্ত করার জন্য আপনার পরিষেবার ক্ষমতার দ্রুত মূল্যায়নের প্রয়োজন হয়, তখন দলগুলির সাথে জড়িত জটিল প্রক্রিয়াগুলি শুরু করার, AQA থেকে সহায়তা চাওয়া বা অবকাঠামো দলের উপর নির্ভর করার দরকার নেই৷
প্রায়শই নয়, বিকাশকারীদের কাছে সক্ষম ল্যাপটপ এবং কম্পিউটার রয়েছে যা একটি ছোট লোড পরীক্ষা চালাতে পারে। সুতরাং, এগিয়ে যান এবং এটি একটি শট দিন - নিজেকে কিছু সময় বাঁচান!
আমি বিশ্বাস করি আপনি এই সংক্ষিপ্ত নিবন্ধটি উপকারী পেয়েছেন।
ইয়ানডেক্স ট্যাঙ্ক: ডক্স লিঙ্ক
ইয়ানডেক্স ট্যাঙ্ক গিটহাব: গিটহাব লিঙ্ক
ইয়ানডেক্স ট্যাঙ্ক সেটিং: লিঙ্ক
GHz অফিসিয়াল পেজ: লিঙ্ক
GHz সেটিং: লিঙ্ক
GHz কনফিগারেশন: লিঙ্ক
আবারও ধন্যবাদ, এবং শুভকামনা! 🍀🕵🏻