100%CPU时如何提高Redis性能?拆分?最快的.Net客户端?

时间:2014-06-19 22:23:12

标签: performance redis sharding servicestack.redis stackexchange.redis

由于我们网站上的负载增加,redis现在正在努力应对峰值负载,因为redis服务器实例达到100%CPU(在八个核心之一上)导致超时。

我们已将客户端软件更新为ServiceStack V3(来自BookSleeve 1.1.0.4),并将redis服务器升级到2.8.11(来自2.4.x)。由于存在使用ServiceStack.Redis的Harbour.RedisSessionStateStore,我选择了ServiceStack。我们之前使用过AngiesList.Redis和BookSleeve,但我们也经历了100%。

我们将8台redis服务器配置为主/从树。用于会话状态的单个服务器。其他用于数据缓存。一个主站,两个主站/从站分别连接到两个从站。

当服务器开始被100%CPU阻塞时,它们在峰值时可以容纳大约600个客户端连接。

我们可以做些什么来提高绩效?

Sharding和/或StackExchange Redis客户端(根据我的知识,没有可用的会话状态客户端......)。

或者它可能是别的吗?会话服务器也达到100%,并且没有连接到任何其他服务器(数据和网络吞吐量很低)。


更新1:分析redis-cli INFO

这是运行Redis 2.8一夜之后INFO命令的输出。

# Server
redis_version:2.8.11
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:7a57b118eb75b37f
redis_mode:standalone
os:Linux 2.6.32-431.11.2.el6.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.7
process_id:5843
run_id:d5bb838857d61a9673e36e5bf608fad5a588ac5c
tcp_port:6379
uptime_in_seconds:152778
uptime_in_days:1
hz:10
lru_clock:10765770
config_file:/etc/redis/6379.conf

# Clients
connected_clients:299
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:80266784
used_memory_human:76.55M
used_memory_rss:80719872
used_memory_peak:1079667208
used_memory_peak_human:1.01G
used_memory_lua:33792
mem_fragmentation_ratio:1.01
mem_allocator:jemalloc-3.2.0

# Persistence
loading:0
rdb_changes_since_last_save:70245
rdb_bgsave_in_progress:0
rdb_last_save_time:1403274022
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok

# Stats
total_connections_received:3375
total_commands_processed:30975281
instantaneous_ops_per_sec:163
rejected_connections:0
sync_full:10
sync_partial_ok:0
sync_partial_err:5
expired_keys:8059370
evicted_keys:0
keyspace_hits:97513
keyspace_misses:46044
pubsub_channels:2
pubsub_patterns:0
latest_fork_usec:22040

# Replication
role:master
connected_slaves:2
slave0:ip=xxx.xxx.xxx.xxx,port=6379,state=online,offset=272643782764,lag=1
slave1:ip=xxx.xxx.xxx.xxx,port=6379,state=online,offset=272643784216,lag=1
master_repl_offset:272643811961
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:272642763386
repl_backlog_histlen:1048576

# CPU
used_cpu_sys:20774.19
used_cpu_user:2458.50
used_cpu_sys_children:304.17
used_cpu_user_children:1446.23

# Keyspace
db0:keys=77863,expires=77863,avg_ttl=3181732
db6:keys=11855,expires=11855,avg_ttl=3126767

更新2:twemproxy(Sharding)

我发现了一个名为twemproxy的有趣组件。据我所知,这个组件可以跨多个redis实例进行Shard。

这有助于缓解CPU吗?

它可以为我们节省大量的编程时间,但是仍然需要花费一些精力在每台服务器上配置3个额外的实例。所以我希望有人能在我们投入工作之前确认或揭穿这个解决方案。

3 个答案:

答案 0 :(得分:3)

我的第一个简单的建议是,如果你还没有这样做,至少要关闭你主人的所有RDB或AOF备份。当然,如果他们仍然保存到磁盘,你的奴隶可能会落后。有关RDB转储成本的概念,请参阅this

要做的另一件事是确保您正在管道所有命令。如果您单独发送许多可以分组到管道中的命令,您应该会看到性能上升。

此外,this SO post对分析Redis

有一个很好的答案

有关您的用例的更多信息,数据结构将有助于确定您是否可以对实际使用Redis的方式进行简单的更改,从而为您提供改进。

编辑:为了回应您的最新评论,请注意每次有奴隶丢失连接并重新连接时,它都会与主设备重新同步。在Redis的早期版本中,这总是完全重新同步,所以它非常昂贵。显然在2.8中,从设备现在能够请求部分重新同步它自从断开连接后丢失的数据。我对细节了解不多,但如果您的主人或任何奴隶不在2.8。*并且您有一个不稳定的连接,这可能会通过不断强迫您的主人重新同步来真正损害您的CPU性能奴隶。更多信息Here

答案 1 :(得分:3)

我们在申请中发现了一个问题。通过redis频道订阅实现了关于缓存中更新数据到本地内存缓存的通信。

每次刷新本地缓存时,项目已过期或项目已更新,消息已发送给所有(35)网络服务器,而这些服务器又开始更新更多项目等等。

禁用更新密钥的消息可将我们的情况提高10倍。

网络带宽从1.2 Gbps降至200 Mbps,CPU利用率为40%,这是我们在极端计算和更新时刻所承受的负载的150%。

答案 2 :(得分:2)

要做的第一件事就是查看slowlog get 50(或选择任意数量的行) - 这会显示最后50个命令,这些命令花费了大量的时间。可能你正在做的一些事情只是花了太长时间。如果我在slowlog中看到任何,我会感到担心 - 我通常会每隔几天看到一些项目。如果您经常 ,那么:您需要调查您在服务器上实际正在做什么。永远不要做的一件事是keys,但还有其他事情。

接下来要做的是:缓存。在它们到达后端之前被短路的请求是免费的。我们广泛使用redis,但这并不意味着我们也忽略了本地内存。