Linux-Memcache分布式部署方案(magent代理解決單點故障)


Memcached的特點

Memcached作為高速運行的分布式緩存服務器具有以下特點。

  1. 協議簡單:memcached的服務器客戶端通信並不使用復雜的MXL等格式, 而是使用簡單的基於文本的協議。

  2. 基於libevent的事件處理:libevent是個程序庫,他將Linux 的epoll、BSD 類操作系統的kqueue等時間處理功能封裝成統一的接口。memcached使用這個libevent庫,因此能在Linux、BSD、Solaris等操作系統上發揮其高性能。

  3. 內置內存存儲方式:為了提高性能,memcached中保存的數據都存儲在 memcached內置的內存存儲空間中。由於數據僅存在於內存中,因此重啟memcached,重啟操作系統會導致全部數據消失。另外,內容容量達到指定的值之后  memcached  回自動刪除不適用的緩存。

  4.Memcached不互通信的分布式:memcached  盡管是  “  分布式  ”  緩存服務器,但服務器端並沒有分布式功能。各個  memcached  不會互相通信以共享信 息。他的分布式主要是通過客戶端實現的。

Memcache內存管理

最近的memcached默認情況下采用了名為Slab Allocatoion的機制分配,管理內存。在改機制出現以前,內存的分配是通過對所有記錄簡單地進行malloc和free來進行的。但是這中方式會導致內存碎片,加重操作系統內存管理器的負擔。

Slab Allocator的基本原理是按照預先規定的大小,將分配的內存分割成特定長度的塊,已完全解決內存碎片問題。Slab Allocation  的原理相當簡單。將分配的內存分割成各種尺寸的塊(chucnk),並把尺寸相同的塊分成組(chucnk的集合)如圖:


而且slab allocator 還有重復使用已分配內存的目的。也就是說,分配到的內存不會釋放,而是重復利用。 
Slab Allocation 的主要術語

  Page :分配給Slab 的內存空間,默認是1MB。分配給Slab 之后根據slab 的大小切分成chunk.

  Chunk : 用於緩存記錄的內存空間。

  Slab Class:特定大小的chunk 的組。 
在Slab 中緩存記錄的原理  Memcached根據收到的數據的大小,選擇最合適數據大小的Slab memcached中保存着slab內空閑chunk的列表,根據該列表選擇chunk,然后將數據緩存於其中。

 

Memcache刪除數據

Memcached刪除數據時數據不會真正從memcached中消失。Memcached不會釋放已分配的內存。記錄超時后,客戶端就無法再看見該記錄(invisible 透明),其存儲空間即可重復使用。

memcached內部不會監視記錄是否過期,而是在get時查看記錄的時間戳,檢查記錄是否過期。這種技術稱為Lazy Expriation。因此memcached不會再過期監視上耗費CPU時間。

LRU:從緩存中有效刪除數據的原理

  Memcached會優先使用已超時的記錄空間,但即使如此,也會發生追加新紀錄時空間不足的情況。此時就要使用名為Least Recently Used (LRU)機制來分配空間。這就是刪除最少使用的記錄的機制。因此當memcached的內存空間不足時(無法從slab class)獲取到新空間時,就從最近未使用的記錄中搜索,並將空間分配給新的記錄。

Memcached存在的問題

本身沒有內置分布式功能,無法實現使用多台Memcache服務器來存儲不同的數據,最大程度的使用相同的資源;無法同步數據,容易造成單點故障。(memagent代理實現集群)

在 Memcached中可以保存的item數據量是沒有限制的,只要內存足夠 。
Memcached單進程最大使用內存為2G,要使用更多內存,可以分多個端口開啟多個Memcached進程
最大30天的數據過期時間,設置為永久的也會在這個時間過期,常量REALTIME_MAXDELTA 60*60*24*30控制
最大鍵長為250字節,大於該長度無法存儲,常量KEY_MAX_LENGTH 250控制
單個item最大數據是1MB,超過1MB數據不予存儲,常量POWER_BLOCK 1048576進行控制,
它是默認的slab大小
最大同時連接數是200,通過 conn_init()中的freetotal進行控制,最大軟連接數是1024,通過settings.maxconns=1024 進行控制
跟空間占用相關的參數:settings.factor=1.25, settings.chunk_size=48, 影響slab的數據占用和步進方式

memcached是一種無阻塞的socket通信方式服務,基於libevent庫,由於無阻塞通信,對內存讀寫速度非常之快。
memcached分服務器端和客戶端,可以配置多個服務器端和客戶端,應用於分布式的服務非常廣泛。
memcached作為小規模的數據分布式平台是十分有效果的。

memcached是鍵值一一對應,key默認最大不能超過128個字節,value默認大小是1M,也就是一個slabs,如果要存2M的值(連 續的),不能用兩個slabs,因為兩個slabs不是連續的,無法在內存中存儲,故需要修改slabs的大小,多個key和value進行存儲時,即使 這個slabs沒有利用完,那么也不會存放別的數據。

Memcache的分布式介紹

memcached雖然稱為“分布式”緩存服務器,但服務器端並沒有“分布式”功能。服務器端僅包括內存存儲功能,其實現非常簡單。至於memcached的分布式,則是完全由客戶端程序庫實現的。這種分布式是memcached的最大特點。

如何理解Memcached的分布式

這里多次使用了“分布式”這個詞,但並未做詳細解釋。 現在開始簡單地介紹一下其原理,各個客戶端的實現基本相同。
下面假設memcached服務器有node1~node3三台, 應用程序要保存鍵名為“tokyo”“kanagawa”“chiba”“saitama”“gunma” 的數據。

准備

首先向memcached中添加“tokyo”。將“tokyo”傳給客戶端程序庫后,客戶端實現的算法就會根據“鍵”來決定保存數據的memcached服務器。服務器選定后,即命令它保存“tokyo”及其值。

添加時

同樣,“kanagawa”“chiba”“saitama”“gunma”都是先選擇服務器再保存。

接下來獲取保存的數據。獲取時也要將要獲取的鍵“tokyo”傳遞給函數庫。 函數庫通過與數據保存時相同的算法,根據“鍵”選擇服務器。 使用的算法相同,就能選中與保存時相同的服務器,然后發送get命令。 只要數據沒有因為某些原因被刪除,就能獲得保存的值。

獲取時

這樣,將不同的鍵保存到不同的服務器上,就實現了memcached的分布式。 memcached服務器增多后,鍵就會分散,即使一台memcached服務器發生故障
無法連接,也不會影響其他的緩存,系統依然能繼續運行。

普通余數分散法

  余數計算的方法簡單,數據的分散性也相當優秀, 但也有其缺點。那就是當添加或移除服務器時,  緩存重組的代價相當巨大。

  添加服務器后,余數就會產生巨變,這樣就無法獲取與保存時相同的服務器,從而影響緩存的命中率。

集群配置

由於Memcached服務器與服務器之間沒有任何通訊,並且不進行任何數據復制備份,所以當任何服務器節點出現故障時,會出現單點故障,如果需要實現HA,則需要通過另外的方式來解決。

通過Magent緩存代理,防止單點現象,緩存代理也可以做備份,通過客戶端連接到緩存代理服務器,緩存代理服務器連接緩存服務器,緩存代理服務器 可以連接多台Memcached機器可以將每台Memcached機器進行數據同步。如果其中一台緩存服務器down機,系統依然可以繼續工作,如果其中 一台Memcached機器down掉,數據不會丟失並且可以保證數據的完整性。具體可以參考:http://code.google.com/p /memagent/

Memcache集群的實現

memcached盡管是“分布式”緩存服務器,但服務器端並沒有分布式功能。各個memcached不會互相通信以共享信息。那么,怎樣進行分布式呢?這完全取決於客戶端的實現。

magent是一個memcached代理軟件(memcached agent),又叫memagent,其項目網址為:
https://github.com/wangmh/memagent,防止單點現象,緩存代理也可以做備份,通過客戶端連接到緩存代理服務器,緩存代理服務器連接緩存服務器。
它提供的功能及特點有:
1、和每個memcache server保持多個長連接,效果是減少memcache server保持的連接數量及創建銷毀連接的開銷。不過,memcache本身就支持大並發連接,這個功能也就沒什么特別的說道。
2、支持memcache的binary協議命令,實現請求的轉發。
3、和memcache一樣,基於libevent的事件驅動來處理IO。
4、支持ketama 的一致性hash算法。
5、支持memcache backup集群,當memcache集群有機器掛了,memagent會將get請求轉向memcache backup集群。這個功能對於cache的穩定性要求高的場景下會有用武之地。

就提供的功能而言,memagent是個很簡單的東西。對於較大的memcache集群,可以考慮搭一套memagent作為proxy使用。

magent的hash算法

  magent采用的是:Consistent Hashing原理,Consistent Hashing如下所示:首先求出memcached服務器(節點)的哈希值, 並將其配置到0~232的圓(continuum)上。 然后用同樣的方法求出存儲數據的鍵的哈希值,並映射到圓上。 然后從數據映射到的位置開始順時針查找,將數據保存到找到的第一個服務器上。 如果超過232仍然找不到服務器,就會保存到第一台memcached服務器上。

  從上圖的狀態中添加一台memcached服務器。余數分布式算法由於保存鍵的服務器會發生巨大變化 而影響緩存的命中率,但Consistent Hashing中,只有在continuum上增加服務器的地點逆時針方向的第一台服務器上的鍵會受到影響。

 

Linux下的Memcache集群環境搭建

環境:CentOS release 6.5

搭建memcached集群環境,先要安裝gcc

yum -y install gcc

如果出現如下錯誤:

Error: Package: glibc-headers-2.12-1.132.el6.x86_64 (base)
    Requires: kernel-headers >= 2.2.1
Error: Package: glibc-headers-2.12-1.132.el6.x86_64 (base)
    Requires: kernel-headers
You could try using --skip-broken to work around the problem
You could try running: rpm -Va --nofiles --nodigest

解決方法:修改文件

vi /etc/yum.conf 

exclude=kernel* 前加注釋即可解決,此參數的意思是排除安裝或更新kernel開頭的軟件,而我們安裝gcc需要依賴kernel相關的軟件glibc-headers-2.12-1.80.el6_3.5.x86_64

在root目錄下創建soft目錄

cd /root/
mkdir soft

安裝libevent

檢查是否安裝了libevent軟件

rpm -qa|grep libevent

編譯安裝libevent

cd /root/soft/
wget http://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
tar -zxvf libevent-2.0.21-stable.tar.gz
cd libevent-2.0.21-stable
./configure --prefix=/usr
make && make install
cd ../
 
#測試是否安裝成功:
ls -al /usr/lib | grep libevent

yum安裝libevent

也可以用yum直接安裝libevent

yum install libevent libevent-devel

編譯安裝Memcached

cd /root/soft/
wget http://memcached.googlecode.com/files/memcached-1.4.15.tar.gz
tar -zxvf memcached-1.4.15.tar.gz
cd memcached-1.4.15/
./configure --with-libevent=/usr
make && make install
cd ../
 
#測試是否安裝成功:
ls -al /usr/local/bin/mem*
 
#或啟動一個memcached進程
memcached -m 1 -u root -d -l 192.168.1.151 -p 11211
 
#查看是否啟動成功了
ps aux|grep memcached
 
#顯示兩行 root,則說明安裝成功了,如下所示:
root     11952  0.0  0.0 331112  1104         Ssl  15:09   0:00 memcached -m 1 -u root -d -l 192.168.1.151 -p 11211
root     11959  0.0  0.0 103240   796 pts/1    S+   15:09   0:00 grep memcached

編譯安裝magent

編譯安裝magent-0.6到/usr/local/下(推薦安裝magent-0.5穩定版本,因為測試發現magent-0.6雖是最新版 本,但是還存在問題,不穩定,第二次訪問magent始終會堵塞在那里,只能set一個值。測試了magent-0.5是穩定版本,沒有出現只能set一 個值的現象,遂推薦安裝magent-0.5版本,不過此問題也可以通過修改源碼的方式來解決,解決方案參考(重點參考第8 樓):https://code.google.com/p/memagent/issues/detail?id=4#makechanges )

cd /usr/local
mkdir magent
cd magent/
wget http://memagent.googlecode.com/files/magent-0.6.tar.gz
解壓的文件中ketama.* 是一致性hash的實現
tar -zxvf magent-0.6.tar.gz
 
vi ketama.h
在開頭加入
#ifndef SSIZE_MAX
#endif
 
############magent-0.6版本修改內容start############
vi Makefile (magent-0.6版本)
 
改為
############magent-0.6版本修改內容end##############
 
############magent-0.5版本修改內容start############
vi Makefile (magent-0.5版本)
 
CFLAGS = -Wall -O2 -g
改為
CFLAGS = -lrt -Wall -O2 -g
 
sed -i "s#LIBS = -levent#LIBS = -levent -lm#g" Makefile
############magent-0.5版本修改內容end##############
 
/sbin/ldconfig
 
make
cp magent /usr/bin/magent
cd ../
 
測試magent是否安裝成功:
 
1.啟動一個magent進程
 
 
2.查看是否啟動成功了
 
ps aux|grep magent

顯示兩行 root,則說明安裝成功了,如下所示:

root 11720 0.0 0.0 10972 588 Ss 13:51 0:00 magent -u root -n 51200 -l 192.168.1.151 -p 12000 -s 192.168.1.151:11211 -s 192.168.1.151:11212 -b 192.168.1.151:11213
root 11974 0.0 0.0 103240 792 pts/1 R+ 15:12 0:00 grep magent[/code]

注: 之前的安裝過程中,我總是只顯示一行:root 11974 0.0 0.0 103240 792 pts/1 R+ 15:12 0:00 grep magent,但是執行magent命令又不報錯,可是查看magent進程,老是沒有,老是啟動不起來,其實還是magent沒有安裝成功,所以這邊必 須要看到兩行,才能說明啟動成功。

安裝可能會出錯,可以到該地址看看:http://ruancl.blog.51cto.com/2699729/850951
其它參考地址:http://blog.csdn.net/laosubitu/article/details/22198613

magent工作方式

1.get操作,先到普通mem上讀取;如果失敗,再到備份mem上讀取(即服務器失效會導致兩次讀,不過只是特殊情況下的處理,可以接受)
2.如果一次get多個key的值,會逐個執行1中的步驟
3.delete,incr,decr,add,set,replace,prepend,append,cas,同時操作{普通mem,備份mem}

* 寫操作:先操作備份men,再操作普通mem
* 不關聯兩者之間操作的成功/失敗

4.client從magent上斷開,不影響magent保持與集群server的鏈接
5.建議:client和magent部署在一起,client通過127.0.0.1訪問magent時,效率會更高
————-

magent命令參數

-h this message
-u uid
-g gid
-p port, default is 11211. (0 to disable tcp support)
-s ip:port, set memcached server ip and port
-b ip:port, set backup memcached server ip and port
-l ip, local bind ip address, default is 0.0.0.0
-n number, set max connections, default is 4096
-D don’t go to background
-k use ketama key allocation algorithm
-f file, unix socket path to listen on. default is off
-i number, max keep alive connections for one memcached server, default is 20
-v verbose

准備測試工具

接着就是進行測試學習了,首先確保telnet服務安裝了

查看telnet客戶端是否安裝:

rpm -q telnet

若無安裝,則執行:

yum -y install telnet

查看telnet服務端是否安裝:

rpm -q telnet-server

若無安裝,則執行:

yum -y install telnet-server

測試流程

參照:http://blog.s135.com/post/393/ 其中使用的是magent-0.5

我嘗試了0.5和最新的0.6,但里面提到的重啟后的” 由於這兩台Memcached重啟后無數據,因此magent取得的將是空值,盡管11213端口的Memcached還有數據(此問題尚待改進)“,仍然存在

PHP+Memcache實現分布式

我們PHP的PECL中的Memcache擴展能夠有效的解決Memcache的分布式問題,主要的接口就是 addServer() 函數,具體關於addServer()函數的實現可以參考該擴展源代碼。那么現在就存在第二個問題,就是說無法同步數據,可以理解為MySQL中 Master/Slave的機制,就是說如果我們有多台的Memcache服務器,使用addServer函數的話,每個服務器存儲的數據都是唯一的,也 就是說每個memcached服務器上存儲的數據不是統一的,而是各自保存了不通的數據。

配置使用memcache存儲session數據

session.save_handler = memcache
session.save_path ="tcp://127.0.0.1:11211"

注意:如果使用的是php的memcached擴展(注意不是memchache擴展)。

按照網上的資料配置php.ini

session.save_handler=memcached
session.save_path="tcp://127.0.0.1:11211"

會發現報錯

Warning: Unknown: Failed to write session data (memcached). Please verify that the current setting of session.save_path is correct (tcp://127.0.0.1:11211) in Unknown on line 0

解決方案是把tcp://去掉。經測試,用memcache(不帶d)擴展,去掉 tcp://后也能正常連接。測試中還發現用memcached擴展時,通過session_id()做為key獲取緩存內容始終是空值,但用 memcache擴展卻是正常,一旦通過memcache擴展設置session后,再通過memcached獲取session_id()做為key獲 取緩存內容就能正常輸出,由些我猜測memcached設置不了session_id(此猜測在后面的測試中發現並非如此,而是memcached生成的 key為session_id的,自動在前面加了’memc.sess.key.’前綴),但獲取值卻是正常的。不知道是我配置過程中出錯還是什么原因, 目前尚未解決這個問題。

其它發現:
1、memcache + magent 不支持session,但支持其它變量的存取
2、memcached + magent 支持session,但是不能通過key為session_id()獲取session_id內容,要加上’memc.sess.key.’前綴才可以獲取session_id的內容
3、memcache和memcached 不加magent都支持session,但是memcache可通過key為session_id()獲取session_id內容,而 memcached則不能,memcached的key要加上’memc.sess.key.’前綴才可以獲取session_id的內容,由此可知 memcache和memcached保存key為session_id()的方式不一樣。

參考地址:
http://www.oschina.net/question/191760_88446
http://cubstag.blog.163.com/blog/static/139826788201072351259638/

session.save_handler=memcached
session.save_path="127.0.0.1:11211"

tcp://開頭的是memcache擴展的寫法,memchached擴展不需要。

參考地址:http://leo108.com/pid-1900.asp

或者某個目錄下的 .htaccess :

php_value session.save_handler"memcache"
php_value session.save_path "tcp://127.0.0.1:11211"

再或者在某個一個應用中:

ini_set("session.save_handler","memcache");
ini_set("session.save_path","tcp://127.0.0.1:11211");

使用多個 memcached server 時用逗號”,”隔開,並且和Memcache::addServer() 文檔中說明的一樣,可以帶額外的參數”persistent”、”weight”、”timeout”、”retry_interval”等等,類似這樣 的:”tcp://host1:port1?persistent=1&weight=2,tcp://host2:port2″。

Memcache存取session測試

session_start();
if (!isset($_SESSION['TEST'])) {
    $_SESSION['TEST'] = time();
}
 
$_SESSION['TEST3'] = time();
 
echo $_SESSION['TEST'];
echo "\n";
echo $_SESSION['TEST3'];
echo "\n";
echo session_id();

從memcache中取回session數據

$memcache = memcache_connect('localhost',11211); var_dump($memcache->get('19216821213c65cedec65b0883238c278eeb573e077'));

會有看到

string(37)"TEST|i:1177556731;TEST3|i:1177556881;"
這樣的輸出,證明 session 正常工作
用 memcache 來存儲 session 在讀寫速度上會比 files 時快很多,而且在多個服務器需要共用 session 時會比較方便,將這些服務器都配置成使用同一組 memcached 服務器就可以,減少了額外的工作量。缺點是 session 數據都保存在 memory 中,持久化方面有所欠缺,但對 session 數據來說也不是很大的問題。

另外,WS Memcached Session Handler for PHP 提供一種用session_set_save_handler 來利用 memcached 的方法。

memcached 與 magent組合搭建方案示例

magent與memcached 是可以混搭的,不必死板的一個magent s-memcached s-memcached b-memcached

上圖此模型已經能夠很好的解決一個節點,一組服務器的緩存數據服務,但是如果在北方網通架設了一組服務器,同時在南方電信又架設了另外一組服務器,那么這兩組相對獨立的節點之間如何做到數據的同步與共享,基於magent與memcached的解決方案如下:

需要注意的是,兩組magent的配置最好完全一致,比如:

北方的magent配置為:magent s-memcached1 s-memcached2 b-memcached3

那么南方的magent配置也為:magent s-memcached1 s-memcached2 b-memcached3

其順序都是一致的,因為magent在分配key到memcached上時只是簡單的使用散列余數算法。(這是網上部分文章的說法,但根據相關資 料,我覺得此處的算法應該是Consistent Hashing算法(http://blog.csdn.net/sparkliang/article/details/5279393),因此我認為 跟配置順序沒有關系)

當然如果你夠懶,那么你可以直接連接備份magent,因為所有的數據上面都有。

有個特別要注意的地方是:

1.其中一台Memcached死掉,從magent取數據,數據會從備份的Memcached取出,保證用戶不受影響.

2.Memcached重啟復活,由於這兩台Memcached重啟后無數據,因此magent取得的將是空值,盡管備份Memcached還有數據。可采用定時維護服務器,恢復memcached。

3.如果Memcached死掉,備份機同時死掉,那么只能說明你夠倒霉,此時此刻你或許能見到上帝。

緩存與DB的同步

比較保險的做法是:查詢的時候從緩存中取,add、updae、delete的時候同時操作緩存與DB。

當然你也可以定時同步緩存與DB的數據,個人認為不同的業務應該有不同的選擇!

我在實際的應用中是同時使用這兩種方式,比如用戶個人信息之類的內容,就用定時同步的方式

緩存集群的形成歷程

緩存集群不是天生就有的,只有應用場景的發展才會引發對集群的需要。

STEP1:無緩存—>STEP2:單機memcached—>STEP3:memcached集群+請求端分片—>STEP4:memcached集群+單台代理—>STEP5:memcached集群+代理集群—>再以后,就沒有以后了

1~3階段都是很輕松的(很多業務能到3階段已經是規模不小,值得慶幸了);
4階段后期就會遇到各種壓力,要考慮memcached單台失效對后端(很可能是DB或其他持久化存儲)突發壓力的影響;magent的備份服務器是方法 之一,但具體的備份方案需要琢磨,簡單的2倍存儲代價不小;5階段要考慮集群+集群的失效,需要引入DNS/名字服務等更低層的網絡措施;

經驗技巧

最后提出兩個使用Memcache的小技巧,第一個是如果是一個有效分布式存儲的數據,key的取名是很有學問的,這個可以按照項目需要去做,但是 key值不要太長,不會沖突就行。第二個就是每個保存在memcache中的數據不要超過1MB。第三個就是開啟一個Memcache進程設置內存不要太 多也不要太少,按照自己合適設置就行,盡量最大程度提高對硬件的使用,同樣可以采取在一台服務器上開啟多個memcached來分擔一個 memcached並發鏈接的壓力。更多技巧在實際使用長慢慢去總結發現,會發現其實memcahe雖然簡單,但是很好用。

magent能夠消除單點故障問題,但是不能實現負載均衡。如果要實現負載均衡的話,可能還要再研究一下其他工具。

參考資料

Memcached的代理服務器軟件:magent使用小記:http://blog.s135.com/post/393/
一致性hash算法 – consistent hashing:http://blog.csdn.net/sparkliang/article/details/5279393
memcached全面剖析–4. memcached的分布式算法:http://blog.charlee.li/memcached-004/
memcache proxy之memagent介紹分析:http://www.kafka0102.com/2010/01/9.html
Memcached代理軟件magent安裝小結:http://www.elesos.com/index.php?title=Memcached %E4%BB%A3%E7%90%86%E8%BD%AF%E4%BB%B6magent%E5%AE%89%E8%A3%85%E5%B0%8F%E7%BB%93
memcached 和它的代理:http://my.oschina.net/kakablue/blog/187270
M​e​m​c​a​c​h​e​d​內​存​分​析​、​調​優​、​集​群:http://wenku.baidu.com/view/23821cebe009581b6bd9ebc2.html
Linux下安裝搭建Memcached集群環境:http://tim-fly.iteye.com/blog/1756936
Memcached 集群架構方面的問題:http://kb.cnblogs.com/page/69074/
Memagent 負載均衡配置.pptx:http://www.open-open.com/doc/view/97ce1f7d85b7425c9c5bcc09a6bb0b39

 

轉自:http://www.3mu.me/linux%E4%B8%8Bmemcache%E5%88%86%E5%B8%83%E5%BC%8F%E9%83%A8%E7%BD%B2%E6%96%B9%E6%A1%88%E4%B8%8E%E4%BD%BF%E7%94%A8magent%E4%BB%A3%E7%90%86%E5%AE%89%E8%A3%85%E6%90%AD%E5%BB%BAmemcached%E9%9B%86%E7%BE%A4/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM