.net throw ex 與 throw 的不同之處(重新理解)
以下是看的出來的例子..
以下是看的出來的例子..
實驗worked!!
記錄一下
今天同事忘了下where條件
不小心誤更新了四千多筆的資料表
一時間協助查詢解決方法,畢竟不是dba
操作實務不足,也不敢馬上給指令
深怕把資料庫搞壞,連現行資料都弄不回來
事後,經過比較各個blog,MSDN,還有跟同事的討論後,實證驗正過以下做法可行,足以做為SOP
也同時花了點時間理解原理
發現原來我認知的誤區就是我以為資料庫靠transaction log就可以rollback回去過去時間點(減法)
但其實關鍵點反而是用加法在還原時間點加回來交易紀錄,見上圖所示,我寫在黑板記錄一下
看參考部落格時還想說為啥要先restore 資料..後來才想通
因此語法真的誤刪(人人似乎都有這個黑歷史)的話,別緊張,Follow以下SOP,應該可以救的回來,前提是資料庫是在完整模式下
範例資料:
原本的資料
不小心誤刪了或漏下了where條件
這個時候,不要緊張,先找到上一次完整備份的時間點
以我的範例是8:55分
Step 0.網站停機或下線 (注意,千萬不能第一時間又做了一次完整備份)
避免寫入更多資料,複原時會遺失更多資料
Step1.切換單人模式並重新離線上線(確保資料庫是無人連線)
這時,你的DB應該會是在還原模式下:
注意:還原計畫只能包含資料,不能勾選到剛剛的交易記錄
還原完整備份的bak時,復原狀態要選擇Restore With No Recovery
還原成功後,再進行將資料庫切回多人模式
檢查資料,已經回復了,可喜可賀
想法有誤的話,歡迎大家回饋指教
參考blog:
https://kknews.cc/zh-tw/code/q4lj5x8.html
https://blog.miniasp.com/post/2010/04/21/SQL-Server-Full-Differential-Transaction-Backup
最近2個月又重回C#懷抱了,昨晚追查一個底層ThreadPool Exception,然後會造成w3wp的Exception, 會造成集區重啟的異常
後來發現有一個非同步呼叫射後不理的部分,並沒有合理的包裝例外,然後又會造成.net framework底層無法Handle的例外
Legacy Code的用法是改一半的非同步呼叫方法
後來查詢多方說法後(StackOverFlow網友建議),建議這種射後不理的整合寫法,可以採用TPL(工作型非同步執行庫)
正規TPL的非同步方法在Handle的時候如下:
其例外處理範例,因為Task的例外會拋出來的是AggregateException方法。因此可以例用以下方法來走訪所有的Exception
後續改寫一版後,能明確抓到射後不理的Exception,也不會造成集區崩潰就變成以下的版本了
當然,若不是要射後不理的話,建議還是要讓function async / wait化,來確保執行流程順序中的工作都有被完成
MS Docs參考
https://docs.microsoft.com/zh-tw/dotnet/standard/parallel-programming/task-based-asynchronous-programming
之前為了一個案子,實作了一個POC秒殺的情境,透過python、nginx、lucust、docker來模擬,但那時候必竟是架構新手,對於POC驗證的環節
只想的到以下的方式,以下提供參考…若有盲點或不足之處,歡迎指導…
一 測試內容
二 測試方法
三 測試方法
四 測試目標
五 測試環境
5-1 壓力測試部署圖
5-2 壓測用戶端與服務端主機規格
六 系統部署
6-1 系統部署架構圖
6-2相關系統容器配置表
七 性能測試結果與分析
7-1 測試步驟與結果摘要
7-2 劇情1 線上用戶30,000,開放10,000個號碼牌
7-3 劇情2線上用戶30,000,開放30,000個號碼牌
7-4 結果與發現
一 測試內容
本次測試是針對搶票系統進行壓力測試,在秒殺產品的場景中,需求遠遠大於供給,因此考慮巨大流量的情況下,我們在設計交易的接口中,加入了號碼牌機制,從入場、選位到結帳三關卡皆透過號碼牌的控制來監控與管理入場選擇產品的人流。並逐步縮小對於後端API的請求,達到集中運算資源與降低關鍵接口負載壓力的目的。這次我們主要驗證的功能包含了領取號碼牌、選位與結帳的功能。
二 測試方法
本次採用了python開源的分散式壓力測試工具Locust.io,這個工具的特性是可以快速佈署壓測用戶端的集群,並透過統一的Master發動壓力測試,並具備Dashboard,提供效能統計表與分析圖型,近期Amazon Web Service廠商已經善用其可分散式佈署的特性,透過259台用戶端,將壓力測試提升到每秒超過10萬次的後端請求的等級,請參考相關AWS官方連結。
這次測試採用容器技術動態建立Locust測試集群,並透過Http協議發出GET請求,伺服器端主要透過Nginx+Tornado建立Load Balance與非阻塞式的Web Server,並結合容器技術動態擴充WebServer群,包含主要關鍵流程API,包含取得號碼牌請求、模擬選位請求、模擬結帳請求。關鍵流程之間,透過Redis快取技術協調並模擬用戶狀態(包含入場前、入場選位前、選位後、結帳前),最終透過MongoDB儲存持久化交易結果。
三 測試場景
測試場景包含了1取得號碼牌API,其主要目的是第一關控制流量,但也因為要面對第一線最多的請求流量,因此需要的資源最多。其2為模擬選位API,因應用戶取得號碼牌後的狀態變動,我們透過快取保存用戶狀態,以模擬用戶端行為。用戶在具備號碼牌的狀態下,呼叫模擬選位API,會有自動配位的邏輯處理,亂數決定客戶購買1~4張的張數,並動態查詢仍有空位的連續座位區域並隨機決定。此時會透過鎖定機制,保存在快取內,並非同步創建訂單到NoSQL的儲存體中,其狀態為未付款(Pay Status=1),並將此用戶加入到待付款的佇列中。最終為模擬結帳API,此API將會隨機取得佇列中的排隊付款用戶,並同步更新NoSQL的付款狀態(Pay Status=2),此時會標記其用戶已付款完成。
本次測試樣本將模擬銷售單一場次、6區域,依2回合進行測試,分別開放token限制為1萬、3萬,分別模擬請求流量的變化。
四 測試目標
測試獲取單一物理主機的伺服器在反應時間3秒內,其單位承載量RPS為多少,模擬併發用戶為多少。
採用號碼牌分流搶票流程下,在上述系統效能需求下,最終全數票券銷售完成到結帳狀態(模擬完成金流後,寫回訂單資料押付款完成的狀態)需要多久的時間。
五 測試環境
5-1 壓力測試部署圖
5-2 壓測用戶端與服務端主機規格
環境 | 機器型號 | 作業系統 | 硬體cpu | 硬體mem |
用戶端 | Linux虛擬機 | CentOS 7 | 4核 | 8G |
服務端 | Linux虛擬機 | CentOS 7 | 4核 | 8G |
六 系統部署
6-1 系統部署架構圖
6-2相關系統容器配置表
容器環境 | 佈署應用程式 | 數量# | 備註 |
用戶端主機 | Locust Master | 1 | 統一發動測試端與測試結果Dashboard |
Locust Slave | 10 | 接受發動測試指令,執行測試腳本 | |
服務端主機 | Nginx | 3 | 用於3個關鍵流程的Reverse Proxy分流關卡 |
Tornado(Token API) | 5 | 主要面對最大流量領取號碼牌請求 | |
Tornado(Reserve API) | 3 | 面對已過濾擁有號碼牌的用戶進行選位模擬 | |
Tornado(Admin API) | 1 | 初始化資料預熱
Dashboard監控資訊 開放TokenLimit接口 |
|
MongoDb(NoSQL) | 1 | 主要儲存最終訂單持久化與結帳後模擬金流回填狀態。 | |
Redis Cache Server | 1 | 主要處理關鍵流程間狀態控管 |
七 性能測試結果與分析
7-1 測試步驟與結果摘要
步驟一.Dashboard 初始化
步驟二.Locust配置與啟動
步驟三.抽樣觀測Server狀態與銷售狀態
步驟四 銷售完畢後,並待所有結帳佇列消耗完成後,搜集Client端數據
7-2 劇情1 模擬線上30,000用戶,開放10,000個號碼牌,銷售總票數為10,000張
7-2-1 Locust壓測用戶端統計資訊
開放10,000個號碼牌,銷售總票數為10,000張 | |
模擬線上用戶數 | 30,000 |
用戶平均爬升數/秒 | 2,000 |
銷售總花費時數 | 1分40秒 |
有效訂單數(已付款,已進入數據庫) | 3,971 |
總請求數(擷至全售完) | 117,678 |
總平均RPS(Request per Second) | 1,176.8 |
取號碼牌成功請求總數(HttpStatus=200) | 32,268 |
模擬選位成功請求總數(HttpStatus=200) | 10,903 |
模擬結帳成功請求總數(HttpStatus=200) | 7,610 |
服務器狀態 | 全數存活 |
7-2-2 Locust壓測期間趨勢圖
7-2-3容器正常服務
7-3 劇情2 模擬線上30,000用戶,開放20,000個號碼牌,銷售總票數為10,000張
7-3-1 Locust壓測用戶端統計資訊
開放20,000個號碼牌,銷售總票數為10,000張 | |
模擬用戶數 | 30,000 |
用戶平均爬升數/秒 | 2,000 |
銷售總花費時數 | 2分17秒 |
有效訂單數(已付款,已進入數據庫) | 3,962 |
總請求數(擷至全售完) | 156,029 |
總平均RPS(Request per Second) | 1,138.9 |
取號碼牌成功請求總數(HttpStatus=200) | 36,606 |
模擬選位成功請求總數(HttpStatus=200) | 14,776 |
模擬結帳成功請求總數(HttpStatus=200) | 6,984 |
服務器狀態 | 全數存活 |
7-2-2 Locust壓測期間趨勢圖
7-2-3容器正常服務
7-4 結果與發現
從相同的壓測用戶參數,並透過號碼牌來控制流程API的流量,我們發現號碼牌發放的控制,可以有效提升服務效率,銷售的時間更短。同時,這次銷售10,000張票在我們配置的架構下(Nginx與Tornado),單台主機可以支撐爆量請求而不會造成應用程式崩潰與異常銷售,仍然可以將其票券全數售完,並正常寫入資料庫。而本次透過容器建置所有的系統與API,說明未來管理上雲或是自建機房(IDC)可以在即短的時間內佈署。同時具備易用與易於擴充的特性。而切分微服務的概念,除了在系統佈署的配置上可以更彈性的運用,且未來更有機會隨時提升到Serverless的層次,透過雲端全託管的服務,可以有效降低維運成本。
看了為你自己學Git,五倍紅寶石,高見龍大師著作(這本真的釐清很多我對git一知半解的觀念,大推)
以下整理筆記,提供日後個人查詢使用~
在windows上,python要連線到mssql,只需要透過pyodbc,幾乎不用什麼設定,就可以輕鬆連線上mssql
但是在linux上,遇到的坑與血淚,相信前人遇到的已經太多了!
以下記錄一下步驟與眉角:
首先我們先假設已經有一個存在的docker container在運作了,裡面有基本python 3.6的環境(或其他版本,這邊以3.x為主,自行上docker hub找吧…)
連進去container後,有3大工程要施作…
註:freetds.conf 的dump file = /tmp/freetds.log反註解,global的tds版本也要改成7.0一致的版本,有dump log的話,後續連線失敗的話,可以看的到錯誤原因,事半功倍
例: severity:9, dberr:20002[Adaptive Server connection failed], oserr:0[Success] –>tds版本問題,要調整,若8.0不行,就7.2->7.1->7.0往回裝
若freetds可以連線,也可以查詢的話,應該會像這樣:
可以下sql指令,也回傳的了資料集
執行成功,我要哭了…凌晨3點了!!
根據網友們的分享,這裡還有一個很大的坑就是連線字串要包含TDS_Version的資訊,版本要跟freetds內配置的版本一樣…
否則就會陷入無限的…08001輪迴,而不知其所以然…
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
pyodbc.Error: (‘08001’, ‘[08001] [unixODBC][FreeTDS][SQL Server]Unable to connect to data source (0) (SQLDriverConnect)’)
https://blog.csdn.net/samed/article/details/50449808
http://www.voidcn.com/article/p-vaxmczdi-dc.html
壓測是考驗整體架構吞吐量與穩定性的最直接方式
繼上一篇 找到了一個壓測新朋友Locust 傳送門
這一篇進一步透過自動化shell,可以加速建置你的壓測Client端集群與Server端集群
首先我們要租2台主機,讓其物理cpu、ram網卡獨立,然後可以預設在相同的DataCenter,以降低跨DataCenter的網路影響因素
整體壓測概念如下:
Initail #number of web server Shell Script
Initail #number of locust client Shell Script
實測下來,8g開10個container(共享)的情況下,估計10000 concurrent user應該已經是很極限了,其實我們會發現極限應該是會在client發出請求端
web server多少會因為os、網卡、容器網路的限制,導致同時connection數無法無限上崗,而web server的運作還不包含更複雜的運算情境(只考慮in ram處理與非同步mongodb log)
因此以此為基準來當作未來擴充的計算基礎參考,應該還ok,若要模擬更複雜的商業邏輯運作,那麼可以仿照此作法去刻
10k
20k (RPS反而降了,看來還是有其極限存在)
美中不足的就是怎麼動態改Nginx的Nginx.Conf,把ReversProxy動態換掉,這個以後再研究吧…
100k on AWS
Reference:
1.https://aws.amazon.com/tw/blogs/devops/using-locust-on-aws-elastic-beanstalk-for-distributed-load-generation-and-testing/
2.https://www.slideshare.net/AmazonWebServices/aws-reinvent-2016-how-to-launch-a-100kuser-corporate-back-office-with-microsoft-servers-and-aws-win303?from_action=save
繼上一篇,自建nginx分流後(傳送門),接著的問題就是要如何驗證分流效果與實際上這樣架構的負載吞吐量到底能到多少了。傳統想到壓測,我們就會想到jmeter,但是jmeter的參數配置繁多,而且若要做到可程式化的話其路可能相當曲折;再者,若在我們實體主機上測試的話,極有可能受限於其物理極限,包含頻寬與網卡的能力,因此我搜尋了一下python有沒有load test framework,又可以同時支援分散式的load test
結果發現了這套名叫:locust的套件!!其安裝方式相當的簡單:
首先,整份框架都是python寫的,透過pip就可以安裝,因此先來試著打包成映像檔,變成隨時可以使用的容器吧:
測試Script寫起來相當簡潔,我們直接存成locustfile.py,實作HttpLocust、TaskSet後,屆時會在locust的壓測ui介面,讀取到接口
Dockerfile的內容:
docker-entrypoint.sh的內容:
單一台load test測試端 啟動指令 (驗證ok):
分散式的測試端配置(待驗證):
啟動指令-master測試端:
啟動指令-slave測試端:
容器執行後,打入http://xxx.xxx.xxx.xxx:8090,就可以連到對應的監控網址(這個是最棒的),一開始就會問你模擬的u數,以及你希望多久時間內要衝到該u數
摘要總表:
即時圖表:
錯誤分析:
同時,我去驗證了我們mongodb的log,是符合他load test的請求數量
以上是這次接觸到新的壓測工具實作的小小記錄,也推薦給大伙
參考:
https://locust.io/
https://docs.locust.io/en/stable/
https://medium.com/locust-io-experiments/locust-io-experiments-running-in-docker-cae3c7f9386e
傳統在雲端平台上,通常都會有現成的Load Balance服務,提供彈性負載分流到自己的應用程式集群
假如我們希望在私有雲下,或是在自己家裡,希望也可以建置Load Balancer的話,透過硬體的F5機制成本高昂
這個時候,就可以依賴Nginx的套件了
其特點是可以大量處理併發連線
Nginx在官方測試的結果中,能夠支援五萬個並列連接,而在實際的運作中,可以支援二萬至四萬個並列連結。
假設以下情境,我們希望建立一個WebTest的測試環境,統一1個domain的port為進入點,但背後可能有很多台Api或子web站台來支持不同的服務與運算
因此這個時候,我們需要nginx來做為API.Domain的代理服務器,將實際的請求轉導到對應的內部伺服器,再把結果回傳回去
我們以Docker為測試環境,方便模擬多台伺服器的情況,而Docker在容器間的網路連線上,提供許多Api可以方便我們建置集群
我透過Python寫一隻輕量運算的api server(這也可以是其他案例,例如取得天氣、股市、時間…等)作為範例
當api層級深度太高的話,瓶頸識別會愈來愈不單純,因此我先在這邊假定問題點就是單一台吞吐量有上限,因此我們透過多台+load balance來支持同時併發的連線請求
小型的python get uuid tornado web server
註:上面python的實作,為了統計server的請求處理數據,因此加入了寫入mongodb的異步流程,可以參考使用,呼叫mongodb連線時,記得也要使用container name哦,不然會連不到
將其server打包成容器
#建立測試api 服務容器映像檔
sudo docker build -t tornado-web-test .#建立容器群網路,網路內的容器可直接互連
sudo docker network create webtest#建立容器實例(共3台),分別佔用10001, 10002, 10003
sudo docker run -d –name webtest001 –network=”webtest” -p 10001:6969 tornado-web-test
sudo docker run -d –name webtest002 –network=”webtest” -p 10002:6969 tornado-web-test
sudo docker run -d –name webtest003 –network=”webtest” -p 10003:6969 tornado-web-test
分別請求10001,10002,10003的http://xxx.xxx.xxx.xxx:10001/webtest?action=get_uuid後,可以正常的回應即可
接著主要工作就是配置nginx,其設定檔,很明確的說明了我希望它扮演的角色
nginx.conf
注意:這邊的webtest1~3的port號都是6969,雖然在之前docker run的時候,有expose綁到其他port號,但是在docker的容器網路內部仍是採用原本容器的設定,因此這邊一定要用容器配置,而不是容器expose的配置,這邊找了一陣子
關於upstream的標籤,官方文件如下:
標籤下,我們可以定義伺服器群組,各別伺服器可以監聽不同的port,而且可以TCP/Socket混用
預設,請求會被透過round-robin balancing方法的權重來分配到不同的伺服器,以此為例,每7個請求,會被分配5個請求到backend1.example.com,還有2個分別被轉送到2、3伺服器
假如轉送過程中,有發生error,該請求會自動pass給下一個伺服器,直到所有的伺服器都試過為止。假如沒有任何伺服器可以回傳正確的結果,那用戶端的通訊結果將會是最後一台伺服器的訊息。
我們啟動Nginx容器,並試著去連線對外的10000 port
#nginx docker command
sudo docker run –name web-test-nginx –network=”webtest” -p 10000:10000 -v /home/paul/webtest/nginx/conf.d/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx nginx-debug -g ‘daemon off;’
實測:http://xxx.xxx.xxx.xxx:10000/webtest?action=get_uuid
打網址,若可以出現這個畫面,那就代表可以work了,多打幾次後,我追蹤mongodb裡的log,可以看到不同的server都有接到請求
大工告成!!
透過這樣的架構,我們可以讓原本單一一台的請求量提升到n台,假如nginx的配置沒有爆的話,那只要擔心後端的每個端點是否服務正常(這關系到監控機制)
當然,docker、vm,個人電腦都有其物理極限,包含網卡、頻寬,伺服器的連線上限…etc,因此負載測試這個issue,有時因為成本過高,我們會測出單位的負載量後再加倍估算。
這個就另開討論吧…