$_GET vs get_query_var()

get_query_var() gets variables from the main instance of WP_Query. It’s the equivalent of running

global $wp_query;
$wp_query->get( 'posts_per_page' );

It is not directly related to $_GET in any way. However, WordPress has a list of ‘public’ query variables that will be applied to the main query if they are passed as URL parameters. This is what the query_vars is filtering. You can see the list here, as the $public_query_vars property of the WP class.

So when you run get_query_var('posts_per_page') you are getting the posts_per_page property of the main query. This will typically be the value from Settings > Reading. Passing ?posts_per_page=2 is not setting this value because posts_per_page is not a public query variable.