Yang pertama ialah mendaftarkan pemproses; sambungan didengari ;
Kemudian Goroutine akan menunggu dalam gelung untuk menerima data permintaan, dan kemudian memadankan pemproses yang sepadan dalam jadual penghalaan pemproses mengikut alamat yang diminta, dan kemudian serahkan permintaan kepada pemproses untuk diproses ;
yang dinyatakan dalam kod adalah seperti ini:
func (srv *Server) Serve(l net.Listener) error { ... baseCtx := context.Background() ctx := context.WithValue(baseCtx, ServerContextKey, srv) for { // 接收 listener 过来的网络连接 rw, err := l.Accept() ... tempDelay = 0 c := srv.newConn(rw) c.setState(c.rwc, StateNew) // 创建协程处理连接 go c.serve(connCtx) } }
Contohnya: terima sepadan dengan pengendali acara acceptTCPHandler, baca & tulis sepadan dengan pengendali acara readQueryFromClient, dsb., dan kemudian acara itu diperuntukkan kepada pengendali acara untuk diproses melalui penghantaran gelung acara.
Jadi mod Reaktor di atas dilaksanakan melalui epoll Untuk epoll, terdapat tiga kaedah:
//创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大 int epoll_create(int size); /* * 可以理解为,增删改 fd 需要监听的事件 * epfd 是 epoll_create() 创建的句柄。 * op 表示 增删改 * epoll_event 表示需要监听的事件,Redis 只用到了可读,可写,错误,挂断 四个状态 */ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); /* * 可以理解为查询符合条件的事件 * epfd 是 epoll_create() 创建的句柄。 * epoll_event 用来存放从内核得到事件的集合 * maxevents 获取的最大事件数 * timeout 等待超时时间 */ int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
Jadi kita boleh melaksanakan kaedah mudah berdasarkan tiga kaedah Pelayan:
// 创建监听 int listenfd = ::socket(); // 绑定ip和端口 int r = ::bind(); // 创建 epoll 实例 int epollfd = epoll_create(xxx); // 添加epoll要监听的事件类型 int r = epoll_ctl(..., listenfd, ...); struct epoll_event* alive_events = static_cast<epoll_event*>(calloc(kMaxEvents, sizeof(epoll_event))); while (true) { // 等待事件 int num = epoll_wait(epollfd, alive_events, kMaxEvents, kEpollWaitTime); // 遍历事件,并进行事件处理 for (int i = 0; i < num; ++i) { int fd = alive_events[i].data.fd; // 获取事件 int events = alive_events[i].events; // 进行事件的分发 if ( (events & EPOLLERR) || (events & EPOLLHUP) ) { ... } else if (events & EPOLLRDHUP) { ... } ... } }
Proses panggilan #
Jadi mengikut pengenalan di atas, anda boleh tahu bahawa untuk Redis, gelung acara tidak lebih daripada beberapa langkah:
Daftar fungsi mendengar acara dan panggilan balik;
Gelung untuk menunggu acara diperoleh dan diproses;
Tulis data kembali kepada Pelanggan
Apabila acara rangkaian datang, fungsi panggil balik acceptTcpHandler akan dipanggil sepenuhnya untuk readQueryFromClient untuk pemprosesan data akan menghuraikan data pelanggan dan mencari fungsi cmd yang sepadan. bukannya kembali serta-merta;
Keseluruhan acara di atas Sebenarnya, langkah kod proses gelung telah ditulis dengan sangat jelas, dan terdapat banyak artikel di Internet mengenainya, jadi saya tidak akan menerangkan secara terperinci.Kami juga menyebut dalam bahagian sebelumnya bahawa jika acara rangkaian datang, fungsi readQueryFromClient akan dipanggil, di mana arahan itu sebenarnya dilaksanakan. Kami hanya mengikut kaedah ini dan melihat ke bawah:
readQueryFromClient akan memanggil fungsi processInputBufferAndReplicate untuk memproses arahan yang diminta
dalam fungsi processInputBufferAndReplicate It; akan memanggil processInputBuffer dan menentukan sama ada arahan itu perlu disalin ke nod lain jika ia adalah mod kluster
fungsi processInputBuffer akan menggelung melalui arahan yang diminta dan memanggilnya mengikut protokol yang diminta processInlineBuffer; fungsi, selepas memanggil objek redisObject, processCommand dipanggil untuk melaksanakan perintah itu; arahan, dan kemudian pergi melalui siri pengesahan, panggil fungsi yang sepadan untuk melaksanakan arahan, dan panggil addReply untuk menulis data yang dikembalikan ke dalam penimbal output klien; 🎜> akan menambah semua data dalam fungsi populateCommandTable Arahan Redis didaftarkan sebagai jadual yang memperoleh fungsi arahan berdasarkan nama arahan.
void getCommand(client *c) { getGenericCommand(c); } int getGenericCommand(client *c) { robj *o; // 查找数据 if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL) return C_OK; ... } robj *lookupKeyReadOrReply(client *c, robj *key, robj *reply) { //到db中查找数据 robj *o = lookupKeyRead(c->db, key); // 写入到缓存中 if (!o) addReply(c,reply); return o; }
Klien tulis balik data #
Selepas menulis arahan ke dalam penimbal, data perlu dikeluarkan daripada penimbal dan dikembalikan kepada klien. Untuk proses menulis data kembali kepada klien, ia sebenarnya telah selesai dalam gelung acara pelayan.
Pertama, Redis akan memanggil fungsi aeSetBeforeSleepProc dalam fungsi utama untuk mendaftarkan fungsi beforeSleep bagi pakej tulis balik ke dalam eventLoop; >
Kemudian apabila Redis memanggil fungsi aeMain untuk gelung acara, ia akan menentukan sama ada beforesleep telah ditetapkan. Pergi ke fungsi handleClientsWithPendingWrites, yang memanggil writeToClient untuk menulis kembali data kepada klien daripada penimbal.Atas ialah kandungan terperinci Apakah proses pemprosesan permintaan Redis?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!