百度網盤javascript
提取碼:qhhv css
問題分析:電商和咱們平時app中,90% 以上都是數據讀取操做,在海量數下,數據庫最後可能成爲高併發的瓶頸,所以減小數據庫交互是首先須要考慮的事情。可是要區分靜態數據和動態數據。長期不變的數據,好比商品詳情,圖片,介紹等適合作緩存,可是評論就不適合作緩存。html
查詢一次數據庫後,把商品詳情,圖片,介紹等放入redis,而後下次redis有的話直接從reids查詢,避免再次查數據庫。
具體切換到 step2-靜態數據優化 分支java
git checkout step2-靜態數據優化
安裝redisnginx
docker pull redis; docker run -d --name redis1 -p 6379:6379 redis --requirepass "123456"
安裝完redis,對應在yml中修改本身的redis配置,訪問下面地址,查看redis,就會發現redis中緩存了商品相關信息,具體實現,查看代碼,很簡單。git
http://localhost:8080/good?gid=2000
頁面靜態化是指把動態頁面,jsp,freemarker等爲每個商品生成一個html靜態頁面。動態數據例如評論就在html頁面用ajax異步獲取。這樣,就直接訪問html避免了頁面數據查詢,解析的過程。web
總結:http://localhost/page/2000.html這裏的流程
是首先去容器內部/usr/share/nginx/html/去找html文件,而後實際上是訪問到了掛載在本地生成html的目錄,而後html裏面發起ajax請求去獲取評論,實際是經過nginx把請求經過upstream轉發到本地。ajax
--- nginx docker pull nginx; docker run -d --name nginx -p 80:80 -v /Users/along/websoft/nginx:/etc/nginx/conf.d -v /Users/along/Desktop/template:/usr/share/nginx/html nginx 上面啓動腳本意思是:映射80端口,而後掛載配置文件目錄和放html的目錄到nginx裏面 啓動腳本和html位置在要和上面啓動命令中的一致。 --- nginx 腳本 #由於容器內部須要訪問到外部的接口,因此須要在容器內容用ip+端口訪問本地接口 upstream seckill { server 192.168.5.3:8080; } server { listen 80; server_name localhost; #把接口轉發到本地起的項目,個人是192.168.5.3:8080; location / { proxy_pass http://seckill; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #頁面轉發地址是容器內部地址 location /page { index index.html; alias /usr/share/nginx/html/; } } 監聽80端口,訪問/放轉發到本地接口,訪問page的時候,定位到nginx的html放置目錄,而後以前掛載過這個目錄,就能訪問到本機的掛載目錄。
兩種方案總結:redis
使用redis以前的通常作法是,查詢數據庫,若是剩餘大於0,就搶到商品,並把剩餘數量減一,並更新數據庫。算法
int num = goodDao.selectRate(num) ; if(num>0){ //處理生成訂單邏輯 num = num -1; //更新數據 }
可是很明顯,查詢數量和更新數量以前是有時差的,有的請求執行到了生成訂單邏輯,東西搶到了,可是沒來得及更新數據庫,可是有的請求在這時獲取了剩餘數量,那麼就會超賣。
選取redis由於它是單線程模型,內存存儲,官網宣稱支持10w qps。並且天生分佈式支持。
邏輯流程
t_promotion_seckill
操做流程:
t_promotion_seckill
, 若是掃不到,請查看sql,修改數據的狀態爲0在搶購之後,每每會發起存數據庫,支付等操做,可是很明顯,以前的從redis中取商品,並添加中獎人到redis這個操做是很快的,可是訂單入庫,支付等操做是很慢的。假設處理取商品,存中獎人每秒能夠處理1000,可是處理訂單,支付等一秒處理100個,那麼,若是是一連串操做,很明顯,後面瓶頸,形成前面操做等待。嚴重的狀況,因爲支付過慢崩潰,致使前面一系列流程所有崩潰。
總而言之就是前臺業務處理能力和後臺業務能力不對稱所致使的
由於能夠分離業務,前臺業務處理快,儘管處理,而後後面生成訂單,支付等在mq中按本身能處理的量異步處理。
rabbitMQ是使用Erlang開發,也有本身的虛擬機,編譯後處處運行,並且編寫分佈式應用簡單。
exchange-order
的交換機,而且建立一個queue-order
的隊列,把他們綁定docker pull rabbitmq; docker run -d -p 15672:15672 -p 5672:5672 -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin --name rabbitmq rabbitmq
用admin和admin打開loaclhost:5672.
LoadBalance:負載均衡,把任務分配到多個服務器上進行處理,進而提升效率,縮短執行時間。
當一臺機器性能到達極限的狀況下,橫向拓展機器的架構是很是好的,能在不改動代碼的狀況下成倍的提高效率。
step5-nginx負載均衡
分支,其中新增了一個 LBController
測試負載均衡的控制器。localhost/LB
這個地址,會發現,請求到不一樣的端口。我比較喜歡使用權重策略,基本都是根據服務器性能來分配。
#nginx.conf,配置中的server是本地ip,使用權重的策略 upstream lb { #least_conn ; 最少鏈接 #ip hash ; ip策略 #權重 server 192.168.5.3:8081 weight=4; server 192.168.5.3:8082 weight=1; server 192.168.5.3:8083 weight=2; } location / { proxy_pass http://lb; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } nginx在docker中的啓動腳本和上面相同。
在部署的多個服務中若是使用session傳遞數據,可能存在獲取不到的狀況,由於假設在8081中執行登錄,session只會存在8081這個服務中,可是下次請求分發到8082或者8083就獲取不到session了。
step6-解決各個服務間session不一樣步問題
分支localhost/login?u=along
,而後在屢次請求localhost/check
發現,有時候能獲取到session,有時不能獲取到。像js,css,圖片,字體等靜態資源,他們都是一個個的url,每次訪問的tamcat都會進行url解析和綁定。可是上線之後,它們幾乎是不會修改的。因此在高併發的狀況下很浪費資源。
nginx區分靜態資源和接口url,把url接口送日後端服務器處理,靜態資源在nginx端緩存處理。
主要是修改nginx的配置,配置以下
#在nginx容器內的/home下面定義緩存文件夾。並設定2層目錄,緩存大小以及過時時間。 proxy_temp_path /home/nginx-temp; proxy_cache_path /home/nginx-cache levels=1:2 keys_zone=lb-cache:100m inactive=7d max_size=20g; upstream lb { #least_conn ; 最少鏈接 #ip hash ; ip策略 #權重 server 192.168.5.3:8081 weight=4; server 192.168.5.3:8082 weight=1; server 192.168.5.3:8083 weight=2; } #用正則匹配靜態資源,~*是不區分大小寫。 location ~* \.(gif|jpg|css|png|js|woff|html)(.*){ proxy_pass http://lb; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #使用上面定義的緩存地址 proxy_cache lb-cache; proxy_cache_valid 200 302 24h; proxy_cache_valid 301 5d; proxy_cache_valid any 5m; expires 90d; } location / { proxy_pass http://lb; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
而後重啓nginx就行了,訪問之後,進入容器
docker exec -it nginx /bin/bash cd /home/nginx-cache 若是上面的文件夾出現了兩層目錄的靜態文件,說明設置成功。
當靜態資源被壓縮後,下降了後端tomcat的壓力,可是在實際開發過程當中,大量的壓力不在於處理速度,而是在於帶寬。帶寬決定了下載的總速度,在總速度不變的狀況下,資源傳到瀏覽器的大小約小越好。越快下載完資源,卡頓的越少。
帶寬是網絡中某一點到另外一點所能經過的"最高數據率",也就是瞬時最高的下載速度。
關於帶寬和下載速度:首先了解一下存儲的單位換算
1M = 10^6; bits換成B除以8,B換成kb除以1024 1M bits/s = 1000000bits/s = 125000 B/s ≈ 128kb/s
nginx將靜態資源打包成gzip傳給瀏覽器,而後瀏覽器解壓縮gizp(這一步瀏覽器自動完成)獲取到資源文件。最少能較少30%內存,最多減小80%的內存損耗。
#打開gzip配置 gzip on; gzip_min_length 1k; gzip_types text/plain application/javascript text/css application/x-javascript font/woff; #禁止IE 1-6 gzip_disable "MSIE [1-6]\."; gzip_buffers 32 4k; #壓縮級別1-9,選1就好了,大小差異不大 gzip_comp_level 1; #在nginx容器內的/home下面定義緩存文件夾。並設定2層目錄,緩存大小以及過時時間。 proxy_temp_path /home/nginx-temp; proxy_cache_path /home/nginx-cache levels=1:2 keys_zone=lb-cache:100m inactive=7d max_size=20g; upstream lb { #least_conn ; 最少鏈接 #ip hash ; ip策略 #權重 server 192.168.5.3:8081 weight=4; server 192.168.5.3:8082 weight=1; server 192.168.5.3:8083 weight=2; } #用正則匹配靜態資源,~*是不區分大小寫。 location ~* \.(gif|jpg|css|png|js|woff|html)(.*){ proxy_pass http://lb; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #使用上面定義的緩存地址 proxy_cache lb-cache; proxy_cache_valid 200 302 24h; proxy_cache_valid 301 5d; proxy_cache_valid any 5m; expires 90d; } location / { proxy_pass http://lb; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
在docker重啓nginx。訪問頁面,當看到瀏覽器,檢查看到css,js等的response header中,編碼爲gzip。就說明設置成功了。
對靜態文件完成了gzip壓縮,可是對圖片等已經被壓縮過的資源gzip傳輸效果並很差,因此對圖片的帶寬消問題並無解決。
圖片能夠考慮使用第三方cdn解決帶寬問題。
cdn全稱Content dekivery network,就是內容分發網絡。
例如中國很大,北京和深圳就隔者2000多千米,若是北京訪問深圳的網絡,必然延時很高。cnd就是把內容放在一臺中心服務器上,而後各地有不少節點服務器,中心服務器會把內容同步到各地的節點服務器,而後就進訪問資源。
能夠買阿里雲,騰訊雲,七牛的cdn服務。
主要流程是買服務,下載客戶端,把圖片等資源上傳到客戶端,自動同步,而後爲oss配置cdn,進行域名解析。就能經過域名訪問到圖片,最後就去修改項目中靜態資源的路徑。
有些人會惡意一直訪問網站,甚至用腳本去刷頁面。
因此在必定時間內只容許一個用戶訪問固定的次數,一旦超過了就不容許訪問。
會有人用爬蟲,爬網站,利用超連接分析內容,提取網站的重要信息,不只拷貝走了數據,並且,還很是消耗服務器資源。
step7-流量防刷與反爬蟲
分支localhost/lb
,並屢次刷新終於寫完啦。這篇文章主要是對代碼和網絡等幾個層面作了優化,主要使用了nginx,redis,rabbitMQ等熱門工具,但願對各位有幫助,若是有問題,歡迎指正,一塊兒討論。