精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

用C語言擼了個DBProxy

開發(fā) 后端
筆者在閱讀了一大堆源碼后,就會情不自禁產(chǎn)生造輪子的想法。于是花了數(shù)個周末的時間用C語言擼了一個DBProxy(MySQL協(xié)議)。在筆者的github中給這個DBProxy起名為Hero。

[[341464]]

前言

筆者在閱讀了一大堆源碼后,就會情不自禁產(chǎn)生造輪子的想法。于是花了數(shù)個周末的時間用C語言擼了一個DBProxy(MySQL協(xié)議)。在筆者的github中給這個DBProxy起名為Hero。

為什么采用C語言

筆者一直有C情節(jié),求學(xué)時候一直玩C。工作之后,一直使用Java,就把C漸漸放下了。在筆者最近一年閱讀了一堆關(guān)于linux Kernel(C)和MySQL(C++)的源碼后,就萌生了重拾C的想法。同時用純C的話,勢必要從基礎(chǔ)開始造一大堆輪子,這也符合筆者當(dāng)時造輪子的心境。

造了哪些輪子

習(xí)慣了Java的各種好用的類庫框架之后,用純C無疑就是找虐。不過,既然做了這個決定,跪著也得搞完。在寫Hero的過程中。很大一部分時間就是在搭建基礎(chǔ)工具,例如:

  • Reactor模型
  • 內(nèi)存池
  • packet_buffer
  • 協(xié)議分包處理
  • 連接池
  • ......

下面在這篇博客里面一一道來

DBProxy的整體原理

Hero(DBProxy)其實就是自己偽裝成MySQL,接收到應(yīng)用發(fā)過來的SQL命令后,再轉(zhuǎn)發(fā)到后端。如下圖所示:

 

由于Hero在解析SQL的時候,可以獲取各種信息,例如事務(wù)這個信息就可以通過set auto_commit和begin等命令存在連接狀態(tài)里面,再根據(jù)解析出來的SQL判斷其是否需要走主庫。這樣就可以對應(yīng)用透明的進行主從分離以至于分庫分表等操作。

當(dāng)然了,筆者現(xiàn)在的Hero剛把基礎(chǔ)的功能搭建好(協(xié)議、連接池等),對連接狀態(tài)還沒有做進一步的處理。

Reactor模式

Hero的網(wǎng)絡(luò)模型采用了Reactor模式,而且是多線程模型,同時采用epoll的水平觸發(fā)。

采用多線程模型

為什么采用多線程,純粹是為了編寫代碼簡單。多進程的話,還得考慮worker進程間負(fù)載均衡問題,例如nginx就在某個worker進程達(dá)到7/8最大連接數(shù)的時候拒絕獲取連接從而轉(zhuǎn)給其它worker。多線程的話,在accept線程里面通過取模選擇一個worker線程就可以輕松的達(dá)到簡單的負(fù)載均衡結(jié)果。

采用epoll水平觸發(fā)

為什么采用epoll的水平觸發(fā),純粹也是為了編寫代碼簡單。如果采用邊緣觸發(fā)的話,需要循環(huán)讀取直到read返回字節(jié)數(shù)為0為止。然而如果某個連接特別活躍,socket的數(shù)據(jù)一直讀不完,會造成其它連接饑餓,所以必須還得自己寫個均衡算法,在讀到一定程度后,去選擇其它連接。

Reactor

整體Reactor模型如下圖所示:

 

其實代碼是很簡單的,如下面代碼所示的就是reactor中的accept處理:

  1. // 中間省略了大量的錯誤處理 
  2. int init_reactor(int listen_fd,int worker_count){ 
  3.     // 注意,這邊需要是unsigned 防止出現(xiàn)負(fù)數(shù) 
  4.     unsigned int current_worker = 0; 
  5.     for(;;){ 
  6.         int numevents = 0; 
  7.         int retval = epoll_wait(reactor->master_fd,reactor->events,EPOLL_MAX_EVENTS,500); 
  8.         ...... 
  9.         for(j=0; j < numevents; j++){ 
  10.             client_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len)) 
  11.             poll_add_event(reactor->worker_fd_arrays[current_worker++%reactor->worker_count],conn->sockfd,EPOLLOUT,conn) 
  12.             ...... 
  13.          } 

上面代碼中,每來一個新的連接current_worker都自增,這樣取模后便可在連接層面上對worker線程進行負(fù)載均衡。

而worker線程則通過pthread去實現(xiàn),如下面代碼所示:

  1. // 這里的worker_count根據(jù)調(diào)用get_nprocs得到的對應(yīng)機器的CPU數(shù)量 
  2. // 注意,由于docker返回的是宿主機CPU數(shù)量,所以需要自行調(diào)整 
  3.     for(int i=0;i<worker_count;i++){ 
  4.         reactor->worker_fd_arrays[i] = epoll_create(EPOLL_MAX_EVENTS); 
  5.         if(reactor->worker_fd_arrays[i] == -1){ 
  6.            goto error_process; 
  7.         } 
  8.         // 通過pthread去創(chuàng)建worker線程 
  9.         if(FALSE == create_and_start_rw_thread(reactor->worker_fd_arrays[i],pool)){ 
  10.             goto error_process; 
  11.         } 
  12.     } 

而worker線程的處理也是按照標(biāo)準(zhǔn)的epoll水平觸發(fā)去處理的:

  1. static void* rw_thread_func(void* arg){ 
  2.     ...... 
  3.     for(;;){ 
  4.         int numevents = 0; 
  5.         int retval = epoll_wait(epfd,events,EPOLL_MAX_EVENTS,500); 
  6.         ...... 
  7.         for(j=0; j < numevents; j++){ 
  8.             if(event & EPOLLHUP){ 
  9.                 // 處理斷開事件 
  10.                 ...... 
  11.             }else if(event & EPOLLERR){ 
  12.                 // 處理錯誤事件 
  13.                 ...... 
  14.             } 
  15.  
  16.         }else { 
  17.             if(event & EPOLLIN){ 
  18.                 handle_ready_read_connection(conn); 
  19.                 continue
  20.             } 
  21.             if(event & EPOLLOUT){ 
  22.                 hanlde_ready_write_connection(conn); 
  23.                 continue
  24.             } 
  25.         } 
  26.     } 
  27.     ...... 

內(nèi)存池

為什么需要內(nèi)存池

事實上,筆者在最開始編寫的時候,是直接調(diào)用標(biāo)準(zhǔn)庫里面的malloc的。但寫著寫著,就發(fā)現(xiàn)一些非常坑的問題。例如我要在一個請求里面malloc數(shù)十個結(jié)構(gòu),同時每次malloc都有失敗的可能,那么我的代碼可能寫這樣。

  1. void do_something(){ 
  2.     void * a1 = (void*)malloc(sizeof(struct A)); 
  3.     if(a1 == NULL){ 
  4.         goto error_process; 
  5.     } 
  6.     ...... 
  7.     void * a10 = (void*)malloc(sizeof(struct A)); 
  8.     if(a10 == NULL
  9.         goto error_process; 
  10.     } 
  11. error_process: 
  12.     if(NULL != a1){ 
  13.         free(a1); 
  14.     } 
  15.     ...... 
  16.     if(NULL != a10){ 
  17.         free(a10); 
  18.     } 

寫著寫著,筆者就感覺完全不可控制了。尤其是在各種條件分支加進去之后,可能本身aN這個變量都還沒有被分配,那么就還不能用(NULL != aN),還得又一堆復(fù)雜的判斷。

有了內(nèi)存池之后,雖然依舊需要仔細(xì)判斷內(nèi)存池不夠的情況,但至少free的時候,只需要把內(nèi)存池整體給free掉即可,如下面代碼所示:

  1. void do_something(mem_pool* pool){ 
  2.     void * a1 = (void*)mem_pool_alloc(sizeof(struct A),pool); 
  3.     if(a1 == NULL){ 
  4.         goto error_process; 
  5.     } 
  6.     ...... 
  7.     void * a10 = (void*)mem_pool_alloc(sizeof(struct A),pool); 
  8.     if(a10 == NULL
  9.         goto error_process; 
  10.     } 
  11. error_process: 
  12.     // 直接一把全部釋放 
  13.     mem_pool_free(pool); 

內(nèi)存池的設(shè)計

為了編寫代碼簡單,筆者采用了比較簡單的設(shè)計,如下圖所示:

 

這種內(nèi)存池的好處就在于分配很多小對象的時候,不必一一去清理,直接連整個內(nèi)存池都重置即可。而且由于每次free的基本都是mem_block大小,所以產(chǎn)生的內(nèi)存碎片也少。不足之處就在于,一些可以被立即銷毀的對象只能在最后重置內(nèi)存池的時候才銷毀。但如果都是小對象的話,影響不大。

內(nèi)存池的分配優(yōu)化

考慮到內(nèi)存對齊,每次申請內(nèi)存的時候都按照sizeof(union hero_aligin)進行最小內(nèi)存分配。這是那本采用\<\>的推薦的對齊大小。

  1. 采用<<c interface and implemention>>的實現(xiàn) 
  2. union hero_align{ 
  3.     int i; 
  4.     long l; 
  5.     long *lp; 
  6.     void *p; 
  7.     void (*fp)(void); 
  8.     float f; 
  9.     double d; 
  10.     long double ld; 
  11. }; 

真正的對齊則是參照nginx的寫法:

  1. size = (size + sizeof(union hero_align) - 1) & (~(sizeof(union hero_align) - 1)); 

其實筆者一開始還打算做一下類似linux kernel SLAB緩存中的隨機著色機制,這樣能夠緩解false sharing問題,想想為了代碼簡單,還是算了。

為什么需要packet_buffer

packet_buffer是用來存儲從socket fd中讀取或?qū)懭氲臄?shù)據(jù)。

設(shè)計packet_buffer的初衷就是要重用內(nèi)存,因為一個連接反復(fù)的去獲取寫入數(shù)據(jù)總歸是需要內(nèi)存的,只在連接初始化的時候去分配一次內(nèi)存顯然是比反復(fù)分配再銷毀效率高。

為什么不直接用內(nèi)存池

上文中說到,銷毀內(nèi)存必須將池里面的整個數(shù)據(jù)重置。如果packet_buffer和其它的數(shù)據(jù)結(jié)構(gòu)在同一內(nèi)存池中分配,要重用它,那么在packet_buffer之前分配的數(shù)據(jù)就不能被清理。如下圖所示:

 

這樣顯然違背了筆者設(shè)計內(nèi)存池是為了釋放內(nèi)存方便的初衷。

另外,如果使用內(nèi)存池,那么從sockfd中讀取/寫入的數(shù)據(jù)就可能從連續(xù)的變成一個一個mem_block分離的數(shù)據(jù),這種不連續(xù)性對數(shù)據(jù)包的處理會特別麻煩。如下圖所示:

 

當(dāng)然了,這種非連續(xù)的分配方式,筆者曾經(jīng)在閱讀lwip協(xié)議時見過(幫某實時操作系統(tǒng)處理一個詭異的bug),lwip在嵌入式這種內(nèi)存稀缺的環(huán)境中使用這種方式從而盡量避免大內(nèi)存的分配。

所以筆者采取了在連接建立時刻一次性分配一個比較大的內(nèi)存來處理單個請求的數(shù)據(jù),如果這個內(nèi)存也滿足不了,則realloc(當(dāng)然了realloc也有坑,需要仔細(xì)編寫)。

packet_buffer結(jié)構(gòu)

 

packet_buffer這種動態(tài)改變大小而且地址上連續(xù)的結(jié)構(gòu)為處理包結(jié)構(gòu)提供了便利。

由于realloc的時候,packet_buffer->buffer本身指向的地址可能會變,所以盡量避免直接操作內(nèi)部buffer,非得使用內(nèi)部buffer的時候,不能將其賦予一個局部變量,否則buffer變化,局部變量可能指向了之前廢棄的buffer。

MySQL協(xié)議分包處理

MySQL協(xié)議基于tcp(當(dāng)然也有unix域協(xié)議,這里只考慮tcp)。同時Hero采用的是非阻塞IO模式,讀取包時,recv系統(tǒng)調(diào)用可能在包的任意比特位置上返回。這時候,就需要仔細(xì)的處理分包。

MySQL協(xié)議外層格式

MySQL協(xié)議是通過在幀頭部加上length field的設(shè)計來處理分包問題。如下圖所示:

 

Hero的處理

Hero對于length field采用狀態(tài)機進行處理,這也是通用的手法。首先讀取3byte+1byte的packet_length和sequenceId,然后再通過packet_length讀取剩下的body長度。如下圖所示:

 

連接池

Hero的連接池造的還比較粗糙,事實上就是一個數(shù)組,通過mutex鎖來控制并發(fā)的put/get

 

連接管理部分尚未開發(fā)。

MySQL協(xié)議格式處理

相較于前面的各種輪子,MySQL協(xié)議本身反倒顯得輕松許多,唯一復(fù)雜的地方在于握手階段的加解密過程,但是MySQL是開源的,筆者直接將MySQL本身對于握手加解密的代碼copy過來就行了。以下代碼copy自MySQL-5.1.59(密碼學(xué)太高深,這個輪子不造也罷):

  1. // 摘自MySQL-5.1.59,用作password的加解密 
  2. void scramble(char *to, const char *message, const char *password) { 
  3.   SHA1_CONTEXT sha1_context; 
  4.   uint8 hash_stage1[SHA1_HASH_SIZE]; 
  5.   uint8 hash_stage2[SHA1_HASH_SIZE]; 
  6.   mysql_sha1_reset(&sha1_context); 
  7.   /* stage 1: hash password */ 
  8.   mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password)); 
  9.   mysql_sha1_result(&sha1_context, hash_stage1); 
  10.   /* stage 2: hash stage 1; note that hash_stage2 is stored in the database */ 
  11.   mysql_sha1_reset(&sha1_context); 
  12.   mysql_sha1_input(&sha1_context, hash_stage1, SHA1_HASH_SIZE); 
  13.   mysql_sha1_result(&sha1_context, hash_stage2); 
  14.   /* create crypt string as sha1(message, hash_stage2) */; 
  15.   mysql_sha1_reset(&sha1_context); 
  16.   mysql_sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH); 
  17.   mysql_sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE); 
  18.   /* xor allows 'from' and 'to' overlap: lets take advantage of it */ 
  19.   mysql_sha1_result(&sha1_context, (uint8 *) to); 
  20.   my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH); 

剩下的無非就是按格式解釋包中的各個字段,然后再進行處理而已。典型代碼段如下:

  1. int handle_com_query(front_conn* front){ 
  2.     char* sql = read_string(front->conn->read_buffer,front->conn->request_pool); 
  3.     int rs = server_parse_sql(sql); 
  4.     switch(rs & 0xff){ 
  5.         case SHOW: 
  6.             return handle_show(front,sql,rs >> 8); 
  7.         case SELECT
  8.             return handle_select(front,sql,rs >> 8); 
  9.         case KILL_QUERY: 
  10.                 ...... 
  11.         default
  12.             return default_execute(front,sql,FALSE); 
  13.     } 
  14.     return TRUE

需要注意的是,hero在后端連接backend返回result_set結(jié)果集并拷貝到前端連接的write_buffer的時候,前端連接可能正在寫入,也會操縱write_buffer。所以在這種情況下要通過Mutex去保護write_buffer(packet_buffer)的內(nèi)部數(shù)據(jù)結(jié)構(gòu)。

性能對比

下面到了令人激動的性能對比環(huán)節(jié),筆者在一個4核8G的機器上用hero和另一個用java nio寫的成熟DBProxy做對比。兩者都是用show databases,這條sql并不會路由到后端的數(shù)據(jù)庫,而是純內(nèi)存返回。這樣筆者就能知道筆者自己造的reactor框架的性能如何,以下是對比情況:

  1. 用作對比的兩個server的代碼IO模型 
  2. hero(c):epoll 水平觸發(fā) 
  3. proxy(java):java nio(內(nèi)部也是epoll 水平觸發(fā)) 
  4. benchMark: 
  5. 服務(wù)器機器 
  6. 4核8G 
  7. CPU主屏2399.996MHZ 
  8. cache size:4096KB 
  9. 壓測機器: 
  10. 16核64G,jmeter 
  11. 同樣配置下,壓測同一個簡單的sql 
  12. hero(c):3.6Wtps/s 
  13. proxy(java):3.6Wtps/s 
  14. tps基本沒有差別,因為瓶頸是在網(wǎng)絡(luò)上 
  15. CPU消耗: 
  16. hero(c):10% cpu 
  17. proxy(java):15% cpu 
  18. 內(nèi)存消耗: 
  19. hero(c):0.2% * 8G 
  20. proxy(java):48.3% * 8G 
  21. 結(jié)論: 
  22. 對于IO瓶頸的情況,用java和C分別處理簡單的組幀/解幀邏輯,C語言帶來的微小收益并不能讓tps有顯著改善。 

Hero雖然在CPU和內(nèi)存消耗上有優(yōu)勢,但是限于網(wǎng)絡(luò)瓶頸,tps并沒有明顯提升-_-!

相比于造輪子時候付出的各種努力,投入產(chǎn)出比(至少在表面上)是遠(yuǎn)遠(yuǎn)不如用Netty這種非常成熟的框架的。如果是工作,那我會毫不猶豫的用后者。

總結(jié)

造輪子是個非常有意思的過程,在這個過程中能夠強迫筆者去思考平時根本無需思考的地方。

造輪子的過程也是非常艱辛的,造出來的輪子也不一定比現(xiàn)有的輪子靠譜。但造輪子的成就感還是滿滿的^_^

github鏈接

https://github.com/alchemystar/hero

碼云鏈接

 

https://gitee.com/alchemystar/hero

本文轉(zhuǎn)載自微信公眾號「解Bug之路」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系解Bug之路公眾號。

 

責(zé)任編輯:武曉燕 來源: 解Bug之路
相關(guān)推薦

2022-04-22 08:22:50

MVCCMySQLC++

2020-05-28 11:00:40

Flutter代碼框架

2021-12-12 18:18:15

代碼元宇宙Python

2019-06-25 10:46:04

Flutter開發(fā)APP

2020-02-17 13:45:27

抓取代碼工具

2020-11-04 07:56:19

工具Linux 翻譯

2023-12-07 12:59:46

C語言循環(huán)隊列代碼

2021-02-03 07:56:08

版本游戲邏輯

2021-04-27 07:52:19

StarterSpring Boot配置

2019-12-06 10:59:21

編程語言C語言開 發(fā)

2022-01-21 07:35:06

LRU緩存java

2021-11-04 17:23:03

Java對象 immutable

2021-11-29 07:47:57

gRPCGUI客戶端

2022-05-07 13:52:22

Feign 增強包K8s

2021-05-24 06:40:59

C語言Linux軟件庫

2011-07-20 16:23:14

C++

2020-10-13 16:30:31

語言鏈表數(shù)組

2020-08-14 10:01:25

編程神經(jīng)網(wǎng)絡(luò)C語言

2021-10-18 09:09:16

數(shù)據(jù)庫

2022-10-08 08:15:55

GScriptGo 語言
點贊
收藏

51CTO技術(shù)棧公眾號

午夜久久av| 在线观看欧美亚洲| 国产精品沙发午睡系列| 天天综合久久综合| 国内精品国产成人国产三级粉色| 国产亚洲婷婷免费| 午夜免费在线观看精品视频| 日韩精品一区二区三区色偷偷 | 国产精品99精品| 成人午夜毛片| 国产丝袜欧美中文另类| 国产在线观看不卡| 国产高潮呻吟久久| 男人av在线播放| 国产尤物一区二区| 中文字幕亚洲天堂| 妞干网在线免费视频| 日韩在线视频观看免费| 欧美激情91| 欧美一区中文字幕| 亚洲免费不卡| 中文字幕自拍偷拍| 第一sis亚洲原创| 在线视频国内一区二区| 久热这里只精品99re8久 | 亚洲色图视频网站| 成人h视频在线观看播放| 69精品无码成人久久久久久| 日韩电影av| 久久久久久久久久电影| 欧美一级视频在线观看| 天天插天天射天天干| 9765激情中文在线| 日韩午夜高潮| 欧美不卡视频一区| av女优在线播放| 五月婷婷丁香网| 久久午夜av| 一区二区欧美亚洲| 亚洲高清免费在线观看| 免费黄网在线观看| 国产一区二区在线观看免费| 国产成人精品一区二区三区| 国产传媒视频在线| 蜜桃在线一区| 精品女厕一区二区三区| 久久久久久久久久久久久久久久av | 国产三级精品在线观看| 久久国产精品亚洲人一区二区三区 | jyzzz在线观看视频| 久久精品麻豆| 亚洲夜晚福利在线观看| 污视频网站观看| 日本免费久久| 色综合天天综合狠狠| 午夜精品一区二区在线观看| 国产精品久久免费| 国内精品久久久久久久97牛牛| 6080yy午夜一二三区久久| av在线免费观看国产| 亚洲 欧美 自拍偷拍| 成人免费av资源| 奇门遁甲1982国语版免费观看高清| av中文字幕免费观看| 在线免费成人| 婷婷久久综合九色综合伊人色| 日产精品一线二线三线芒果| 免费黄网站在线观看| 韩日精品视频一区| 57pao成人国产永久免费| 日韩和一区二区| 日韩欧美三级| 俺去了亚洲欧美日韩| 尤物网站在线观看| 美女视频一区| 欧美日韩国产一区二区三区| 天天夜碰日日摸日日澡性色av| 在线中文资源天堂| 成人性生交大合| 精品国产乱码久久久久久蜜柚| 中文字幕精品无码亚| 久久超级碰视频| 777国产偷窥盗摄精品视频| 亚洲少妇xxx| 天堂99x99es久久精品免费| 欧美日韩在线不卡| 欧美丰满熟妇bbbbbb百度| a级片国产精品自在拍在线播放| 26uuu国产日韩综合| 亚洲综合日韩在线| 97人妻精品视频一区| 亚洲毛片在线| 欧美日本高清视频| 极品尤物一区二区| 欧美国产综合| 全球成人中文在线| 国产一区二区三区中文字幕| 久久香蕉精品| 亚洲r级在线观看| 艳母动漫在线看| 1000部国产精品成人观看| 青娱乐国产91| 天堂av在线播放| 成人精品一区二区三区四区 | 久久久久久一区| 香蕉视频在线免费看| 91麻豆精品一区二区三区| 一区二区三区四区视频在线观看| 九色在线视频| 久久嫩草精品久久久久| 久草热久草热线频97精品| 国产中文字幕在线播放| 一区二区三区中文字幕精品精品| 日韩久久不卡| 爱情岛亚洲播放路线| 亚洲一区欧美一区| 国产1区2区3区中文字幕| 免费av在线播放| 精品毛片网大全| 国产精品中文久久久久久| 99视频这里有精品| 亚洲欧美精品在线| 亚洲区自拍偷拍| 激情视频一区| 久久人人爽国产| 制服.丝袜.亚洲.中文.综合懂色| 狠狠色丁香久久综合频道| 国产精品久久av| 亚洲视频中文字幕在线观看| 久久精品国产一区二区| 成人免费激情视频| 国产鲁鲁视频在线观看免费| 中文字幕精品一区二区三区精品| 一道精品一区二区三区| 成人影院大全| 欧美日韩视频不卡| 国产美女喷水视频| 成人看的视频| 51精品国产黑色丝袜高跟鞋| 动漫av一区二区三区| 99国产精品久| 神马影院我不卡| 成人免费看视频网站| 亚洲国产成人一区| 亚洲午夜精品久久久久久高潮| 亚洲国产网站| 国产伦精品一区二区三| 每日更新av在线播放| 亚洲成a人在线观看| 黄色影视在线观看| 免费一二一二在线视频| 精品99久久久久久| 亚洲av毛片基地| 欧美日韩一卡| 国产成人在线一区| 你懂的在线视频| 色婷婷av一区二区三区大白胸| www.cao超碰| 精品午夜电影| 最新91在线视频| 久久免费视频精品| 日韩福利视频网| 超碰国产精品久久国产精品99| 午夜在线视频免费| 一卡二卡欧美日韩| caoporn超碰97| 亚洲超碰在线观看| 欧美国产日韩在线| 中文字幕777| 国产精品久久一卡二卡| 免费看日本毛片| 午夜精品福利影院| 国产精品27p| 欧美一区二区三区| 日韩午夜av电影| 亚洲天堂av中文字幕| 久久99精品国产| 黄色片免费在线观看视频| 卡一精品卡二卡三网站乱码| 国产suv精品一区二区三区88区| 国产av一区二区三区| 久久精品一二三| 中文字幕在线观看第三页| y111111国产精品久久久| 亚洲视屏在线播放| 国产精品6666| 国产亚洲成av人在线观看导航| 国产理论在线播放| 欧美精品日韩| 欧美日韩日本网| 激情国产在线| 亚洲精品一区二区三区香蕉| 在线观看免费av片| 99精品国产视频| 日日噜噜夜夜狠狠| 国产影视精品一区二区三区| 欧美激情a在线| 日本ー区在线视频| 精品久久久久久久久久久久久| 91精品人妻一区二区| 狠狠色2019综合网| 国产网站免费在线观看| 999精品色在线播放| 国产精品999999| 亚洲精品一线| 日韩欧美国产精品一区| 婷婷伊人五月天| 蜜臀av性久久久久av蜜臀妖精| 日本10禁啪啪无遮挡免费一区二区 | 精品亚洲欧美一区| 国产小视频免费| 成人短片线上看| 国产一区二区免费在线观看| 26uuu亚洲电影在线观看| 在线视频国内自拍亚洲视频| 免费视频网站www| 国产精品白丝jk黑袜喷水| 裸体大乳女做爰69| 天天躁日日躁成人字幕aⅴ| 亚洲综合色激情五月| 在线看欧美视频| 在线免费观看羞羞视频一区二区| 精品国产99久久久久久宅男i| 亚洲欧洲日本在线| 免费观看av网站| www.亚洲在线| www.com毛片| 欧美.日韩.国产.一区.二区| 亚洲精品二区| 国产日韩欧美一区二区三区| 精品999在线观看| 77成人影视| 欧美又大又硬又粗bbbbb| 中文在线观看免费| 久久久精品免费| 丰满人妻一区二区三区免费视频| 欧美日韩精品三区| 精品无码一区二区三区电影桃花| 中文字幕视频一区| 亚洲不卡的av| 国产精品欧美经典| 国产18无套直看片| 国产午夜精品久久久久久免费视| 国产伦精品一区三区精东| 粉嫩绯色av一区二区在线观看| 缅甸午夜性猛交xxxx| 极品av少妇一区二区| 成年人视频网站免费| 韩国亚洲精品| 久操网在线观看| aa级大片欧美三级| 免费日韩视频在线观看| 一区二区国产在线| 久久精品国产99精品国产亚洲性色| 成人看片爽爽爽| 国产欧美日韩一区二区三区| 久久精品色播| 久久婷婷人人澡人人喊人人爽| 欧美巨大xxxx| 成人精品网站在线观看| 九九久久国产| 91精品视频在线| 神马久久午夜| 日韩av手机在线| 99久久精品一区二区成人| 国产精品永久免费观看| 第四色日韩影片| 久久免费视频网| 在线观看爽视频| 欧美另类在线观看| 182在线视频观看| 亲子乱一区二区三区电影 | 欧美视频亚洲图片| 在线亚洲欧美| 国产一区视频免费观看| 青娱乐精品在线视频| 可以在线看的av网站| 嫩草成人www欧美| www.夜夜爽| 国产91高潮流白浆在线麻豆| 成人手机在线免费视频| 国产欧美精品在线观看| 亚洲一区二区乱码| 国产视频亚洲色图| 国产精品 欧美激情| 国产免费观看久久| 亚洲色图综合区| 狠狠色狠狠色综合日日五| 中文字幕永久在线视频| 日韩精品最新网址| 国产私人尤物无码不卡| 久久成人18免费网站| 国产高清视频在线| 久久伊人精品一区二区三区| 国产一二三在线| 国产日韩亚洲欧美| 啪啪国产精品| 在线观看一区二区三区三州| 亚洲精品日本| 99国产精品久久久久久| 麻豆精品在线看| 亚洲欧洲国产视频| 国产成人丝袜美腿| 国产色视频在线播放| 成人精品电影在线观看| 天堂在线中文视频| 黄网动漫久久久| 99久久精品国产色欲| 亚洲欧美日韩一区二区在线| 在线中文字幕-区二区三区四区| 欧美一级bbbbb性bbbb喷潮片| 高清一区二区中文字幕| 91日韩在线播放| 青青草久久爱| 日韩欧美一级在线| 亚洲天堂成人| www.超碰97.com| 国产亚洲制服色| 日本一级黄色大片| 6080国产精品一区二区| www免费网站在线观看| 26uuu久久噜噜噜噜| a级日韩大片| 99re99热| 伊人久久婷婷| 成年人三级黄色片| 国产欧美日韩亚州综合| 成人毛片在线播放| 亚洲国产精久久久久久| 一区二区三区伦理| 91免费看国产| 99tv成人| 国产人妻人伦精品| 麻豆国产欧美一区二区三区| 亚洲精品国产91| 日韩欧美aⅴ综合网站发布| 国产午夜无码视频在线观看| 亚洲精品电影网| 激情小视频在线| 国产91成人video| 国内自拍欧美| av网站手机在线观看| 免费在线成人| 色啦啦av综合| 欧美韩国日本综合| 日韩黄色片网站| 亚洲新中文字幕| 日韩高清成人| 99re在线国产| 欧美va天堂| 中文字幕制服丝袜| 亚洲国产精品一区二区久久| 成人午夜免费在线观看| 高清在线视频日韩欧美| 激情亚洲另类图片区小说区| 欧美深夜福利视频| 久久亚洲免费视频| 99成人精品视频| 亚洲天堂色网站| 黄页免费欧美| 国产又爽又黄ai换脸| 国产麻豆午夜三级精品| 久久久久久久久毛片| 色综合久久久久综合99| 精品一二三区视频| 国产伦精品免费视频| 欧美国产免费| 800av在线播放| 91国在线观看| 欧美精品日韩少妇| 成人欧美一区二区三区视频| 精品欧美久久| 青青草精品视频在线| 91色视频在线| 中国一级片黄色一级片黄| 久久伊人精品视频| 欧美丝袜足交| 亚洲欧美另类动漫| 亚洲理论在线观看| 亚洲午夜在线播放| 久久综合色影院| 看全色黄大色大片免费久久久| 久久午夜夜伦鲁鲁一区二区| 亚洲人成网站在线| 午夜影院免费视频| 国产精品一区av| 影音先锋一区| gv天堂gv无码男同在线观看| 欧美一级久久久| 大胆人体一区二区| 国产欧美综合一区| 91尤物视频在线观看| 一级片免费网站| 97国产精品免费视频| 久久一区二区三区电影| 亚洲一区二区三区四区av| 一区二区三区精密机械公司| 青青草在线免费视频| 91蜜桃网站免费观看| 欧美福利视频|