在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何提高Mysql數據庫的訪問瓶頸

科技綠洲 ? 來源:Linux開發架構之路 ? 作者:Linux開發架構之路 ? 2023-11-08 16:22 ? 次閱讀

在學習Mysql的時候,我們都有這個常識:對于DB的操作,其實本質上是對于磁盤的操作,如果對于DB的訪問次數過多,其實就是涉及了大量的磁盤IO,這就會導致MYsql出現性能上的瓶頸。

項目背景

為了提高Mysql數據庫的訪問瓶頸,常用的方法有如下兩個:

  • 在服務器端增加緩存服務器緩存常用的數據(例如redis)
  • 增加連接池,來提高MYsql Server的訪問效率,在高并發的情況下,每一個用戶大量的TCP三次握手。Mysql Server的連接認證,Mysql Server關閉連接回收資源和TCP四次揮手所耗費的性能時間也是明顯的,增加連接池就是為了減少這一部分的性能損耗。

注:常見的MySQL、Oracle、SQLServer等數據庫都是基于C/S架構設計的。

市面上主流的Mysql數據庫連接池,對于短時間內的大量增刪改查操作的性能提升很明顯,但大多數都是Java實現的,該項目的開展就是為了提高Mysql Server的訪問效率,實現基于C++代碼的數據庫連接池模塊。

針對于系統啟動時就創建一定數量的連接,用戶一旦執行CURD操作,直接拿出一條連接即可,不需要TCP的連接過程和資源回收過程,使用完該連接后歸還給連接池的連接隊列,供之后使用。

功能點介紹

連接池一般包含了數據庫連接所用的ip地址、port端口號、username用戶名、password密碼以及其他一些性能參數:比如初始連接量、最大連接量、最大空閑時間、連接超時時間等,本項目重點實現上述通用功能:

1、初始連接量(initSize):

初始連接量表示連接池事先會和MySQL Server創建的initSize數量的Connection連接。在完成初始連接量之后,當應用發起MySQL訪問時,不用創建新的MySQLServer連接,而是從連接池中直接獲取一個連接,當使用完成后,再把連接歸還到連接池中。

2、最大連接量(maxSize)

當并發訪問MySQL Server的請求增加,初始連接量不夠用了,此時會增加連接量,但是增加的連接量的上限就是maxSIze。因為每一個連接都會占用一個socket資源,一般連接池和服務器都是部署在一臺主機上,如果連接池的連接數量過多,那么服務器就不能響應太多的客戶端請求了。

3、最大空閑時間(maxIdleTime)

當高并發過去,因為高并發而新創建的連接在很長時間(maxIdleTime)內沒有得到使用,那么這些新創建的連接處于空閑,并且占用著一定的資源,這個時候就需要將其釋放掉,最終只用保存iniSize個連接就行。

4、連接超時時間(connectionTimeOut)

當MySQL的并發訪問請求量過大,連接池中的連接數量已經達到了maxSize,并且此時連接池中沒有可以使用的連接,那么此時應用阻塞connectionTimeOut的時間,如果此時間內有使用完的連接歸還到連接池,那么他就可以使用,如果超過這個時間還是沒有連接,那么它獲取數據庫連接池失敗,無法訪問數據庫。

功能點實現的相關原理綜述

  1. 連接池只需要一個實例,所以ConnectionPool以單例`模式設計;
  2. 從ConnectionPool中可以獲取和Mysql的連接Connection;
  3. 空閑連接Connection全部維護在一個線程安全的Connection隊列中,使用線程互斥鎖保證隊列的線程安;
  4. 如果Connection隊列為空,還需要再獲取連接,此時需要動態創建連接,上限數量是maxSize;
  5. 隊列中空閑連接時間超過maxIdleTime的就會被釋放掉,只保留初始的initSize個連接就可以了,這個功能點肯定要放在獨立的線程中去做;
  6. 如果Connection隊列為空,而此時連接的數量已達上限maxSize,那么等待ConnectionTimeout時間還獲取不到空閑的連接,那么獲取連接失敗,此處從Connection隊列獲取空閑連接,可以使用帶超時時間的mutex互斥鎖來實現連接超時時間;
  7. 用戶獲取的連接用shared_ptr智能指針來管理,用lambda表達式定制連接釋放的功能(不真正釋放連接,而是把連接歸還到連接池中);
  8. 連接的生產和連接的消費采用生產者-消費者線程模型來設計,使用了線程間的同步通信機制條件變量和互斥鎖。

圖示如下:

圖片

關鍵技術點

1、MySql數據庫編程

目的:在C++下輸入Sql語句對數據庫進行操作的代碼封裝

說明:這里的MYSQL的數據庫編程直接采用oracle公司提供的C++客戶端開發包 , 讀者可以自己查閱資料或搜索官方文檔自行學習相關API的使用方法。

Connection.h:

class Connection
{
public:
// 初始化數據庫連接
Connection();
// 釋放數據庫連接資源
~Connection();
// 連接數據庫
bool connect(string ip,
unsigned short port,
string user,
string password,
string dbname);
// 更新操作 insert、delete、update
bool update(string sql);
// 查詢操作 select
MYSQL_RES* query(string sql);
// 刷新一下連接的起始的空閑時間點
void refreshAliveTime() { _alivetime = clock(); }
// 返回存活的時間
clock_t getAliveeTime()const { return clock() - _alivetime; }
private:
MYSQL* _conn; // 表示和MySQL Server的一條連接
clock_t _alivetime; // 記錄進入空閑狀態后的起始存活時間
};

Connection.cpp:

Connection::Connection()
{
// 初始化數據庫連接
_conn = mysql_init(nullptr);
}

Connection::~Connection()
{
// 釋放數據庫連接資源
if (_conn != nullptr)
mysql_close(_conn);
}

bool Connection::connect(string ip, unsigned short port,
string username, string password, string dbname)
{
// 連接數據庫
MYSQL* p = mysql_real_connect(_conn, ip.c_str(), username.c_str(),
password.c_str(), dbname.c_str(), port, nullptr, 0);
return p != nullptr;
}

bool Connection::update(string sql)
{
// 更新操作 insert、delete、update
if (mysql_query(_conn, sql.c_str()))
{
LOG("更新失敗:" + sql);
return false;
}
return true;
}

MYSQL_RES* Connection::query(string sql)
{
// 查詢操作 select
if (mysql_query(_conn, sql.c_str()))
{
LOG("查詢失敗:" + sql);
return nullptr;
}
return mysql_use_result(_conn);
}

這里需要說明的是:在Windows上使用數據庫需要進行相關配置,大致配置內容如下:

  • 右鍵項目- C/C++ - 常規 -附加包含目錄 - 增加mysql.h的頭文件路徑;
  • 右鍵項目 - 鏈接器 - 常規 - 附加庫目錄 - 填寫libmysql.lib的路徑;
  • 右鍵項目 - 鏈接器 - 輸入 - 附加依賴項 - 填寫libmysql.lib的路徑;
  • 把libmysql.dll的動態鏈接庫(Linux下后綴名是.so庫)放在工程目錄下。

2、數據庫連接池單例代碼

連接池僅需要一個實例,同時服務器肯定是多線程的,必須保證線程安全,所以采用懶漢式線程安全的單例:

CommonConnectionPool.h: 部分代碼

class ConnectionPool
{
public:
// 獲取連接池對象實例
static ConnectionPool* getConnectionPool();
// 給外部提供接口,從連接池中獲取一個可用的空閑連接
shared_ptr getConnection();
private:
// 單例#1 構造函數私有化
ConnectionPool();
};

CommonConnectionPool.cpp: 部分代碼

// 線程安全的懶漢單例函數接口
ConnectionPool* ConnectionPool::getConnectionPool()
{
static ConnectionPool pool; //靜態對象初始化由編譯器自動進行lock和unlock
return &pool;
}

3、queue隊列容器

連接池的數據結構是queue隊列,最早生成的連接connection放在隊頭,此時記錄一個起始時間,這一點在后面最大空閑時間時會發揮作用:如果隊頭都沒有超過最大空閑時間,那么其他的一定沒有

CommonConnectionPool.cpp的連接池構造函數:

// 連接池的構造
ConnectionPool::ConnectionPool()
{
// 加載配置項了
if (!loadConfigFile())
{
return;
}

// 創建初始數量的連接
for (int i = 0; i < _initSize; ++i)
{
Connection* p = new Connection();//創建一個新的連接
p->connect(_ip, _port, _username, _password, _dbname);
p->refreshAliveTime(); // 刷新一下開始空閑的起始時間
_connectionQue.push(p);
_connectionCnt++;
}
}

連接數量沒有到達上限,繼續創建新的連接

if (_connectionCnt < _maxSize)
{
Connection* p = new Connection();
p->connect(_ip, _port, _username, _password, _dbname);
p->refreshAliveTime(); // 刷新一下開始空閑的起始時間
_connectionQue.push(p);
_connectionCnt++;
}

掃描整個隊列,釋放多余的連接(高并發過后,新建的連接超過最大超時時間時)

unique_lock lock(_queueMutex);
while (_connectionCnt > _initSize)
{
Connection* p = _connectionQue.front();
if (p->getAliveTime() >= (_maxIdleTime * 1000))
{
_connectionQue.pop();
_connectionCnt--;
// 調用~Connection()釋放連接
delete p;
}
else
{
// 如果隊頭的連接沒有超過_maxIdleTime,其他連接肯定沒有
break;
}
}

4、多線程編程

為了將多線程編程的相關操作應用到實際,也為了進行壓力測試,用結果證明使用連接池之后對數據庫的訪問效率確實比不使用連接池的時候高很多,使用了多線程來進行數據庫的訪問操作,并且觀察多線程下連接池對于性能的提升。

代碼如下:

int main()
{
thread t1([]() {
for (int i = 0; i < 250; ++i)
{
Connection conn;
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
conn.connect("127.0.0.1", 3306, "root", "991205", "chat");
conn.update(sql);
}
});
thread t2([]() {
for (int i = 0; i < 250; ++i)
{
Connection conn;
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
conn.connect("127.0.0.1", 3306, "root", "991205", "chat");
conn.update(sql);
}
});
thread t3([]() {
for (int i = 0; i < 250; ++i)
{
Connection conn;
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
conn.connect("127.0.0.1", 3306, "root", "991205", "chat");
conn.update(sql);
}
});
thread t4([]() {
for (int i = 0; i < 250; ++i)
{
Connection conn;
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "male");
conn.connect("127.0.0.1", 3306, "root", "991205", "chat");
conn.update(sql);
}
});

t1.join();
t2.join();
t3.join();
t4.join();

return 0;
}

五、線程互斥、線程同步通信(生產者-消費者模型)、unique_lock

連接池中連接隊列的連接的生產和消費需要保證其線程安全,于是我們需要引入互斥鎖mutex,線程同步通信確保執行順序,以及唯一鎖。

代碼如下:

class ConnectionPool
{
private:
// 設置條件變量,用于連接生產線程和連接消費線程的通信
condition_variable cv;
// 維護連接隊列的線程安全互斥鎖
mutex _queueMutex;
};

for (;;)
{
unique_lock lock(_queueMutex);
while (!_connectionQue.empty())
{
// 隊列不為空,此處生產線程進入等待狀態
cv.wait(lock);
}

// 連接數量沒有達到上限,繼續創建新的連接
if (_connectionCnt < _maxSize)
{
Connection* p = new Connection();
p->connect(_ip, _port, _username, _password, _dbname);
// 刷新一下開始空閑的起始時間
p->refreshAliveTime();
_connectionQue.push(p);
_connectionCnt++;
}

// 通知消費者線程,可以消費連接了
cv.notify_all();
}
// 啟動一個新的線程,作為連接的生產者 linux thread => pthread_create
thread produce(std::bind(&ConnectionPool::produceConnectionTask, this));
produce.detach();

// 啟動一個新的定時線程,掃描超過maxIdleTime時間的空閑連接,進行對于的連接回收
thread scanner(std::bind(&ConnectionPool::scannerConnectionTask, this));
scanner.detach();

六、CAS原子操作

對于連接池內的連接數量,生產者和消費者線程都會去改變其值,那么這個變量的修改就必須保證其原子性,于是使用C++11中提供的原子類:atomic_int

atomic_int _connectionCnt; // 記錄連接所創建的connection連接的總數量

// 生產新連接時:
_connectionCnt++;
// 當新連接超過最大超時時間后被銷毀時
_connectionCnt--;

七、shared_ptr及lambda表達式

對于使用完成的連接,不能直接銷毀該連接,而是需要將該連接歸還給連接池的隊列,供之后的其他消費者使用,于是我們使用智能指針,自定義其析構函數,完成放回的操作:

shared_ptr sp(_connectionQue.front(),
[&](Connection* pcon) {
// 這里是在服務器應用線程中調用的,所以一定要考慮隊列的線程安全操作
unique_lock lock(_queueMutex);
pcon->refreshAliveTime();
_connectionQue.push(pcon);
});

八、壓力測試

測試添加連接池后效率是否提升:

未使用連接池

1.單線程

int main()
{
clock_t begin = clock();
for (int i = 0; i < 1000; ++i)
{
Connection conn;
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
conn.connect("127.0.0.1", 3306, "root", "123456", "chat");
conn.update(sql);
}
clock_t end = clock();
cout << (end - begin) << "ms" << endl;
return 0;
}

運行時間如下:

圖片

添加圖片注釋,不超過 140 字(可選)

2.多線程

int main()
{
Connection conn;
conn.connect("127.0.0.1", 3306, "root", "991205", "chat");
clock_t begin = clock();

thread t1([]() {
for (int i = 0; i < 250; ++i)
{
Connection conn;
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
conn.connect("127.0.0.1", 3306, "root", "123456", "chat");
conn.update(sql);
}
});
thread t2([]() {
for (int i = 0; i < 250; ++i)
{
Connection conn;
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
conn.connect("127.0.0.1", 3306, "root", "123456", "chat");
conn.update(sql);
}
});
thread t3([]() {
for (int i = 0; i < 250; ++i)
{
Connection conn;
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
conn.connect("127.0.0.1", 3306, "root", "123456", "chat");
conn.update(sql);
}
});
thread t4([]() {
for (int i = 0; i < 250; ++i)
{
Connection conn;
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
conn.connect("127.0.0.1", 3306, "root", "123456", "chat");
conn.update(sql);
}
});

t1.join();
t2.join();
t3.join();
t4.join();

clock_t end = clock();
cout << (end - begin) << "ms" << endl;
return 0;
}

運行時間如下:

圖片

使用連接池

1.單線程

int main()
{
clock_t begin = clock();
ConnectionPool* cp = ConnectionPool::getConnectionPool();
for (int i = 0; i < 1000; ++i)
{
shared_ptr sp = cp->getConnection();
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
sp->update(sql);
}

clock_t end = clock();
cout << (end - begin) << "ms" << endl;
return 0;
}

運行時間如下:

圖片

2.多線程

int main()
{
clock_t begin = clock();

thread t1([]() {
ConnectionPool* cp = ConnectionPool::getConnectionPool();
for (int i = 0; i < 250; ++i)
{
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
shared_ptr sp = cp->getConnection();
sp->update(sql);
}
});
thread t2([]() {
ConnectionPool* cp = ConnectionPool::getConnectionPool();
for (int i = 0; i < 250; ++i)
{
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
shared_ptr sp = cp->getConnection();
sp->update(sql);
}
});
thread t3([]() {
ConnectionPool* cp = ConnectionPool::getConnectionPool();
for (int i = 0; i < 250; ++i)
{
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
shared_ptr sp = cp->getConnection();
sp->update(sql);
}
});
thread t4([]() {
ConnectionPool* cp = ConnectionPool::getConnectionPool();
for (int i = 0; i < 250; ++i)
{
char sql[1024] = { 0 };
sprintf(sql, "insert into user(name,age,sex) values('%s',%d,'%s')",
"zhang san", 20, "M");
shared_ptr sp = cp->getConnection();
sp->update(sql);
}
});

t1.join();
t2.join();
t3.join();
t4.join();

clock_t end = clock();
cout << (end - begin) << "ms" << endl;
return 0;
}

圖片

比較

在使用了連接池之后,性能確實提升了不少

  • 數據量1000,單線程從1417ms變成697ms
  • 數據量1000,多線程從420ms變成了307ms
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 磁盤
    +關注

    關注

    1

    文章

    380

    瀏覽量

    25294
  • TCP
    TCP
    +關注

    關注

    8

    文章

    1381

    瀏覽量

    79341
  • 數據庫
    +關注

    關注

    7

    文章

    3852

    瀏覽量

    64728
  • ip地址
    +關注

    關注

    0

    文章

    303

    瀏覽量

    17144
  • MySQL
    +關注

    關注

    1

    文章

    831

    瀏覽量

    26762
收藏 人收藏

    評論

    相關推薦

    labview遠程訪問服務器的mysql數據庫

    大神求助!!!求問怎么通過labview讀取服務器中的數據庫,使用mysql寫的數據庫
    發表于 04-01 20:57

    ESP8266如何連接mysql數據庫

    各位大神,我試圖用ESP8266 連接mysql ,將溫濕度傳感器的數據,寫入數據庫mysql數據庫已建好,在局域網中的其他電腦也可以正常
    發表于 01-12 09:22

    mysql數據庫同步原理

    數據庫訪問壓力,提升整個系統的性能和可用性,降低了大訪問量引發數據庫宕機的故障率。 binlog簡介 MySQL主從同步是基于binlo
    發表于 09-28 11:49 ?0次下載
    <b class='flag-5'>mysql</b><b class='flag-5'>數據庫</b>同步原理

    數據庫教程之PHP訪問MySQL數據庫的理論知識詳細說明

    本文檔的主要內容詳細介紹的是數據庫教程之PHP訪問MySQL數據庫的理論知識詳細說明包括了:1.phpMyAdmin的安裝和使用,2.PHP操作數據
    發表于 06-17 17:06 ?15次下載

    Serverless 解惑—函數計算如何訪問 MySQL 數據庫

    任務,并提供日志查詢、性能監控和報警等功能。借助函數計算,您可以快速構建任何類型的應用和服務,并且只需為任務實際消耗的資源付費。 訪問 MySQL 數據庫是指在函數計算中通過編寫代碼調用數據庫
    發表于 03-09 16:52 ?744次閱讀

    MySQL數據庫如何安裝和使用說明

    MySQL數據庫開發 基礎概念 1.數據:描述事物特征的符號,屬性 2.數據庫的概念:管理計算機中的數據的倉庫 2.
    的頭像 發表于 02-13 16:13 ?2851次閱讀

    MySQL監控-Datadog數據庫監控調研

    大多系統的后端的存儲都有MySQL的身影,MySQL運行的是否健康,直接影響著整個系統的運行,數據庫瓶頸往往也是整個系統的瓶頸,其重要性不
    發表于 11-24 17:53 ?4030次閱讀

    華為云數據庫-RDS for MySQL數據庫

    華為云數據庫-RDS for MySQL數據庫 華為云數據庫作為華為云的一款數據庫產品,它主要是以MyS
    的頭像 發表于 10-27 11:06 ?1580次閱讀

    MySQL數據庫管理與應用

    MySQL數據庫管理與應用 MySQL是一種廣泛使用的關系型數據庫管理系統,被認為是最流行和最常見的開源數據庫之一。它可以被用于多種不同的應
    的頭像 發表于 08-28 17:15 ?1048次閱讀

    mysql是一個什么類型的數據庫

    MySQL是一種關系型數據庫管理系統(RDBMS),用于存儲和管理大量結構化數據。它被廣泛用于各種應用程序和網站的后端,包括電子商務平臺、社交媒體網站、金融系統等等。MySQL的特點是
    的頭像 發表于 11-16 14:43 ?1899次閱讀

    MySQL數據庫基礎知識

    MySQL 是一種開源的關系型數據庫管理系統,它是目前最流行的數據庫之一。MySQL 提供了一種結構化的方法來管理大量的數據,并且具有高效、
    的頭像 發表于 11-21 11:09 ?1023次閱讀

    mysql數據庫基礎命令

    MySQL是一個流行的關系型數據庫管理系統,經常用于存儲、管理和操作數據。在本文中,我們將詳細介紹MySQL的基礎命令,并提供與每個命令相關的詳細解釋。 登錄
    的頭像 發表于 12-06 10:56 ?651次閱讀

    數據庫數據恢復—Mysql數據庫表記錄丟失的數據恢復流程

    Mysql數據庫故障: Mysql數據庫表記錄丟失。 Mysql數據庫故障表現: 1、
    的頭像 發表于 12-16 11:05 ?229次閱讀
    <b class='flag-5'>數據庫</b><b class='flag-5'>數據</b>恢復—<b class='flag-5'>Mysql</b><b class='flag-5'>數據庫</b>表記錄丟失的<b class='flag-5'>數據</b>恢復流程

    MySQL數據庫的安裝

    MySQL數據庫的安裝 【一】各種數據庫的端口 MySQL :3306 Redis :6379 MongoDB :27017 Django :8000 flask :5000 【二】
    的頭像 發表于 01-14 11:25 ?142次閱讀
    <b class='flag-5'>MySQL</b><b class='flag-5'>數據庫</b>的安裝

    從Delphi、C++ Builder和Lazarus連接到MySQL數據庫

    ? 從 Delphi、C++ Builder 和 Lazarus 連接到 MySQL 數據庫 MySQL 數據訪問組件(MyDAC)是一個組
    的頭像 發表于 01-20 13:47 ?145次閱讀
    從Delphi、C++ Builder和Lazarus連接到<b class='flag-5'>MySQL</b><b class='flag-5'>數據庫</b>
    主站蜘蛛池模板: 国产综合久久久久影院 | 欧美成人午夜毛片免费影院 | 成人美女隐私免费 | 人人成人免费公开视频 | 日韩毛片网 | 特级一级毛片免费看 | 日本不卡免费高清一级视频 | 亚洲免费看片 | 色婷婷久久合月综 | 在线天堂资源www中文在线 | 黄 色 录像成 人播放免费99网 | 欧美一区亚洲 | 欧美性xx18一19 | 国产一级做a爱免费视频 | 国产亚洲人成a在线v网站 | 99久久精品国产自免费 | 国产精品高清一区二区三区不卡 | 亚洲伊人精品综合在合线 | 四虎精品免费国产成人 | 人操人操 | 天天干天天天天 | 天堂网最新版中文 | 天天操人人爱 | 综合色中色| 国产精品三级在线观看 | 婷婷激情久久 | 精品国产污污免费网站入口 | 99pao强力打造免费高清色 | 色五月情 | 中文天堂最新版www官网在线 | 国产成人悠悠影院 | 一本到午夜92版免费福利 | 久草丁香| 特级黄色毛片 | 亚洲bbbbbxxxxx精品三十七 | 51国产午夜精品免费视频 | 天天操bb | 午夜精品视频在线看 | 天天色影院 | 成人免费无毒在线观看网站 | 手机看片1024欧美 |