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

[Remote Vector Index Build] Add metric collection #2615

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

owenhalpert
Copy link
Contributor

@owenhalpert owenhalpert commented Mar 19, 2025

Description

Adds metric collection for various metrics related to the Remote Vector Index Build service, with stats only being returned in /stats if the feature flag is enabled. Also adds a flag to detect whether the index build is coming from merge or flush to get granular operation-level metrics.

Gist showing stats response with and without feature flag enabled: https://gist.github.com/owenhalpert/a05029924887390bed6c14d60b34bf01

New metrics (only returned if feature flag is enabled):

"remote_vector_index_build_stats" : {
        "repository_stats" : {
          "read_success_count" : 0,
          "read_failure_count" : 0,
          "successful_read_time_in_millis" : 0,
          "write_success_count" : 0,
          "write_failure_count" : 0,
          "successful_write_time_in_millis" : 0
        },
        "client_stats" : {
          "status_request_failure_count" : 0,
          "status_request_success_count" : 0,
          "index_build_success_count" : 0,
          "index_build_failure_count" : 1,
          "build_request_failure_count" : 0,
          "build_request_success_count" : 0,
          "waiting_time_in_ms" : 0
        },
        "build_stats" : {
          "remote_index_build_flush_time_in_millis" : 0,
          "remote_index_build_current_merge_operations" : 0,
          "remote_index_build_current_flush_operations" : 0,
          "remote_index_build_current_merge_size" : 0,
          "remote_index_build_current_flush_size" : 0,
          "remote_index_build_merge_time_in_millis" : 0
        }
},

From @jed326's original PR (#2566):

Complementary to these, existing repository implementations may also collect their own metrics. For example, repository-s3 collects metrics like so:
Existing repo metrics:

     "repositories" : [
        {
          "repository_name" : "vector-repo",
          "repository_type" : "s3",
          "repository_location" : {
            "bucket" : "gpu-acceleration",
            "base_path" : "vectors"
          },
          "request_time_in_millis" : {
            "ListObjects" : 49,
            "PutMultipartObject" : 0,
            "PutObject" : 199,
            "GetObject" : 38,
            "DeleteObjects" : 51
          },
          "request_retry_count_total" : {
            "ListObjects" : 0,
            "PutMultipartObject" : 0,
            "PutObject" : 0,
            "GetObject" : 0,
            "DeleteObjects" : 0
          },
          "request_failures_total" : {
            "ListObjects" : 0,
            "PutMultipartObject" : 0,
            "PutObject" : 0,
            "GetObject" : 0,
            "DeleteObjects" : 0
          },
          "generic_stats" : {
            "LowPriorityPermitsUtilization" : 0,
            "NormalPriorityPermitsUtilization" : 0,
            "LowPriorityQUtilization" : 0,
            "NormalPriorityQUtilization" : 0
          },
          "request_success_total" : {
            "ListObjects" : 1,
            "PutMultipartObject" : 0,
            "PutObject" : 6,
            "GetObject" : 3,
            "DeleteObjects" : 1
          }
        }
      ],

Related Issues

Meta #2391

Check List

  • New functionality includes testing.
    - [ ] New functionality has been documented.
    - [ ] API changes companion pull request created.
  • Commits are signed per the DCO using --signoff.
    - [ ] Public documentation issue/PR created.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@owenhalpert owenhalpert force-pushed the remote-metrics branch 9 times, most recently from a795d41 to 97a5c0c Compare March 19, 2025 22:33
Comment on lines 23 to 30
/**
* Build and write index with flush flag. Default implementation calls the non-flag version.
* RemoteIndexBuildStrategy will override this to use the flag.
*
* @param indexInfo {@link BuildIndexParams} containing information about the index to be built
* @param isFlush Flag indicating if operation is from flush (vs merge)
* @throws IOException if an error occurs during the build process
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can just explain that this is to differentiate the context for metrics purposes rather than explain what it is doing

Copy link
Collaborator

Choose a reason for hiding this comment

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

There doesn't seem to be a need for this method - why can't we add context in BuildIndexParams? the context can be either merge or flush

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can do that, good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@shatejas I added a boolean isFlush field in BuildIndexParams. I considered having this be a string of either merge or flush but I felt that keeping it as a boolean named isFlush is more clear for its usage.

Comment on lines +46 to +62
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.BUILD_REQUEST_FAILURE_COUNT;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.BUILD_REQUEST_SUCCESS_COUNT;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.INDEX_BUILD_FAILURE_COUNT;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.INDEX_BUILD_SUCCESS_COUNT;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.READ_FAILURE_COUNT;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.READ_SUCCESS_COUNT;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.READ_TIME;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.REMOTE_INDEX_BUILD_CURRENT_FLUSH_OPERATIONS;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.REMOTE_INDEX_BUILD_CURRENT_FLUSH_SIZE;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.REMOTE_INDEX_BUILD_CURRENT_MERGE_OPERATIONS;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.REMOTE_INDEX_BUILD_CURRENT_MERGE_SIZE;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.REMOTE_INDEX_BUILD_FLUSH_TIME;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.REMOTE_INDEX_BUILD_MERGE_TIME;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.WAITING_TIME;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.WRITE_FAILURE_COUNT;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.WRITE_SUCCESS_COUNT;
import static org.opensearch.knn.plugin.stats.KNNRemoteIndexBuildValue.WRITE_TIME;
Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking out loud here, should we try to offload all of the stats collection to a separate class? One example could be we have a MetricsCollectingRemoteIndexBuildStrategy extends RemoteIndexBuildStrategy which does all the metrics collection.

@owenhalpert owenhalpert force-pushed the remote-metrics branch 3 times, most recently from 0841e10 to 04e1b56 Compare March 25, 2025 00:05
Comment on lines +222 to +225
recordBuildRequestSuccess(stopWatch.stop().totalTime().millis(), indexInfo.getFieldName());
return remoteBuildResponse;
} catch (IOException e) {
recordBuildRequestFailure(stopWatch.stop().totalTime().millis(), indexInfo.getFieldName(), e);
Copy link
Collaborator

Choose a reason for hiding this comment

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

We need to do these in finally block. Any other exception and you are not capturing failure. another approach is to catch a generic approach which is generally not recommended. I see the pattern at other places as well.

bool success = false;
try {

success = true;

......
} finally {
    recordBuildRequestMetrics(success, stopWatch.millis);
}

I see you are passing in the exception and its just used for logging. Please log in the catch block so you don't have to pass the error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants