StackExchange.Redis+;Azure Redis速度不一致

StackExchange.Redis+;Azure Redis速度不一致,azure,asp.net-web-api,redis,stackexchange.redis,azure-redis-cache,Azure,Asp.net Web Api,Redis,Stackexchange.redis,Azure Redis Cache,我使用Azure Redis和StackExchange.Redis来提供类似Twitter的新闻提要。这正发生在我身上: 我将代码发布到我的云服务,一切都很好,页面在不到300毫秒的时间内加载了60个提要项,这对我来说太棒了。这会持续一段时间,比如说几个小时,然后提要页面的加载速度会降低到8000毫秒左右 奇怪的是,当我在本地主机上测试相同的代码时,速度始终在500毫秒左右。我连接到了同一个Redis实例,它在美国,我在欧洲(云服务和Redis在同一个Azure地区——美国东部) 通过Azue

我使用Azure Redis和StackExchange.Redis来提供类似Twitter的新闻提要。这正发生在我身上:

我将代码发布到我的云服务,一切都很好,页面在不到300毫秒的时间内加载了60个提要项,这对我来说太棒了。这会持续一段时间,比如说几个小时,然后提要页面的加载速度会降低到8000毫秒左右

奇怪的是,当我在本地主机上测试相同的代码时,速度始终在500毫秒左右。我连接到了同一个Redis实例,它在美国,我在欧洲(云服务和Redis在同一个Azure地区——美国东部)

通过Azue portal,我可以看到Redis服务器负载始终低于10%,CPU使用率低于40%。由于这一点以及localhost上的良好速度负载,我相信Redis没有任何问题,而且显然我在代码中做了一些愚蠢的事情,我看不到,因此我的代码如下:

以下是我如何初始化与Redis的连接:

  public static class AzureRedisFeedsConnectionMultiplexer
{
    private static readonly Lazy<ConnectionMultiplexer> LazyConnection =
       new Lazy<ConnectionMultiplexer>(
           () =>
           {
               var config = new ConfigurationOptions
               {
                   AbortOnConnectFail = false,
                   Password = password,
                   EndPoints = { "myEndpoint" },
                   ConnectRetry = 5,
                   ConnectTimeout = 2 * 60 * 1000,
                   Ssl = true
               };

               return ConnectionMultiplexer.Connect(config);
           });

    private static ConnectionMultiplexer Connection
    {
        get { return LazyConnection.Value; }
    }

    public static ConnectionMultiplexer GetRedisConnection()
    {
        return Connection;
    }

    public static IDatabase GetRedisDatabase()
    {
        return Connection.GetDatabase();
    }
}
公共静态类AzureRedisFeedsConnectionMultiplexer
{
私有静态只读懒连接=
新懒汉(
() =>
{
var config=新配置选项
{
AbortOnConnectFail=false,
密码=密码,
端点={“myEndpoint”},
ConnectRetry=5,
连接超时=2*60*1000,
Ssl=true
};
返回ConnectionMultiplexer.Connect(配置);
});
专用静态连接多路复用器连接
{
获取{return LazyConnection.Value;}
}
公共静态连接多路复用器GetRedisConnection()
{
回路连接;
}
公共静态IDatabase GetRedisDatabase()
{
返回Connection.GetDatabase();
}
}
下面是API调用(调用我的FeedService):

公共异步任务GetFeedForAllUsers(int-page、int-pageSize、int-skip、int-take)
{
返回
等待
_feedService.GetFeedWorkoutsFromRedisAsync(AzureRedisFeedsConnectionMultiplexer.GetRedisDatabase(),
User.Identity.GetUserId(),(第1页)*pageSize,pageSize-1);
}
以下是FeedService中的此方法:

  public async Task<List<FeedMobileHelper>> GetFeedForAllUsers(int page, int pageSize, int skip, int take)
    {
        return
            await
                _feedService.GetFeedWorkoutsFromRedisAsync(AzureRedisFeedsConnectionMultiplexer.GetRedisDatabase(),
                    User.Identity.GetUserId(), (page - 1)*pageSize, pageSize - 1);
    }
public async Task<List<FeedMobileHelper>> GetFeedWorkoutsFromRedisAsync(IDatabase redis, string userId, int numOfItemsToSkip, int numOfItemsToTake)
    {

        var redisFeed = await redis.ListRangeAsync("FeedAllWorkouts", numOfItemsToSkip, numOfItemsToSkip + numOfItemsToTake);

        /* WE KNOW FOR SURE TAHT THERE IS 10.000  ELEMENTS IN FEED SOTRED IN REDIS*/
        //so if there is request for more (i.e. already gotten (numOfItemsToSkip) +  numOfItemsToTake > 10.000 go to SQL

        if (numOfItemsToSkip + numOfItemsToTake > 10000)
        {
            //some items arealready fetched from redis, so we have to skip those
            var numOfItemsToGet = numOfItemsToSkip + numOfItemsToTake - 10000;
            return await GetFeedWorkoutsMobileAsync(numOfItemsToSkip, numOfItemsToGet, userId);
        }

        // if length is zero go to SQL
        if (redisFeed.Length <= 0)
        {
            return await GetFeedWorkoutsMobileAsync(numOfItemsToSkip, numOfItemsToSkip, userId);
        }

        return await CreateRedisFeedViewModelAsync(redisFeed, redis, userId);

    }
公共异步任务GetFeedWorkoutsFromRedisAsync(IDatabase redis,字符串userId,int numOfItemsToSkip,int numOfItemsToTake)
{
var redisFeed=wait redis.listRangeAync(“FeedAllWorkouts”,numOfItemsToSkip,numOfItemsToSkip+numOfItemsToTake);
/*我们可以肯定地知道,REDIS的FEED中有10000个元素*/
//因此,如果请求更多(即已获取(numOfItemsToSkip)+numOfItemsToTake>10.000,请转到SQL
如果(numOfItemsToSkip+numOfItemsToTake>10000)
{
//有些项目已经从redis获取,因此我们必须跳过这些项目
var numOfItemsToGet=numOfItemsToSkip+numOfItemsToTake-10000;
返回等待GetFeedWorkoutsMobileAsync(numOfItemsToSkip,numOfItemsToGet,userId);
}
//如果长度为零,则转到SQL
如果(redisFeed.Length r.TreningId==workoutGuid&&r.UserId==UserId)!=null;
}
管柱长度;
如果(锻炼长度>=3600)
{
var t=从秒开始的时间跨度(训练长度);
workoutLength=$“{t.Hours:D2}:{t.Minutes:D2}:{t.Seconds:D2}”;
}
其他的
{
var t=从秒开始的时间跨度(训练长度);
workoutLength=$“{t.Minutes:D2}:{t.Seconds:D2}”;
}
listToReturn.Add(新的FeedMobileHelper
{
Id=feedDeserialized[i]。Id.ToString(),
UserId=workout.UserId,
WorkUtid=feedDeserialized[i]。WorkUtid,
积分=训练。积分。ToString(“N0”,新编号格式信息
{
numbergroupsize=new[]{3},
NumberGroupSeparator=“”
}),
WorkoutName=锻炼。名称,
修井长度=修井长度,
NumberOfAspects=锻炼。NumberOfAspects,
NumberOfComments=训练。NumberOfComments,
WorkoutComment=WorkoutComment,
尊敬的,尊敬的,
UserImageUrl=profilePic,
用户名=用户名,
DisplayName=string.IsNullOrWhiteSpace(全名)?用户名:全名,
时间戳=训练。完成时的日期,
DateFormatted=workout.DateWhenFinished.FormattDateTohrsDaysWeeksString()
});
}
}
返回列表返回;
}
我相信这种方法存在问题,但我无法确定:

public async Task<RedisFeedDataModel> GetDataForFeed(IDatabase redisDb, string userId, string[] workoutIds, string[] userIds)
    {
        var listOfUsers = new Task<HashEntry[]>[userIds.Length];
        var workoutsToReturn = new List<RedisValue>();
        var usersToReturn = new List<Dictionary<RedisValue, RedisValue>>();
        var commentsToReturn = new List<RedisValue>();
        var listOfTaks = new List<Task<RedisValue>>();


        for (var i = 0; i < userIds.Length; i++)
        {
            listOfTaks.Add(redisDb.StringGetAsync("workout:" + workoutIds[i]));
            listOfTaks.Add(redisDb.StringGetAsync("workoutComment:" + workoutIds[i]));
            listOfUsers[i] = redisDb.HashGetAllAsync("user:" + userIds[i]);
        }

        var resultForListOfTasks =  await Task.WhenAll(listOfTaks);
        var resultForListOfUsers = await Task.WhenAll(listOfUsers);

        for (var i = 0; i < resultForListOfTasks.Length; i += 2)
        {
            workoutsToReturn.Add(resultForListOfTasks[i]);
            commentsToReturn.Add( resultForListOfTasks[i + 1]);
        }

        for (int i = 0; i < resultForListOfUsers.Length; i++)
        {

            var redisUser = resultForListOfUsers[i];
            var userToReturn = redisUser.Length > 0 ? redisUser.ToDictionary(t => t.Name, t => t.Value) : null;
            usersToReturn.Add(userToReturn);
        }


        return new RedisFeedDataModel
        {
            Comments = commentsToReturn,
            Workouts = workoutsToReturn,
            Users = usersToReturn

        };

    }
public异步任务GetDataForFeed(IDatabase redisDb,字符串userId,字符串[]workUtids,字符串[]userId)
{
var listOfUsers=新任务[userid.Length];
var workoutsToReturn=新列表();
var usersToReturn=new List();
var commentsToReturn=新列表();
var listOfTaks=新列表();
for(var i=0;ipublic async Task<RedisFeedDataModel> GetDataForFeed(IDatabase redisDb, string userId, string[] workoutIds, string[] userIds)
    {
        var listOfUsers = new Task<HashEntry[]>[userIds.Length];
        var workoutsToReturn = new List<RedisValue>();
        var usersToReturn = new List<Dictionary<RedisValue, RedisValue>>();
        var commentsToReturn = new List<RedisValue>();
        var listOfTaks = new List<Task<RedisValue>>();


        for (var i = 0; i < userIds.Length; i++)
        {
            listOfTaks.Add(redisDb.StringGetAsync("workout:" + workoutIds[i]));
            listOfTaks.Add(redisDb.StringGetAsync("workoutComment:" + workoutIds[i]));
            listOfUsers[i] = redisDb.HashGetAllAsync("user:" + userIds[i]);
        }

        var resultForListOfTasks =  await Task.WhenAll(listOfTaks);
        var resultForListOfUsers = await Task.WhenAll(listOfUsers);

        for (var i = 0; i < resultForListOfTasks.Length; i += 2)
        {
            workoutsToReturn.Add(resultForListOfTasks[i]);
            commentsToReturn.Add( resultForListOfTasks[i + 1]);
        }

        for (int i = 0; i < resultForListOfUsers.Length; i++)
        {

            var redisUser = resultForListOfUsers[i];
            var userToReturn = redisUser.Length > 0 ? redisUser.ToDictionary(t => t.Name, t => t.Value) : null;
            usersToReturn.Add(userToReturn);
        }


        return new RedisFeedDataModel
        {
            Comments = commentsToReturn,
            Workouts = workoutsToReturn,
            Users = usersToReturn

        };

    }