-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refresh metrics per pod periodically #223
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: 罗泽轩 <[email protected]>
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: spacewander The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Hi @spacewander. Thanks for your PR. I'm waiting for a kubernetes-sigs member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
✅ Deploy Preview for gateway-api-inference-extension ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
/ok-to-test |
/retest |
@@ -120,56 +151,13 @@ func (p *Provider) refreshPodsOnce() { | |||
pod := k.(Pod) | |||
if _, ok := p.datastore.pods.Load(pod); !ok { | |||
p.podMetrics.Delete(pod) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we remove this, given the LoadAndDelete below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The map loads the pod is different from the map deletes the pod.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am confused, in line 161 p.podMetrics.Delete(pod)
, and then in line 162, p.podMetrics.LoadAndDelete(pod)
, won't line 162 always return false since the pod is already deleted in line 161?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching up! Sorry for misunderstanding you at the beginning. The p.podMetrics.LoadAndDelete(pod)
should be p.podMetricsRefresher.LoadAndDelete(pod)
. I will fix it soon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need another map in the first place? can't we put the PodMetricsRefresher in the PodMetrics struct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ahg-g
I tried it before. But if we put PodMetricsRefresher under PodMetrics, it's not easy to make it concurrency-safe without a big refactor. As PodMetricsRefresher needs to change PodMetrics on the fly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we should be able to do that, I sent out #350 which does a major refactor to the datastore/provider layer. It consolidating storage in one place under datastore, and so it does in-place updates to the metrics. Please take a look and advice is there are any concurrency issues that I may have missed.
Co-authored-by: Cong Liu <[email protected]>
Signed-off-by: spacewander <[email protected]>
Signed-off-by: spacewander <[email protected]>
@liu-cong |
@@ -120,56 +151,13 @@ func (p *Provider) refreshPodsOnce() { | |||
pod := k.(Pod) | |||
if _, ok := p.datastore.pods.Load(pod); !ok { | |||
p.podMetrics.Delete(pod) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am confused, in line 161 p.podMetrics.Delete(pod)
, and then in line 162, p.podMetrics.LoadAndDelete(pod)
, won't line 162 always return false since the pod is already deleted in line 161?
pkg/ext-proc/scheduling/scheduler.go
Outdated
} | ||
|
||
// Schedule finds the target pod based on metrics and the requested lora adapter. | ||
func (s *Scheduler) Schedule(req *LLMRequest) (targetPod backend.Pod, err error) { | ||
klog.V(logutil.VERBOSE).Infof("request: %v; metrics: %+v", req, s.podMetricsProvider.AllPodMetrics()) | ||
pods, err := s.filter.Filter(req, s.podMetricsProvider.AllPodMetrics()) | ||
klog.V(logutil.VERBOSE).Infof("request: %v; metrics: %+v", req, s.podMetricsProvider.AllFreshPodMetrics()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you remove the AllFreshPodMetrics()
from this logging? This was probably added in initial POC. This is really DEBUG level logging and can be very heavy if there are many pods in the pool
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@liu-cong
Updated.
@spacewander The change looks good to me, thank you! Since this is a pretty big change, I was wondering if you can perform some manual testing and update the testing results. /lgtm /hold For testing update |
I think we need to run a benchmark with this change. |
I have a couple of concerns with this design, and I am hesitant to move forward with it:
|
PR needs rebase. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
Agree with both concerns however both exist in current implementation and are not something introduced by this PR. IMO this PR is an improvement, provided that the benchmark shows improvements (or at least no regression). |
Yes, they do exist now, but it tries to solve a problem using the same approach (with a higher likelihood of Goroutine leak). Another issue is that it adds yet another cache, after this PR we will have three caches tracking pods: datastore.pods, podRefresher and prover.podMetrics and podMetricsRefresher, each has its type too: PodMetricsRefresher, backend.Pod, PodMetrics. We only need one cache and one type. Cleaning up the datastore cache started in the informer cache PR, but then I realized that we will benefit from a pod reconciler to handle probing, hence walking back that change. We could do this over two PRs:
I am happy to send a PR for step 1 to help accelerate execution in this direction. |
Agree with the "we have too many caches" part. Maybe we can do a refactor after this PR is merged (if the direction is acceptable, of course)? As this PR is broken by merge conflicts again.
Using requeue may be good, but here we use one go routines per task so that slow probes won't affect the other probes. Go runtime already uses a thread pool to schedule go routines, so it can manage the go routines effectively. Inventing another level of thread pool may be less helpful. BTW, is there any SLO about how many pods/models that an inference extension should handle? Anyway, we can reduce the chance of goroutine leaks by reducing the cache, which makes the lifecycle of pod/podmetrics clearer. |
Right, we could continue with this approach of using separate goroutines with careful tracking, I agree that go runtime will anyway limit the number of actual threads, but again I am concerned about goroutine leak, which happened to us in the past in kube-scheduler. My hunch is that using the pod controller will make probing straightforward, but I could be wrong. I sent out #350, which consolidates storage in the datastore, and the pod controller already accesses that to add/delete/update pod entries, I think it should be easy now to add probing updates as well. |
I suggested a similar consolidation followup refactor in #223 (comment). I will review #350 and hopefully this PR can be simplified based on that. |
I reviewed PR #350 and I believe it will make this PR much cleaner. @spacewander If you don't mind, I suggest rebasing once PR #350 is merged, and make the following changes:
|
It seems that there will be other ongoing refactor PRs from #350 (comment). I would like to continue the work once the codebase is stable. |
Apologies for the churn. Note that the two main refactoring, which restructured the repo, are done. What is left are improving test coverage, which should not impact this enhancement. Renaming the PodMetrics struct is not high priority and we can hold off that. I think this enhancement is the top priority now and we can prioritize getting it in. To align on the direction: I think creating a prober type that we instantiate every time we add a new PodMetric instance to the map is likely a good path forward, wdyt? |
@spacewander Thank you again for your patience! +1 with Abdullah. All the important refactoring is done and and I support holding off on any further refactoring and prioritizing this one, as this addresses a big risk. So just for the sake of clarity, I think we are really close of getting this done:
I am happy to help benchmarking this change once it's ready for review. What do you think @spacewander ? |
@ahg-g @liu-cong |
@spacewander Really appreciate your effort in this! Let me give it a try based the great work you already have. |
Fix #99