NoSQL
NoSQL是對非SQL、非傳統關系型數據庫的統稱。
NoSQL一詞誕生於1998年,2009年這個詞匯被再次提出指非關系型、分布式、不提供ACID的數據庫設計模式。
隨着互聯網時代的到來,數據爆發式增長,數據庫技術發展日新月異,要適應新的業務需求。
隨着移動互聯網、物聯網的到來,大數據的技術中NoSQL也同樣重要。
https://db-engines.com/en/ranking
分類
Key-value Store
redis、memcached
Document Store
mongodb、CouchDB
Column Store列存數據庫,Column-Oriented DB
HBase、Cassandra
Graph DB
Neo4j
Time Series 時序數據庫
InfluxDB
Memcached不支持集群,只支持字符串類型、字節流,不支持持久化,不支持buffer緩存,而Redis支持字符串、源地址hash等類型,支持buffer緩存,且支持主從復制、集群、支持持久化等
Memcached只支持能序列化的數據類型,不支持持久化,基於Key-Value的內存緩存系統。
內存分配機制
應用程序運行需要使用內存存儲數據,但對於一個緩存系統來說,申請內存、釋放內存將十分頻繁,非常容易導致大量內存碎片,最后導致無連續可用內存可用。
(1)Memcached采用了Slab Allocator機制來分配、管理內存。
(2)Page:分配給Slab的內存空間,默認為1MB,分配后就得到一個Slab。Slab分配之后內存按照固定字節大小等分成chunk。
(3)Chunk:用於緩存記錄kv值的內存空間。Memcached會根據數據大小選擇存到哪一個chunk中,假設chunk有128bytes、64bytes,數據只有100bytes存儲在128bytes中,存在些浪費。
Chunk最大就是Page的大小,即一個Page中就一個Chunk
(5)Slab Class:Slab按照大小分組,就組成不同的Slab Class
如果有100bytes要存,那么Memcached會選擇上圖中Slab Class 2存儲,因為它是120bytes的Chunk。
Slab之間的差異可以使用Growth Factor控制,默認1.25。
懶過期Lazy Expiration
memcached不會監視數據是否過期,而是在取數據時才看是否過期,過期的把數據有效期限標識為0,並不清除該數據。以后可以覆蓋該位置存儲其它數據。
LRU
當內存不足時,memcached會使用LRU(Least Recently Used)機制來查找可用空間,分配給新紀錄使用。
集群
Memcached集群,稱為基於客戶端的分布式集群。
Memcached集群內部並不互相通信,一切都需要客戶端連接到Memcached服務器后自行組織這些節點,並決定數據存儲的節點。
memcached選項:
修改memcached運行參數,可以使用下面的選項修改/etc/sysconfig/memcached文件
-u username memcached運行的用戶身份,必須普通用戶 -p 綁定的端口,默認11211 -m num 最大內存,單位MB,默認64MB -c num 最大連接數,缺省1024 -d 守護進程方式運行 -f 增長因子Growth Factor,默認1.25 -v 詳細信息,-vv能看到詳細信息 -M 內存耗盡,不許LRU -U 設置UDP監聽端口,0表示禁用UDP
實戰一:基於session共享存儲實現LAMT的會話保持(sticky模式生產中常用)
msm
msm(memcached session manager)提供將Tomcat的session保持到memcached或redis的程序,可以實現高可用。
目前項目托管在Github:https://github.com/magro/memcached-session-manager
支持Tomcat的6.x、7.x、8.x、9.x。
Tomcat的Session管理類,Tomcat版本不同
memcached-session-manager-2.3.2.jar memcached-session-manager-tc8-2.3.2.jar
Session數據的序列化、反序列化類
官方推薦kyro 在webapp中WEB-INF/lib/下
驅動類
memcached(spymemcached.jar) Redis(jedis.jar) # redis的jar包
官網下載依賴的jar包:https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration
將spymemcached.jar、memcached-session-manage、kyro相關的jar文件都放到Tomcat的lib目錄中去,這個目錄是$CATALINA_HOME/lib/ ,對應本次安裝就是/usr/local/tomcat/lib。
asm-5.2.jar kryo-3.0.3.jar kryo-serializers-0.45.jar memcached-session-manager-2.3.2.jar memcached-session-manager-tc8-2.3.2.jar minlog-1.3.1.jar msm-kryo-serializer-2.3.2.jar objenesis-2.6.jar reflectasm-1.11.9.jar spymemcached-2.12.3.jar jedis-3.0.0.jar # redis相關的jar包
sticky模式
1、當請求結束時Tomcat的session會送給memcached備份。即Tomcat session為主session,memcached session為備session,使用memcached相當於備份了一份Session。
2、查詢Session時Tomcat會優先使用自己內存的Session,Tomcat通過jvmRoute發現不是自己的Session,便從memcached中找到該Session,更新本機Session,請求完成后更新memcached。
<t1> <t2> . \ / . . X . . / \ . <m1> <m2>
t1和m1部署在一台主機上,t2和m2部署在同一台。
開始部署session共享會話保持
1、在t0和t1安裝memcached服務
#yum install memcached -y
2、修改t0和t1的配置文件,需要監聽其他地址的IP地址,否則只會監聽本地的IP地址,內存可以設置為1024,最大連接設置為2048
[root@centos-7 yum.repos.d]# cat /etc/sysconfig/memcached PORT="11211" USER="memcached" MAXCONN="2048" #修改最大連接數 CACHESIZE="1024" # 修改內存大小 OPTIONS=""
3、啟動memcached服務,監聽的是11211端口
# systemctl start memcached
4、將依賴的包在官網下載下來並導入到/usr/local/tomcat/lib目錄下:
asm-5.2.jar kryo-3.0.3.jar kryo-serializers-0.45.jar memcached-session-manager-2.3.2.jar memcached-session-manager-tc8-2.3.2.jar minlog-1.3.1.jar msm-kryo-serializer-2.3.2.jar objenesis-2.6.jar reflectasm-1.11.9.jar spymemcached-2.12.3.jar jedis-3.0.0.jar
5、修改tomcat服務的配置文件
特別注意,t0配置中為failoverNodes="n1(memcached1)", t1(tomcat1)配置為failoverNodes="n2(memcached2)"
failoverNodes故障轉移節點,n1是備用節點,n2是主存儲節點。另一台Tomcat將n1改為n2,其主節點是n1,備用節點是n2。
修改t0的配置文件
[root@mysql1 lib]# vim /usr/local/tomcat/conf/context.xml <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:192.168.7.100:11211,n2:192.168.7.101:11211" failoverNodes="n1" #改為n1時,n1為備用節點,優先使用n2的主機節點 requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
修改t1的配置文件
[root@openstack-2 lib]# vim /usr/local/tomcat/conf/context.xml <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:192.168.7.100:11211,n2:192.168.7.101:11211" failoverNodes="n2" #改為n2時,優先使用n1的主節點,n2為備用節點。 requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
6、修改tomcat(0和1)的主配置文件
#vim /usr/local/tomcat/conf/server.xml <Engine name="Catalina" defaultHost="t0.baidu.com" jvmRoute="Tomcat1"> #加上后面的名稱,方便辨認是哪個主機 <Engine name="Catalina" defaultHost="t1.baidu.com" jvmRoute="Tomcat2">
7、修改兩個tomcat的server.xml配置文件
# vim /usr/local/tomcat/conf/server.xml <Engine name="Catalina" defaultHost="t1.baidu.com"> </Host> <Host name="t1.baidu.com" appBase="/data/webapps" autoDeploy="true" > </Host> </Engine>
8、創建t0和t1的測試頁面
# vim /data/webapps/ROOT/index.jsp <%@ page import="java.util.*" %> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>lbjsptest</title> </head> <body> <div>On <%=request.getServerName() %></div> <div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div> <div>SessionID = <span style="color:blue"><%=session.getId() %></span></div> <%=new Date()%> </body> </html>
9、啟動tomcat服務:
# startup.sh
修改httpd服務的配置文件
修改httpd主配置文件
# vim /etc/httpd/conf/httpd.conf 注釋 #DocumentRoot "/var/www/html"
修改httpd的反向代理配置
[root@computer-2 ~]# cat /etc/httpd/conf.d/vhosts.conf <VirtualHost *:80> ServerName node1.baidu.com ProxyRequests Off ProxyVia On ProxyPreserveHost On ProxyPass / balancer://lbtomcats/ ProxyPassReverse / balancer://lbtomcats/ </VirtualHost> <Proxy balancer://lbtomcats> BalancerMember ajp://t0.baidu.com:8009 loadfactor=1 route=Tomcat1 BalancerMember ajp://t1.baidu.com:8009 loadfactor=2 route=Tomcat2 #ProxySet stickysession=ROUTEID </Proxy>
啟動httpd服務
# systemctl start httpd
測試效果:
第一次測試:
第二次測試:
下來模擬memcached的n2宕機,此時t0和t1都轉移到memcached的n1上:
宕機n2:systemctl stop memcached
再次重啟n2的memcached服務,此時Tomcat1就會又去優先到n2進行寫入緩存:
重啟n2的memcached服務:systemctl restart memcached
實戰二:基於session共享存儲實現LNMT的會話保持(sticky模式生產中常用)
1、修改nginx服務器的主配置文件
upstream tomcats { #在http 段配置 server t0.baidu.com:8080 weight=1; server t1.baidu.com:8080 weight=2; } location / { #在server 段配置 proxy_pass http://tomcats; } location ~* \.(jsp|do)$ { proxy_pass http://tomcats; }
只需要將httpd的配置改為nginx配置,upstream轉發到后端服務器,其他的tomcat配置不變、memcached服務配置文件都在上面:
2、測試效果:
此時tomcat1對應的n2和tomcat2對應的n1都是一個session ID,實驗成功:
實戰三:基於session共享存儲(memcached)實現LNMT的會話保持(non-sticky模式)
實現原理
從msm 1.4.0之后開始支持non-sticky模式。
Tomcat session為中轉Session,n1為主session,n2為備session。產生的新的Session會發送給主、備memcached,並清除本地Session。
n1下線,n2轉正。n1再次上線,n2依然是主Session存儲節點。
注意:其他測試頁面在上面已經存在,下面就不在寫入。
1、開始部署,在t0和t1的/usr/local/tomcat/conf/context.xml配置文件中修改
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="n1:192.168.7.100:11211,n2:192.168.7.101:11211" sticky="false" sessionBackupAsync="false" lockingMode="uriPattern:/path1|/path2" requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
2、修改nginx服務器的主配置文件
upstream tomcats { #在http 段配置 server t0.baidu.com:8080 weight=1; server t1.baidu.com:8080 weight=2; } location / { #在server 段配置 proxy_pass http://tomcats; } location ~* \.(jsp|do)$ { proxy_pass http://tomcats; }
3、啟動nginx服務和tomcat服務
# nginx # shutdown.sh # startup.sh
測試效果
此時可以看到,訪問tomcat時,占用的是memcached的n1
模擬此時的n1(memcached)宕機,此時n2就會占用上來,由於n1和n2是同優先級的服務器,此時就算n1啟動起來,也不會再占用到n1的緩存服務器上。
實戰四:基於session共享存儲(redis)實現LNMT的會話保持(non-sticky模式)
1、安裝並配置redis服務
# yum install redis -y # vim /etc/redis.conf #修改redis配置 bind 0.0.0.0 #監聽本地的所有IP地址 # systemctl start redis #啟動redis服務
2、配置tomcat服務
修改tomcat文件時,目前沒有做redis主從復制及集群模式,生產中必須做,此時將IP地址都指向了一個redis的IP地址上
[root@centos-7 ~]# vim /usr/local/tomcat/conf/context.xml <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="redis://192.168.7.100:6379" sticky="false" sessionBackupAsync="false" lockingMode="uriPattern:/path1|/path2" requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" />
創建t0和t1的測試頁面
# vim /data/webapps/ROOT/index.jsp <%@ page import="java.util.*" %> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>lbjsptest</title> </head> <body> <div>On <%=request.getServerName() %></div> <div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div> <div>SessionID = <span style="color:blue"><%=session.getId() %></span></div> <%=new Date()%> </body> </html>
3、修改nginx服務器的主配置文件
upstream tomcats { #在http 段配置 server t0.baidu.com:8080 weight=1; server t1.baidu.com:8080 weight=2; } location / { #在server 段配置 proxy_pass http://tomcats; } location ~* \.(jsp|do)$ { proxy_pass http://tomcats; }
啟動nginx和tomcat服務
# nginx # shutdown.sh # startup.sh
測試效果:
兩個主機的session ID都一致,實驗成功:
總結
通過多組實驗,使用不同技術實現了session持久機制
1. session綁定,基於IP或session cookie的。其部署簡單,尤其基於session黏性的方式,粒度小,對負載均衡影響小。但一旦后端服務器有故障,其上的session丟失。
2. session復制集群,基於tomcat實現多個服務器內共享同步所有session。此方法可以保證任意一台后端服務器故障,其余各服務器上還都存有全部session,對業務無影響。但是它基於多播實現心跳,TCP單播實現復
制,當設備節點過多,這種復制機制不是很好的解決方案。且並發連接多的時候,單機上的所有session占據的內存空間非常巨大,甚至耗盡內存。
3. session服務器,將所有的session存儲到一個共享的內存空間中,使用多個冗余節點保存session,這樣做到session存儲服務器的高可用,且占據業務服務器內存較小。是一種比較好的解決session持久的解決方案。
以上的方法都有其適用性。生產環境中,應根據實際需要合理選擇。
不過以上這些方法都是在內存中實現了session的保持,可以使用數據庫或者文件系統,把session數據存儲起來,實現持久化。
這樣服務器重啟后,也可以重新恢復session數據。不過session數據是有時效性的,是否需要這樣做,視情況而定。