距離找到獲取比特幣餘額的方法已經過去四個多月了,中間停頓了一段時間,沒有深入研究,最近又重新拾起這個需求來,遇到了一些大大小小的問題,記錄下來,作爲自己一個成長的見證
開始時的代碼結構是這樣
每個getblock返回的tx可能是幾個到幾千個,每個tx可以根據gettransaction生成詳細的交易記錄older,根據交易信息獲取當前接收方的utxo及address地址,這樣從頭連到尾便會形成比特幣這個特殊的餘額。
當然,在成功之前遇到了各種問題,然而都合理解決掉了
首先是圍繞性能問題,ps:主要是性能問題,其他問題都不大,本文就不羅嗦了。
性能瓶頸1
由於每次找到一個交易詳情後,需要向前一步找到send,也就是每一個txid對應的是至少兩次操作。
相對的時間至少會增加兩倍,實際肯定會超出兩倍。
解決方法
遍歷一次txid,通過兩種不同的數據表存放send及rece,用相對較小的空間換取時間,性能提高兩倍有餘。
算法複雜度由O(n*N)縮小爲O(n)。
實際上這個方法也改變了數據存放的結構,間接影響了mysql的性能。
性能瓶頸2
bitcoin的API命令gettransaction命令會去index文件夾下遍歷levelDB數據庫
鎖定到這一行代碼後,研究了一番levelDB,發現levelDB的寫性能十分強勁,而隨機讀就有點相形見絀了。
要知道bitcoin截至到目前爲止將近4億個txid,而我每次通過gettransaction訪問txid的交易記錄便是一次隨機讀。
根據實際測試,平均讀取速度是每次70ms左右,要知道,光是讀取txid就要1000個小時,這肯定是不可以的.
解決方法
解決方法是通過getblock獲取整個tx下的txid交易詳情,執行一次大約需要400ms,但是getblock對應的數據量只有區區56萬多個塊,獲取同樣數量的txid只需要72個小時,性能提升有多高不需要細說了吧。
性能瓶頸3
mysql插入語句insert,開始時使用go庫中sql的事務,後來檢查sql語句在執行事務時是每個value執行一次insert語句。
要知道,mysql資源佔比中,語句的重複插入佔比非常高。
解決方法
將value值用字符串拼接方法拼接,一個數據表只執行一次insert語句便將所有對應的value插入
在這個方法下,性能提高5-10倍,由於預計將有20多億條數據存放,所以mysql分表數量爲512個。
多個表的情況下確實會降低mysql的insert性能,不過這些相對數據量來說是不可避免的。
性能瓶頸4
mysql中的主鍵索引隨着數據量的增加也會直接影響性能,經過測試,當每個表中的數據量達到幾萬時,便會大大降低insert速度
解決方法
索引在insert時不設置,當數據插入完成後設置
性能相對來說,提高几倍-幾十倍,這個沒有實現完整的表數據無法獲取到精確數值
性能瓶頸5
由於以上所有的硬盤操作都是採用win10下的機械硬盤,所以考慮到服務器的c盤是固態硬盤,將mysql的數據移到c盤的固態中
解決方法
經過測試,由原來的機械硬盤100%佔用率到固態硬盤的5%佔用率,看到後大喜。
直接開10個併發,因爲一開始寫代碼時就考慮到了以後要併發,所以併發只是一個參數的問題。
開啓併發後,cpu佔用率到70%,固態佔用50%。
性能相比最開始的提高整整幾千幾萬倍。
經過計算抓取完整區塊信息時間不超過2天48小時,整個過程包括getjson,解析,分類,存庫,最後大功告成。
這個過程非常的舒服,很有成就感,本次分享到此結束。