SQL (Structured Query Language) 數據庫,指關係型數據庫。主要表明:SQL Server,Oracle,MySQL,PostgreSQL。javascript
NoSQL(Not Only SQL)泛指非關係型數據庫。主要表明:MongoDB,Redis,CouchDB。php
k-v形式:memcached、redis適合存儲用戶信息,例如會話、配置文件、參數、購物車等。這些信息通常和ID(主鍵)掛鉤,這種情景下鍵值數據庫是個很好的選擇; 文檔數據庫:mongodb將數據以文檔的形式存儲,每一個文檔都是一系列數據項的集合。每一個數據項都有一個名稱與對應的值,值既能夠是簡單的數據類型,如字符串、數字和日期等;也能夠是複雜的類型,若有序列表和關聯對象。數據存儲的最小單位是文檔,同一個表中存儲的文檔屬性能夠是不一樣的,數據可使用xml、json或者jsonb等多種形式存儲 列存儲:Hbase 圖:Neo4j、Infinite Graph、OrientDB
隨着互聯網的不斷髮展,各類類型的應用層出不窮,在這個雲計算的時代,對技術提出了更多的需求,主要體如今下面這四個方面:css
1. 低延遲的讀寫速度:應用快速地反應能極大地提高用戶的滿意度; 2. 海量的數據和流量:對於搜索這樣大型應用而言,須要利用PB級別的數據和能應對百萬級的流量; 3. 大規模集羣的管理:系統管理員但願分佈式應用能更簡單的部署和管理; 4. 龐大運營成本的考量:IT經理們但願在硬件成本、軟件成本和人力成本可以有大幅度地下降。
目前世界上主流的存儲系統大部分仍是採用了關係型數據庫,其主要有一下優勢:html
1. 事務處理—保持數據的一致性; 2. 因爲以標準化爲前提,數據更新的開銷很小(相同的字段基本上只有一處); 3. 能夠進行Join等複雜查詢。
雖然關係型數據庫已經在業界的數據存儲方面佔據不可動搖的地位,可是因爲其天生的幾個限制,使其很難知足上面這幾個需求:java
1. 擴展困難:因爲存在相似Join這樣多表查詢機制,使得數據庫在擴展方面很艱難; 2. 讀寫慢:這種狀況主要發生在數據量達到必定規模時因爲關係型數據庫的系統邏輯很是複雜,使得其很是容易發生死鎖等的併發問題,因此致使其讀寫速度下滑很是嚴重; 3. 成本高:企業級數據庫的License價格很驚人,而且隨着系統的規模,而不斷上升; 4. 有限的支撐容量:現有關係型解決方案還沒法支撐Google這樣海量的數據存儲。
爲了解決這些問題,NoSQL由此被設計出來,它有如下優缺點:node
優勢: 1. 簡單的擴展:典型例子是Cassandra,因爲其架構是相似於經典的P2P,因此能經過輕鬆地添加新的節點來擴展這個集羣; 2. 快速的讀寫:主要例子有Redis,因爲其邏輯簡單,並且純內存操做,使得其性能很是出色,單節點每秒能夠處理超過10萬次讀寫操做; 3. 低廉的成本:這是大多數分佈式數據庫共有的特色,由於主要都是開源軟件,沒有昂貴的License成本。
缺點: 1. 不提供對SQL的支持:若是不支持SQL這樣的工業標準,將會對用戶產生必定的學習和應用遷移成本; 2. 支持的特性不夠豐富:現有產品所提供的功能都比較有限,大多數NoSQL數據庫都不支持事務,也不像MS SQL Server和Oracle那樣能提供各類附加功能,好比BI和報表等; 3. 現有產品的不夠成熟:大多數產品都還處於初創期,和關係型數據庫幾十年的完善不可同日而語。
並非任何場景,NoSQL都要優於關係型數據庫,在這些場景它更加給力:mysql
1. 數據庫表schema常常變化。例如在線商城,NoSQL應用在這種場景,能夠極大提高DB的可伸縮性,開發人員能夠將更多的精力放在業務層; 2. 數據庫表字段是複雜數據類型。對於複雜數據類型,NoSQL以json方式存儲,提供了原生態的支持,在效率方面遠遠高於傳統關係型數據庫; 3. 高併發數據庫請求。此類應用常見於web2.0的網站,不少應用對於數據一致性要求很低,而關係型數據庫的事務以及大表join反而成了」性能殺手」; 4. 海量數據的分佈式存儲。海量數據的存儲若是選用大型商用數據,如Oracle,那麼整個解決方案的成本是很是高的,要花不少錢在軟硬件上。NoSQL分佈式存儲,能夠部署在廉價的硬件上,是一個性價比很是高的解決方案。
其實NoSQL數據庫僅僅是關係數據庫在某些方面(性能,擴展)的一個彌補,單從功能上講,NoSQL的幾乎全部的功能,在關係數據庫上都可以知足,因此選擇NoSQL的緣由並不在功能上。nginx
因此,咱們通常會把NoSQL和關係數據庫進行結合使用,各取所長,須要使用關係特性的時候咱們使用關係數據庫,須要使用NoSQL特性的時候咱們使用NoSQL數據庫,各得其所。web
Memcached是國外社區網站LiveJournal團隊開發,可以將數據存儲在內存中,目的是爲了經過緩存數據庫查詢結果,減小數據庫訪問次數,從而提升動態web站點性能。redis
Memcached官網,memcached有如下特色:
數據結構簡單(k-v),數據存放在內存裏 多線程 基於C/S架構,協議簡單 基於libevent的事件處理 主內存存儲處理(slab allocation) 數據過時方式:Lazy Expiration和LRU
slab allocation的原理:
將分配的內存分隔成各類尺寸的塊(chunk),並把尺寸相同的塊分紅組(chunk的集合),各個chunk集合被稱爲slab; memcached的內存分配以page爲單位,page默認值爲1M,能夠在啓動時經過-I參數來指定; slab是由多個page組成的,page按照指定大小切割成多個chunk。即chunk組成page,page組成slab。
chunk的大小差別由growth factor控制:
memcached在啓動時經過 -f 選項能夠指定growth factor因子。該值控制chunk大小的差別。默認值爲1.25; 經過memcached-tool命令查看指定memcached實例的不一樣slab狀態,能夠看到個ltem所佔大小(chunk大小)爲1.25。
Memcached的數據過時方式有兩種:
memcached內部不會監視記錄是否過時,而是在get時查看記錄的時間戳,檢查記錄是否過時。 這種技術稱爲lazy expiration,主要特色是memcached不會在過時監視上耗費CPU資源。
memcached會優先使用已超時的記錄的空間,但即使如此,也會發生追加新紀錄時空間不足的狀況, 此時就要使用名爲「Least Recently Used(LRU)」機制來分配空間,即刪除「最近最少使用」的記錄的機制。 所以,當內存空間不足(沒法從slab class獲取到新的空間時),就從最近未被使用的記錄中搜索, 並將其空間分配給新的記錄。從緩存的實用角度來看,該模型十分理想。
# yum install -y libevent libmemcached memcached #安裝memcached須要先安裝libevent
# systemctl start memcached# ps aux |grep memcachedmemcach+ 28622 0.0 0.1 344080 1656 ? Ssl 16:17 0:00 /usr/bin/memcached -u memcached -p 11211 -m 64 -c 1024 # netstat -lntp |grep 11211tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 28622/memcached tcp6 0 0 :::11211 :::* LISTEN 28622/memcached
上面,
-u 指定運行memcached服務的用戶 -p 指定監聽端口 -m 指定memcached分配內存 -c 指定最大併發數
# vim /etc/sysconfig/memcachedPORT="11211"USER="memcached"MAXCONN="1024"CACHESIZE="64"OPTIONS=""
除了上面幾個參數以外,memcached還有如下經常使用參數:
-l 指定監聽IP -d 以守護進程(daemon)啓動
memcached啓動以後,咱們能夠查看memcached服務的狀態,有幾種方式。
# memcached-tool 127.0.0.1:11211 stats #這裏是stats,而不是status#127.0.0.1:11211 Field Value accepting_conns 1 auth_cmds 0 auth_errors 0 bytes 0 bytes_read 7 bytes_written 0 cas_badval 0 cas_hits 0 cas_misses 0 cmd_flush 0 cmd_get 0 cmd_set 0 cmd_touch 0 conn_yields 0 connection_structures 11 curr_connections 10 curr_items 0 #關注這個數據,表示目前在memcached中的項目 decr_hits 0 decr_misses 0 delete_hits 0 delete_misses 0 evicted_unfetched 0 evictions 0 expired_unfetched 0 get_hits 0 #關注這個數據,表示命中了多少,命中率就是命中數除以項目數 get_misses 0 hash_bytes 524288 hash_is_expanding 0 hash_power_level 16 incr_hits 0 incr_misses 0 libevent 2.0.21-stable limit_maxbytes 67108864 listen_disabled_num 0 pid 28622 pointer_size 64 reclaimed 0 reserved_fds 20 rusage_system 0.049655 rusage_user 0.019310 threads 4 time 1534840454 total_connections 11 total_items 0 touch_hits 0 touch_misses 0 uptime 985 version 1.4.15
# yum install -y nc# echo stats |nc 127.0.0.1 11211STAT pid 28622 STAT uptime 1517 STAT time 1534840986 STAT version 1.4.15 STAT libevent 2.0.21-stable STAT pointer_size 64 STAT rusage_user 0.027098 STAT rusage_system 0.067747 STAT curr_connections 10 STAT total_connections 12 STAT connection_structures 11 STAT reserved_fds 20 STAT cmd_get 0 STAT cmd_set 0 STAT cmd_flush 0 STAT cmd_touch 0 STAT get_hits 0 STAT get_misses 0 STAT delete_misses 0 STAT delete_hits 0 STAT incr_misses 0 STAT incr_hits 0 STAT decr_misses 0 STAT decr_hits 0 STAT cas_misses 0 STAT cas_hits 0 STAT cas_badval 0 STAT touch_hits 0 STAT touch_misses 0 STAT auth_cmds 0 STAT auth_errors 0 STAT bytes_read 13 STAT bytes_written 1025 STAT limit_maxbytes 67108864 STAT accepting_conns 1 STAT listen_disabled_num 0 STAT threads 4 STAT conn_yields 0 STAT hash_power_level 16 STAT hash_bytes 524288 STAT hash_is_expanding 0 STAT bytes 0 STAT curr_items 0 STAT total_items 0 STAT expired_unfetched 0 STAT evicted_unfetched 0 STAT evictions 0 STAT reclaimed 0 END
# memstat --servers=127.0.0.1:11211Server: 127.0.0.1 (11211) pid: 28622 uptime: 1802 time: 1534841271 version: 1.4.15 libevent: 2.0.21-stable pointer_size: 64 rusage_user: 0.041055 rusage_system: 0.071847 curr_connections: 10 total_connections: 13 connection_structures: 11 reserved_fds: 20 cmd_get: 0 cmd_set: 0 cmd_flush: 0 cmd_touch: 0 get_hits: 0 get_misses: 0 delete_misses: 0 delete_hits: 0 incr_misses: 0 incr_hits: 0 decr_misses: 0 decr_hits: 0 cas_misses: 0 cas_hits: 0 cas_badval: 0 touch_hits: 0 touch_misses: 0 auth_cmds: 0 auth_errors: 0 bytes_read: 30 bytes_written: 2071 limit_maxbytes: 67108864 accepting_conns: 1 listen_disabled_num: 0 threads: 4 conn_yields: 0 hash_power_level: 16 hash_bytes: 524288 hash_is_expanding: 0 bytes: 0 curr_items: 0 total_items: 0 expired_unfetched: 0 evicted_unfetched: 0 evictions: 0 reclaimed: 0
# yum install -y telnet# telnet 127.0.0.1 11211Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'.
set key2 0 30 2 #key2表示ID,0爲標誌,30表示過時時間爲30s,2表示存儲的字節數爲212 STORED #STORED表示value 12 已經存儲set key1 0 30 3 #ID爲key1,設置valueabc STORED get key2 #查看key2的valueVALUE key2 0 2 12 END get key1 #查看key1的valueVALUE key1 0 3 abc END get key2 #過一段時間以後再次查看END #發現value已經消失,這是由於已通過期了get key1 END
\r\n\r\n # \r\n在window下表示Enter鍵是一個16位的無符號的整數(以十進制的方式表示)。該標誌將和存儲的數據一塊兒存儲,並在客戶端get數據時返回。 客戶端能夠將此標誌用做特殊用途,此標誌對服務器來講是不透明的。爲過時的時間。若爲0表示存儲的數據永遠不過時(但可被服務器算法:LRU等替換); 若不爲0(unix時間或者距離此時的秒數),當過時後,服務器能夠保證用戶得不到該數據(以服務器時間爲標準)須要存儲的字節數,當用戶但願存儲空數據時能夠爲0須要存儲的內容,輸入完成後,客戶端須要加上\r\n(直接點擊Enter)做爲結束標誌能夠是set,add,replace set表示按照相應的存儲該數據,沒有的時候增長,有的時候覆蓋 add表示按照相應的添加該數據,可是若是該已存在則會操做失敗 replace表示按照相應的替換數據,可是若是該不存在則會操做失敗客戶端須要保存數據的
set key3 1 110 4 1234 STORED replace key3 1 0 5 abcde STORED get key3 VALUE key3 1 5 abcde END
delete key3 DELETED get key3 END
Tips:假如輸入錯誤是直接點擊Backspace是沒用的,能夠按Ctrl+Backspace來刪除輸入的錯誤。
若是想要重啓memcached服務,那在重啓以前,最好將數據導出一下,重啓完以後再導入進去。
set name 1 0 6 lzxlzx STOREDset psd 1 0 5 12345 STOREDset age 1 0 2 22 STORED ^] #輸入Ctrl+]telnet> quit #再輸入quit退出Connection closed.
# memcached-tool 127.0.0.1:11211 dump > data.txtDumping memcache contents Number of buckets: 1 Number of items : 3 Dumping bucket 1 - 3 total items# cat data.txtadd psd 1 1534853776 5 12345 add name 1 1534853776 6 lzxlzx add age 1 1534853776 2 22 #導出來的數據帶有時間戳,由於系統在你建立數據的時候就已經加上了時間戳,以前沒有的數據是由於已通過期了
# nc 127.0.0.1 11211 < data.txtNOT_STORED NOT_STORED NOT_STORED #提示NOT_STORED,這是由於裏面的數據已經有了,並且data.txt裏面是add,它不會覆蓋已經存在的數據# systemctl restart memcached #數據存在內存中,重啓服務可讓以前數據消失# nc 127.0.0.1 11211 < data.txtSTORED STORED STORED# telnet 127.0.0.1 11211Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'.get name END get psd END get age END #能夠看到,查看剛剛導入的數據,發現沒有value# date -d '+1 hour' +%s1534862308# vim data.txtadd psd 1 1534862308 5 #修改時間戳,留一個以前的時間戳做對比12345 add name 1 1534862308 6 lzxlzx add age 1 1534853776 2 22# systemctl restart memcached# nc 127.0.0.1 11211 < data.txtSTORED STORED STORED# telnet 127.0.0.1 11211Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'.get age END get name VALUE name 1 6 lzxlzx END get psd VALUE psd 1 5 12345 END #能夠看到,修改了時間戳以後就能夠查看value了,沒修改的就仍是查看不到,由於已通過期
# cd /usr/local/src/# wget http://www.apelearn.com/bbs/data/attachment/forum/memcache-2.2.3.tgz# tar zxf memcache-2.2.3.tgz # cd memcache-2.2.3# /usr/local/php-fpm/bin/phpize Configuring for: PHP Api Version: 20131106 Zend Module Api No: 20131226 Zend Extension Api No: 220131226 #這裏可能提示要安裝autoconf,yum安裝便可# ./configure --with-php-config=/usr/local/php-fpm/bin/php-config# echo $?0# make# echo $?0# make install Installing shared extensions: /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/# ls /usr/local/php-fpm/lib/php/extensions/no-debug-non-zts-20131226/memcache.so opcache.a opcache.so #有memcache.so文件
# vim /usr/local/php-fpm/etc/php.ini #添加下面一行extension=memcache.so;session.save_handler = files #前面增長分號將該行註銷# /usr/local/php-fpm/bin/php -m #查看模塊[PHP Modules]Core ctypecurldatedom ereg exif fileinfo filterftpgdhashiconvjson libxml mbstring mcrypt memcache #有這個模塊就說明成功mysql openssl pcre PDO pdo_sqlite Phar posix Reflection session SimpleXML soap SPL sqlite3 standard tokenizer xml xmlreader xmlwriter zlib[Zend Modules]
# curl www.apelearn.com/study_v2/.memcache.txt > 1.php 2>/dev/null# cat 1.php<?php //鏈接Memcache Memcache$mem = new Memcache;$mem->connect("localhost", 11211);//保存數據$mem->set('key1', 'This is first value', 0, 60);$val = $mem->get('key1');echo "Get key1 value: " . $val ."
";//替換數據$mem->replace('key1', 'This is replace value', 0, 60);$val = $mem->get('key1');echo "Get key1 value: " . $val . "
";//保存數組數據$arr = array('aaa', 'bbb', 'ccc', 'ddd');$mem->set('key2', $arr, 0, 60);$val2 = $mem->get('key2');echo "Get key2 value: ";print_r($val2);echo "
";//刪除數據$mem->delete('key1');$val = $mem->get('key1');echo "Get key1 value: " . $val . "
";//清除全部數據$mem->flush();$val2 = $mem->get('key2');echo "Get key2 value: ";print_r($val2);echo "
";//關閉鏈接$mem->close();?># /usr/local/php-fpm/bin/php 1.php Get key1 value: This is first value<br>Get key1 value: This is replace value<br>Get key2 value: Array( [0] => aaa [1] => bbb [2] => ccc [3] => ddd #有這樣的數聽說明已經支持memcached擴展)<br>Get key1 value: <br>Get key2 value: <br>
在作了負載均衡的同時,如何讓用戶的session保存在同一臺服務器上呢?這就須要在memcached中作些修改。
# vim /usr/local/php-fpm/etc/php-fpm.conf #添加下面兩行配置php_value[session.save_handler] = memcache php_value[session.save_path] = " tcp://127.0.0.1:11211 "
# vim session.php #寫入下面內容<?php session_start();if (!isset($_SESSION['TEST'])) {$_SESSION['TEST'] = time();}$_SESSION['TEST3'] = time();print $_SESSION['TEST'];print "
";print $_SESSION['TEST3'];print "
";print session_id();?># cat /usr/local/nginx/conf/nginx.conf #查看nginx配置文件user nobody nobody;worker_processes 2;error_log /usr/local/nginx/logs/nginx_error.log crit;pid /usr/local/nginx/logs/nginx.pid;worker_rlimit_nofile 51200;events{ use epoll; worker_connections 6000;}http{ include mime.types; default_type application/octet-stream; server_names_hash_bucket_size 3526; server_names_hash_max_size 4096; log_format combined_realip '$remote_addr $http_x_forwarded_for [$time_local]' ' $host "$request_uri" $status' ' "$http_referer" "$http_user_agent"'; sendfile on; tcp_nopush on; keepalive_timeout 30; client_header_timeout 3m; client_body_timeout 3m; send_timeout 3m; connection_pool_size 256; client_header_buffer_size 1k; large_client_header_buffers 8 4k; request_pool_size 4k; output_buffers 4 32k; postpone_output 1460; client_max_body_size 10m; client_body_buffer_size 256k; client_body_temp_path /usr/local/nginx/client_body_temp; proxy_temp_path /usr/local/nginx/proxy_temp; fastcgi_temp_path /usr/local/nginx/fastcgi_temp; fastcgi_intercept_errors on; tcp_nodelay on; gzip on; gzip_min_length 1k; gzip_buffers 4 8k; gzip_comp_level 5; gzip_http_version 1.1; gzip_types text/plain application/x-javascript text/css text/htm application/xml; server { listen 80; server_name localhost; index index.html index.htm index.php; root /usr/local/nginx/html; #將上面寫好的腳本放到這個目錄下 location ~ \.php$ { include fastcgi_params; fastcgi_pass unix:/tmp/php-fcgi.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /usr/local/nginx/html$fastcgi_script_name; } }}# mv session.php /usr/local/nginx/html/ #移動到/usr/local/nginx/html/目錄下
# ls /tmp/ks-script-kWjJSk php-fcgi.sock mysql.sock systemd-private-65239b999e6a467d80882d3bafffb812-chronyd.service-ILuCrK pear yum.log# curl localhost/session.php #訪問一下session.php1532089311<br><br>1532089311<br><br>rpqvi8bd8hnkjrei5gdak50jh4 #產生記錄# ls /tmp/ #再次查看/tmp目錄,發現多了一個session記錄ks-script-kWjJSk sess_rpqvi8bd8hnkjrei5gdak50jh4 mysql.sock systemd-private-65239b999e6a467d80882d3bafffb812-chronyd.service-ILuCrK pear yum.log php-fcgi.sock# curl localhost/session.php #再訪問一次1532091866<br><br>1532091866<br><br>o8225a4bqqfnf5oqsa7u3fl776# telnet 127.0.0.1 11211Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'.get o8225a4bqqfnf5oqsa7u3fl776 #這裏根據鍵名能夠查到它的value,說明存儲在memcached中VALUE o8225a4bqqfnf5oqsa7u3fl776 0 37 TEST|i:1532091866;TEST3|i:1532091866;END
至此,就實現了在負載均衡地狀況下,將用戶session保存在同一服務器上。
更多資料參考: