Skip to content
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

cri: get pid count from container metrics #10375

Merged
merged 1 commit into from
Jul 1, 2024
Merged

Conversation

linxiulei
Copy link
Contributor

This reduces latency of ListPodSandboxStats() by avoiding calling shim API Task().

Prior to this commit, the latency of calling ListPodSandboxStats() with 35 sandboxes (one container per sandbox) took 450ms. Mostly it was due to calling Task() to each container's shim, which took 10ms.

However, the pid count has already been present in collected cgroup metrics so this commit reuses that info to improve performance. It also means Windows platform would still need to call Task().

After this commit, the latency of ListPodSandboxStats() is about 120ms.

@k8s-ci-robot
Copy link

Hi @linxiulei. Thanks for your PR.

I'm waiting for a containerd member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

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.

@linxiulei
Copy link
Contributor Author

/retest

3 similar comments
@linxiulei
Copy link
Contributor Author

/retest

@linxiulei
Copy link
Contributor Author

/retest

@linxiulei
Copy link
Contributor Author

/retest

Comment on lines 478 to 480
default:
return 0, fmt.Errorf("unexpected metrics type: %T from %s", metrics, reflect.TypeOf(metrics).Elem().PkgPath())
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the code further up in linuxContainerMetrics (where this function is called), it looks like that function accepts wstats.Statistics, but here we produce an error for it.

case typeurl.Is(stats.Data, (*cg1.Metrics)(nil)):
data = &cg1.Metrics{}
case typeurl.Is(stats.Data, (*cg2.Metrics)(nil)):
data = &cg2.Metrics{}
case typeurl.Is(stats.Data, (*wstats.Statistics)(nil)):
data = &wstats.Statistics{}
default:
return nil, errors.New("cannot convert metric data to cgroups.Metrics or windows.Statistics")
}

So probably we should either add the type here (and ignore), or change that switch above to return an error if we can't accept it.

I'm also wondering if we should roll up the unmarshaling inside those branches at the cost of duplicating 3 lines of code, so that we don't have to do the type-assertions multiple times;

if err := typeurl.UnmarshalTo(stats.Data, data); err != nil {
	return containerStats{}, fmt.Errorf("failed to extract container metrics: %w", err)
}

In that case we can inline the code to get the number of pids;

var data interface{}
var pids int
switch {
case typeurl.Is(stats.Data, (*cg1.Metrics)(nil)):
    data = &cg1.Metrics{}
    if err := typeurl.UnmarshalTo(stats.Data, data); err != nil {
        return nil, fmt.Errorf("failed to extract container metrics: %w", err)
    }
    pids = metrics.GetPids().GetCurrent()
case typeurl.Is(stats.Data, (*cg2.Metrics)(nil)):
    data = &cg2.Metrics{}
    if err := typeurl.UnmarshalTo(stats.Data, data); err != nil {
        return nil, fmt.Errorf("failed to extract container metrics: %w", err)
    }
    pids = metrics.GetPids().GetCurrent()
case typeurl.Is(stats.Data, (*wstats.Statistics)(nil)):
    // FIXME: should this be an error on Linux??
    data = &wstats.Statistics{}
    if err := typeurl.UnmarshalTo(stats.Data, data); err != nil {
        return nil, fmt.Errorf("failed to extract container metrics: %w", err)
    }
default:
    return nil, errors.New("cannot convert metric data to cgroups.Metrics or windows.Statistics")
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

case typeurl.Is(stats.Data, (*wstats.Statistics)(nil)): 
	data = &wstats.Statistics{} 

Actually, I am not sure if this code is dead as I think this is for windows platform. At least internal/cri/server/sandbox_stats_linux.go should never care about wstats.Statistics since it assumes Linux.

But anyway, I think it's safe to have pids as 0 without returning an error here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, I had a second look and found cpuContainerStats doesn't accept wstats.Statistics at all

func (c *criService) cpuContainerStats(ID string, isSandbox bool, stats interface{}, timestamp time.Time) (*runtime.CpuUsage, error) {
switch metrics := stats.(type) {
case *cg1.Metrics:
metrics.GetCPU().GetUsage()
if metrics.CPU != nil && metrics.CPU.Usage != nil {
return &runtime.CpuUsage{
Timestamp: timestamp.UnixNano(),
UsageCoreNanoSeconds: &runtime.UInt64Value{Value: metrics.CPU.Usage.Total},
}, nil
}
case *cg2.Metrics:
if metrics.CPU != nil {
// convert to nano seconds
usageCoreNanoSeconds := metrics.CPU.UsageUsec * 1000
return &runtime.CpuUsage{
Timestamp: timestamp.UnixNano(),
UsageCoreNanoSeconds: &runtime.UInt64Value{Value: usageCoreNanoSeconds},
}, nil
}
default:
return nil, fmt.Errorf("unexpected metrics type: %T from %s", metrics, reflect.TypeOf(metrics).Elem().PkgPath())
}
return nil, nil

It should be safe to return an error early here.

Comment on lines +74 to +75
// pids is only valid in linux platform
pids uint64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if this would be a potential candidate for inclusion in runtime.ContainerStats, so that we don't need to define a wrapper in future 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was tempted to do so as well, but pids doesn't seem a common field for all platforms (i.e. windows) so not sure how feasible it is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I was curious about the Windows case; maybe there's still an equivalent somewhere, but if not, then it could possibly still be fine as long as it's documented "not used on Windows platforms".

@kevpar @kiashok do you know if there's an equivalent on Windows that could be implemented in future (and/or if it's relevant for Windows?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW; I don't think the current wrapper is too problematic; it's not exported, so only used internally. I merely went looking if we could reduce code-churn somehow, but as the runtime.ContainerStats is not owned by containerd, that would require upstream changes first, so in the meantime having the wrapper isn't a huge issue (for me at least 😄)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to make sure I'm understanding: pids is the number of processes in the container, and the question is "does Windows support querying for this as well, so that it would make sense to make it a common field?"?

HCS does support querying for an array of info on each process in the container, so you could use that to determine the count. At the HCS level it is returned as a JSON object with an array of process entries, rather than a single count, though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, we can create new issue to track this question. This patch is to reduce api calls. It's not intend to introduce new field in CRI-API.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @kevpar yes, I think "yes to both" - if having this information makes sense to both Windows and Linux, possibly it could be included in the type.

Definitely not a blocker (as mentioned; changes in this PR are internal, so perfectly fine for now).

@samuelkarp samuelkarp added the area/cri Container Runtime Interface (CRI) label Jun 26, 2024
@linxiulei linxiulei force-pushed the podstats branch 3 times, most recently from 804fc2e to a53f4c0 Compare June 27, 2024 10:09
@linxiulei
Copy link
Contributor Author

@thaJeztah would you mind LGTM-ing this? Thanks!

Copy link
Member

@fuweid fuweid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Left one comment on test. Thank you for the fix.

internal/cri/server/container_stats_list_test.go Outdated Show resolved Hide resolved
Comment on lines +74 to +75
// pids is only valid in linux platform
pids uint64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, we can create new issue to track this question. This patch is to reduce api calls. It's not intend to introduce new field in CRI-API.

This reduces latency of calling ListPodSandboxStats() by avoiding calling
shim API Task().

Signed-off-by: Eric Lin <[email protected]>
@linxiulei
Copy link
Contributor Author

/retest

1 similar comment
@linxiulei
Copy link
Contributor Author

/retest

@samuelkarp samuelkarp enabled auto-merge July 1, 2024 18:26
@samuelkarp samuelkarp added this pull request to the merge queue Jul 1, 2024
Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jul 1, 2024
@fuweid fuweid added this pull request to the merge queue Jul 1, 2024
Merged via the queue into containerd:main with commit 1fb1882 Jul 1, 2024
47 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/cri Container Runtime Interface (CRI) ok-to-test size/L
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants