Pavel Schudel
07/28/2024, 5:23 PM@bentoml.service(
# workers="cpu_count",
resources={
"memory": "8Gi",
"cpu": "4",
},
workers=4,
http={"port": 8181},
tracing={
"exporter_type": "jaeger",
"sample_rate": 1.0,
"jaeger": {
"protocol": "thrift",
"collector_endpoint": "<http://localhost:14268/api/traces?format=jaeger.thrift>",
"thrift": {
"agent_host_name": "localhost",
"agent_port": 6831,
"udp_split_oversized_batches": True,
}
}
}
)
class AnchorModels:
def __init__(self):
self.cross_encoder = CrossEncoder(
"cross-encoder/stsb-distilroberta-base",
num_labels=1,
device="cpu",
)
@bentoml.api()
async def rank(self, query: str, documents: list[str], ctx: bentoml.Context):
scores = self.cross_encoder.rank(query, documents)
# turn score to float instead of numpy float that causes serialization issue
scores = [
{"corpus_id": score["corpus_id"], "score": float(score["score"])}
for score in scores
]
return scores
but it doesn’t seem to parallelize the requests. I set the number of workers to 4 but it processes at most 2 requests.
here is a trace with jaeger .Jian Shen Yap
07/29/2024, 8:14 AMresources={
"memory": "8Gi",
"cpu": "4",
},
Does not set 4 workers nor uses 4 core of the CPU, this is a BentoCloud related feature and does not do anything within BentoML.
Also, if you managed to run 4 workers locally, do you see 4 process spun in the access logs?Pavel Schudel
07/29/2024, 8:20 AM> lsof -i :8181
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python3.1 82313 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82475 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82476 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82477 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82478 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82479 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82480 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82481 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82482 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82483 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82484 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82486 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82488 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82490 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82497 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82498 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82499 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82500 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82506 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82547 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 82548 pavelschudel 3u IPv4 0x8286e06ddbdf4a25 0t0 TCP *:8181 (LISTEN)
python3.1 97014 pavelschudel 103u IPv4 0x8286e06ddcb514b5 0t0 TCP localhost:65306->localhost:8181 (CLOSED)
python3.1 97014 pavelschudel 104u IPv4 0x8286e06ddde114b5 0t0 TCP localhost:65304->localhost:8181 (CLOSED)
python3.1 97014 pavelschudel 106u IPv4 0x8286e06dde0c94b5 0t0 TCP localhost:65307->localhost:8181 (CLOSED)
python3.1 97014 pavelschudel 107u IPv4 0x8286e06ddef55f45 0t0 TCP localhost:65308->localhost:8181 (CLOSED)
python3.1 97014 pavelschudel 108u IPv4 0x8286e06ddef67465 0t0 TCP localhost:65309->localhost:8181 (CLOSED)
this is what is see listening on port 8181 where my service is running. I don’t see logs of number of workers started. I remember in the old ranners API there was logging for number of workers.Jian Shen Yap
07/29/2024, 8:32 AMimport bentoml
@bentoml.service(
workers=4
)
class svc:
@bentoml.api
def predict(self, inputs: str) -> str:
# print current python process id
import os
print(f"Current process id: {os.getpid()}")
import time
print("Sleeping for 5 seconds")
time.sleep(5)
return f"{inputs}"
if you run the code above and run ps aux | grep python
you should see there is a main process and 4 subprocesses running. and that should handle up to 4 concurrent requestPavel Schudel
07/29/2024, 8:36 AM@bentoml.service(
workers=4,
http={"port": 8181},
)
class AnchorModels:
@bentoml.api
def rank(self, query: str, documents: list[str]) -> str:
# print current python process id
import os
print(f"Current process id: {os.getpid()}")
import time
print("Sleeping for 5 seconds")
time.sleep(5)
return f"{query}"Pavel Schudel
07/29/2024, 8:37 AMPavel Schudel
07/29/2024, 8:37 AMPavel Schudel
07/29/2024, 8:38 AMCurrent process id: 16870
Sleeping for 5 seconds
2024-07-29T11:36:11+0300 [INFO] [entry_service:AnchorModels:2] 127.0.0.1:56576 (scheme=http,method=POST,path=/rank,type=application/json,length=3076) (status=200,type=text/plain; charset=utf-8,length=42) 5018.664ms (trace=5104f3ea590d1bb70bb48871d6750789,span=789b36608e2791b0,sampled=0,service.name=AnchorModels)
Current process id: 16870
Sleeping for 5 seconds
2024-07-29T11:36:16+0300 [INFO] [entry_service:AnchorModels:2] 127.0.0.1:56580 (scheme=http,method=POST,path=/rank,type=application/json,length=3076) (status=200,type=text/plain; charset=utf-8,length=42) 10028.010ms (trace=9163fdac36c903c27a0eada96112bb98,span=ebf5042d9024ef4d,sampled=0,service.name=AnchorModels)
Current process id: 16870
Sleeping for 5 seconds
2024-07-29T11:36:21+0300 [INFO] [entry_service:AnchorModels:2] 127.0.0.1:56581 (scheme=http,method=POST,path=/rank,type=application/json,length=3076) (status=200,type=text/plain; charset=utf-8,length=42) 15048.424ms (trace=963fb6e2b24b4ce33f9b0c2284a86df5,span=7fd6dcdf3919dc32,sampled=0,service.name=AnchorModels)
Current process id: 16870
Sleeping for 5 secondsPavel Schudel
07/29/2024, 8:38 AMJian Shen Yap
07/29/2024, 8:38 AMJian Shen Yap
07/29/2024, 8:39 AMbentoml serve?Pavel Schudel
07/29/2024, 8:39 AMJian Shen Yap
07/29/2024, 8:39 AMPavel Schudel
07/29/2024, 8:40 AMPavel Schudel
07/29/2024, 8:40 AMPavel Schudel
07/29/2024, 8:40 AMclass AsyncCrossEncoder:
async def rank(self, querie, documents):
async with bentoml.AsyncHTTPClient(env.MODELS_URL, timeout=300) as client:
print("sent request")
return await client.rank(query=querie, documents=documents) # type: ignoreJian Shen Yap
07/29/2024, 8:42 AMps aux | grep pythonPavel Schudel
07/29/2024, 8:44 AMpavelschudel 32189 0.3 0.8 37485340 256108 ?? Ss 11:42AM 0:02.56 /Users/pavelschudel/opt/anaconda3/envs/anchor/bin/python -m _bentoml_impl.worker.service models.service:AnchorModels --fd 3 --service-name AnchorModels --backlog 2048 --worker-id 2 --prometheus-dir /Users/pavelschudel/bentoml/prometheus_multiproc_dir --ssl-version 17 --ssl-ciphers TLSv1
pavelschudel 32188 0.3 0.8 37501724 255800 ?? Ss 11:42AM 0:02.59 /Users/pavelschudel/opt/anaconda3/envs/anchor/bin/python -m _bentoml_impl.worker.service models.service:AnchorModels --fd 3 --service-name AnchorModels --backlog 2048 --worker-id 1 --prometheus-dir /Users/pavelschudel/bentoml/prometheus_multiproc_dir --ssl-version 17 --ssl-ciphers TLSv1
pavelschudel 32191 0.3 0.8 37501724 257560 ?? Ss 11:42AM 0:02.57 /Users/pavelschudel/opt/anaconda3/envs/anchor/bin/python -m _bentoml_impl.worker.service models.service:AnchorModels --fd 3 --service-name AnchorModels --backlog 2048 --worker-id 4 --prometheus-dir /Users/pavelschudel/bentoml/prometheus_multiproc_dir --ssl-version 17 --ssl-ciphers TLSv1
pavelschudel 32190 0.3 0.8 37500740 262232 ?? Ss 11:42AM 0:02.56 /Users/pavelschudel/opt/anaconda3/envs/anchor/bin/python -m _bentoml_impl.worker.service models.service:AnchorModels --fd 3 --service-name AnchorModels --backlog 2048 --worker-id 3 --prometheus-dir /Users/pavelschudel/bentoml/prometheus_multiproc_dir --ssl-version 17 --ssl-ciphers TLSv1Pavel Schudel
07/29/2024, 8:44 AMJian Shen Yap
07/29/2024, 8:51 AMPavel Schudel
07/29/2024, 8:58 AMimport asyncio
import httpx
async def send_request(client, url, data):
try:
response = await <http://client.post|client.post>(url, json=data, timeout=100.0) # Set a timeout of 10 seconds
return response.text
except httpx.ReadTimeout:
return {"error": "Request timed out"}
async def send_multiple_requests(url, queries, documents, num_requests):
async with httpx.AsyncClient() as client:
tasks = []
for i in range(num_requests):
data = {
"query": queries[i % len(queries)],
"documents": documents[i % len(documents)]
}
tasks.append(send_request(client, url, data))
responses = await asyncio.gather(*tasks)
return responses
url = "<http://localhost:8181/rank>"
queries = ["example query 1", "example query 2"]
documents = [["doc1", "doc2", "doc3"], ["doc4", "doc5", "doc6"]]
await send_multiple_requests(url, queries, documents, 2)
got results in 5 seconds.
Current process id: 52413
Sleeping for 5 seconds
Current process id: 52412
Sleeping for 5 seconds
2 distinct processes
for 3 requests
Current process id: 52412
Sleeping for 5 seconds
Current process id: 52413
Sleeping for 5 seconds
Current process id: 52413
Sleeping for 5 seconds
still only 2 processes and took 10 secondsPavel Schudel
07/29/2024, 8:58 AMCurrent process id: 61456
Sleeping for 5 seconds
Current process id: 61454
Sleeping for 5 seconds
Current process id: 61455
Sleeping for 5 seconds
Current process id: 61455
Sleeping for 5 seconds
(restarted the server)Jian Shen Yap
07/29/2024, 9:00 AMPavel Schudel
07/29/2024, 9:01 AMPavel Schudel
07/29/2024, 9:10 AMCounter({'76679': 15, '76677': 3, '76680': 2})
not very random I must say.Pierre Lecerf
08/13/2024, 7:23 AM