亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

連接redis的超時間一般設置多少?

連接redis的超時間一般設置多少?

蝴蝶不菲 2018-11-15 19:14:22
連接redis的超時間一般設置多少
查看完整描述

1 回答

?
侃侃無極

TA貢獻2051條經驗 獲得超10個贊

Redis在分布式應用中占據著越來越重要的地位,短短的幾萬行代碼,實現了一個高性能的數據存儲服務。最近dump中心的cm8集群出現過幾次redis超時的情況,但是查看redis機器的相關內存都沒有發現內存不夠,或者內存發生交換的情況,查看redis源碼之后,發現在某些情況下redis會出現超時的狀況,相關細節如下。
1. 網絡。Redis的處理與網絡息息相關,如果網絡出現閃斷則容易發生redis超時的狀況。如果出現這種狀況首先應查看redis機器網絡帶寬信息,判斷是否有閃斷情況發生。
2. 內存。redis所有的數據都放在內存里,當物理內存不夠時,linux os會使用swap內存,導致內存交換發生,這時如果有redis調用命令就會產生redis超時。這里可以通過調整/proc/sys/vm/swappiness參數,來設置物理內存使用超過多少就會進行swap。
int rdbSaveBackground(char *filename) { pid_t childpid; long long start; if (server.rdb_child_pid != -1) return REDIS_ERR; serverserver.dirty_before_bgsave = server.dirty; server.lastbgsave_try = time(NULL); start = ustime(); if ((childpid = fork()) == 0) { int retval; /* Child */ if (server.ipfd > 0) close(server.ipfd); if (server.sofd > 0) close(server.sofd); retval = rdbSave(filename); if (retval == REDIS_OK) { size_t private_dirty = zmalloc_get_private_dirty(); if (private_dirty) { redisLog(REDIS_NOTICE, "RDB: %zu MB of memory used by copy-on-write", private_dirty/(1024*1024)); } } exitFromChild((retval == REDIS_OK) ? 0 : 1); } else { /* Parent */ server.stat_fork_time = ustime()-start; if (childpid == -1) { server.lastbgsave_status = REDIS_ERR; redisLog(REDIS_WARNING,"Can't save in background: fork: %s", strerror(errno)); return REDIS_ERR; } redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid); server.rdb_save_time_start = time(NULL); server.rdb_child_pid = childpid; updateDictResizePolicy(); return REDIS_OK; } return REDIS_OK; /* unreached */ }

程序1
另外還有一些特殊情況也會導致swap發生。當我們使用rdb做為redis集群持久化時可能會發生物理內存不夠的情況(aof持久化只是保持支持不斷的追加redis集群變化操作,不太容易引起swap)。當使用rdb持久化時,如程序1所示主進程會fork一個子進程去dump redis中所有的數據,主進程依然為客戶端服務。此時主進程和子進程共享同一塊內存區域, linux內核采用寫時復制來保證數據的安全性。在這種模式下如果客戶端發來寫請求,內核將該頁賦值到一個新的頁面上并標記為寫,在將寫請求寫入該頁面。因此,在rdb持久化時,如果有其他請求,那么redis會使用更多的內存,更容易發生swap,因此在可以快速恢復的場景下盡量少使用rdb持久化可以將rdb dump的條件設的苛刻一點,當然也可以選擇aof,但是aof也有他自身的缺點。另外也可以使用2.6以后的主從結構,將讀寫分離,這樣不會出現server進程上又讀又寫的情景發生 3. Redis單進程處理命令。Redis支持udp和tcp兩種連接,redis客戶端向redis服務器發送包含redis命令的信息,redis服務器收到信息后解析命令后執行相應的操作,redis處理命令是串行的具體流程如下。首先服務端建立連接如程序2所示,在創建socket,bind,listen后返回文件描述符

server.ipfd = anetTcpServer(server.neterr,server.port,server.bindaddr);

程序2
對于redis這種服務來說,它需要處理成千上萬個連接(最高達到655350),需要使用多路復用來處理多個連接。這里redis提供了epoll,select, kqueue來實現,這里在默認使用epoll(ae.c)。拿到listen函數返回的文件描述符fd后,redis將fd和其處理acceptTcpHandler函數加入到事件驅動的鏈表中.實際上在加入事件隊列中,程序4事件驅動程序將套接字相關的fd文件描述符加入到epoll的監聽事件中。
if (server.ipfd > 0 && aeCreateFileEvent(server.el,server.ipfd,AE_READABLE, acceptTcpHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.ipfd file event."); int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData) { if (fd >= eventLoop->setsize) { errno = ERANGE; return AE_ERR; } aeFileEvent *fe = &eventLoop->events[fd]; if (aeApiAddEvent(eventLoop, fd, mask) == -1) return AE_ERR; fe->mask |= mask; if (mask & AE_READABLE) fe->rfileProc = proc; if (mask & AE_WRITABLE) fe->wfileProc = proc; fe->clientDataclientData = clientData; if (fd > eventLoop->maxfd) eventLoop->maxfd = fd; return AE_OK; }

程序3

static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { aeApiState *state = eventLoop->apidata; struct epoll_event ee; /* If the fd was already monitored for some event, we need a MOD * operation. Otherwise we need an ADD operation. */ int op = eventLoop->events[fd].mask == AE_NONE ? EPOLL_CTL_ADD : EPOLL_CTL_MOD; ee.events = 0; mask |= eventLoop->events[fd].mask; /* Merge old events */ if (mask & AE_READABLE) ee.events |= EPOLLIN; if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; ee.data.u64 = 0; /* avoid valgrind warning */ ee.data.fd = fd; if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1; return 0; }

程序4
在初始話完所有事件驅動后,如程序5所示主進程根據numevents = aeApiPoll(eventLoop, tvp)獲得io就緒的文件描述符和其對應的處理程序,并對fd進行處理。大致流程是accept()->createclient()->readQueryFromClient()。其中readQueryFromClient()讀取信息中的redis命令-> processInputBuffer()->call()最后完成命令。
void aeMain(aeEventLoop *eventLoop) { eventLoop->stop = 0; while (!eventLoop->stop) { if (eventLoop->beforesleep != NULL) eventLoop->beforesleep(eventLoop); aeProcessEvents(eventLoop, AE_ALL_EVENTS); } } int aeProcessEvents(aeEventLoop *eventLoop, int flags) {------------------------------- numevents = aeApiPoll(eventLoop, tvp); for (j = 0; j < numevents; j++) { aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; int mask = eventLoop->fired[j].mask; int fd = eventLoop->fired[j].fd; int rfired = 0; /* note the fe->mask & mask & ... code: maybe an already processed * event removed an element that fired and we still didn't * processed, so we check if the event is still valid. */ if (fe->mask & mask & AE_READABLE) { rfired = 1; fe->rfileProc(eventLoop,fd,fe->clientData,mask); } if (fe->mask & mask & AE_WRITABLE) { if (!rfired || fe->wfileProc != fe->rfileProc) fe->wfileProc(eventLoop,fd,fe->clientData,mask); } processed++; } }

程序5
從上述代碼可以看出redis利用ae事件驅動結合epoll多路復用實現了串行式的命令處理。所以一些慢命令例如sort,hgetall,union,mget都會使得單命令處理時間較長,容易引起后續命令time out.所以我們第一需要從業務上盡量避免使用慢命令,如將hash格式改為kv自行解析,第二增加redis實例個數,每個redis服務器調用盡量少的慢命令。



查看完整回答
反對 回復 2018-12-13
  • 慕仙1425852
    慕仙1425852
    人家是問redis的expire超時時間設置多少最合適,兼顧各級緩存、數據臟讀、性能等多方面考慮。你這回到牛頭不對馬嘴!建議看項目需求,熱點數據,對臟讀要求不高的,可以設置長一點,比如1小時或者30分鐘。
  • 1 回答
  • 0 關注
  • 5284 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號