主頁 >  其他 > 10分鐘拿下雪花演算法

10分鐘拿下雪花演算法

2021-05-07 10:45:43 其他

道阻且長,行則將至,請相信我,你一定會更優秀!

「 人人都聽過的雪花演算法,你真的推敲過嗎?」

很多人聽過或用過雪花演算法,可是到底一個ID是如何計算出來的,沒幾個講明白,別上來就跟我聊時鐘回撥的問題,貌似你很懂一樣,首先這是個演算法,你先給我寫個代碼我看看?

技術人要對自己寫的每一行代碼負責,靜下心來,我帶你吃透雪花演算法,關于分布式ID的文章有很多,你可以自己去查閱,此處我們不再贅述,本文只聊雪花演算法,


目錄

一、為啥叫雪花?

二、技術設計點剖析

1、技術背景

a. 我們希望一個id有以下2個特性足以:

b. 我們希望id服務有以下幾個特點:

c. 綜上,雪花演算法的id由以下部分組成,完美匹配我們想要的規則:

d. 為啥不用納秒?納秒不是更精確嗎,更不容易沖突嗎?

2、twepoch 這個是干嘛的?

a. 那這個時間起啥作用?我們用的時候,這個時間寫什么呢?

3、假如同一毫秒內,12個bit位的序列自增用完了,咋辦?

4、如何判斷序列號用完了?比大小嗎?

5、計算 id的移位操作,是如何移位的?

6、生成的 id是單調遞增、趨勢遞增的,會出現第2次拿到的比第1次拿到的id小嗎?

7、生成 id的長度有多長?

8、這個 id的位數分配規則,自己能調整嗎?

9、workerId怎么計算的?

三、安全問題

1、時鐘回撥,即時間走著走著卻倒回去了,如何解決?

2、新起的節點中,機器時間不對,那就壓根不能提供服務,如何校正?

3、業務上,通過 getById 介面遍歷能拿走多少越權資料?

4、友商是否可以決議你的 id大概計算出你的業務量?


一、為啥叫雪花?

世界上沒有兩片完全相同的雪花,任何一個技術設計,都值得有一個代號,都值得有自己的 slogan 并為之努力讓它產生價值,

二、技術設計點剖析

雪花演算法的源代碼或者優秀代碼示例有很多,但思想是一樣的,我們這里不再一行行寫代碼,把里邊的關鍵代碼拿出來決議即可,這里提供一個代碼示例:https://github.com/Meituan-Dianping/Leaf,是美團的雪花演算法代碼實作(個人認為,美團開源出的代碼真的很糟糕,內部一定是有另外一套,這個代碼只是供大家參考的,不過不影響核心邏輯),不管你有沒有讀過雪花演算法代碼,關鍵的代碼我會在下邊一個個剖析,讀懂這些關鍵點,你就掌握了雪花演算法,

1、技術背景

a. 我們希望一個id有以下2個特性足以:

  • 純正整數,占用記憶體小
  • 遞增,后一個大于前一個,且多節點時依然這樣

第1條,純數字好說,十進制,不出現字母就行,表中用 bigint表示,對應 java中用 long表示即可(均占用8個byte,64個bit);

第2條,遞增,那我們就想,什么是遞增的?時間呀,時間天然是遞增的;那多個節點在同一時間不就生成了相同的id了?再加上每個節點的唯一標識;同一時間內有多個請求咋辦?再加上個序列號,就這點事,

b. 我們希望id服務有以下幾個特點:

  • 速度快,并發高
  • 支持集群高可用HA
  • 對業務系統無侵入,與業務系統松耦合

第1條,速度快:純記憶體操作就可以,1s出100萬,夠用吧

第2條,可集群部署,且id也是遞增狀態,且單節點故障不影響集群HA

第3條,與業務系統松耦合,遵循業務各服務間呼叫方式即可,如業務系統服務呼叫使用Dubbo,此id服務也是Dubbo服務提供出去就好

c. 綜上,雪花演算法的id由以下部分組成,完美匹配我們想要的規則:

from: 美團leaf > 雪花演算法

分析:一共 64個bit,占用 8個位元組,MySQL中是 bigint表示,java中是 long表示,注意是64個bit運算表示出一個數字,而不是幾個段的數字用字串拼接起來!

1個bit:第0位,符號位,0只要正數

41個bit:毫秒時間戳的數字,注意,和時間本身沒有任何關系,只是借助了時間戳的數字,要理解清楚,很重要

10個bit:集群部署的話,為避免不同節點生成出相同的id,給每個節點一個唯一的數字標識

10個bit:同1毫秒內,同一節點,需要多個id的話,用序列號自增

記住上邊的位數分配,下邊會逐個決議,

d. 為啥不用納秒?納秒不是更精確嗎,更不容易沖突嗎?

  1. 你的業務并發需要納秒級別的嗎?1ms=1,000,000ns 我的業務并發連毫秒都到不了,然后我這里花時間、花記憶體去計算/存盤納秒?再說了,CPU主頻2G的時鐘周期算下來才 0.5ns,你上層建筑空想啥呢?毫無意義!
  2. 我們一共只有64個bit,要做好幾件事情呢,合理分配,省著點,留著bit給其他段用吧;
  3. 所以,用毫秒ms時間戳表示足以;

2、twepoch 這個是干嘛的?

SnowflakeIDGenImpl#SnowflakeIDGenImpl

注意這行注釋:

//Thu Nov 04 2010 09:42:54 GMT+0800 (中國標準時間)

首先要清楚,這個時間對于我們來說,不是什么特殊的時間點,對我們來講沒有意義,或許是美團內部開始用雪花演算法的時間點,我們不用研究這個時間,

a. 那這個時間起啥作用?我們用的時候,這個時間寫什么呢?

上邊說過用 41個bit表示時間戳,如果41個bit都占滿,能表示的最大數字是:2199023255551,也就是 2199023255551個毫秒,這么多毫秒換算下來是大概 69年,

2199023255551 / 1000 / 60 / 60 / 24 / 365 ≈ 69
毫秒          / 秒   /分鐘/ 小時 / 天 /  年

也就是說,從這 41個bit都是0開始計算,到 41個bit都用滿,需要 69年的毫秒時間戳才能填滿,

可關鍵是不可能是從0開始呀,當前、現在的時間戳已經是一個很大的數字,那要是從現在開始算的話,能用多少年呢?(從0開始算只是理論值而已)

ok,繼續看代碼:

long id = ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;

為啥要減去 twepoch呢?(timestamp - twepoch),如果不減這個 twepoch,問題就出現了,我們的 69年算的是從 0開始計算,但是假如我們是 2021-05-05才開始用的雪花演算法,也就是說我們第一次使用的時候,就已經從 1620179006000時間戳開始了,不是從 0開始的,這個數字會浪費掉我的 41bit能表示的資料集中的一大部分,所以,必須要減,因為我才今天剛開始用,要從我的投產時間開始算的,如果不減我們會浪費掉多少呢?

1620179006000 / 1000 / 60 / 60 / 24 / 365 ≈ 51
毫秒          / 秒   /分鐘/ 小時 / 天 /  年

也就是說,本來我的 41個bit夠我用 69年,但是剛一投產,就耗掉了51年的,剩下的只夠我用 69-51=18年!

那么我們的這個 twepoch設定為多少呢?

比方說我們是 2021-05-05 上線,雖然是我們第一次使用的時間,但是我們不能這么設定,因為我們有業務歷史資料,如果這個時間設定的不對,一定會遇到和現有id沖突的情況!可以設定一個公司成立或者業務線開始的時間,現在的時間和指定的時間點的差集耗掉的數字,我們認了,如果你是全新的開始,那完全可以設定為投產時間即可,

3、假如同一毫秒內,12個bit位的序列自增用完了,咋辦?

12個bit能表示的最大數字是 4095,一共 4096個 [0, 4095],

首先這個計算是在單個 JVM中計算的,按照美團的位數分配,即同一毫秒同一個worker最大能生成 4096個id,如果同一毫秒內,用完了,就等待到下一毫秒,

根據這個情況我們可以推理出,我們的批量獲取的介面中,一定要加上數量限制,如果不限制,如果業務端傳過來的是 Integer.MAX_VALUE,那就是說這一次呼叫需要等待的時間大概為:

2147483647 / 4096 ≈ 524287ms ≈ 524s ≈ 8.7min

忽略呼叫時超時時間的問題,單純說這個事情,CPU打滿8分鐘... 我這里建議批量介面中數量引數不要超過1000,甚至是100,什么樣的業務場景中會一下子需要這么多id?業務上能處理過來嗎?自己根據情況權衡下,

4、如何判斷序列號用完了?比大小嗎?

SnowflakeIDGenImpl#get

注意這行代碼,很有意思:

sequence = (sequence + 1) & sequenceMask;

sequenceMask為序列號的最大值,也就是序列號的 bit位都占滿,都是1,那 sequence的值在正常增長情況下,任何一個 bit &1,都是1,怎么可能會出現 if (sequence == 0) 這個情況呢?

只有一種情況,就是超出了 bit位,這些 bit位已經裝不下了,進位了,后面全是 0,所以 &出來結果成 0了,

5、計算 id的移位操作,是如何移位的?

long id = ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
  • (timestamp - twepoch) 是時間戳計算值,是long型別,64個bit,timestampLeftShift 是 12+10=22
  • (timestamp - twepoch) << timestampLeftShift) 意思是將這 64個bit 左移22位,也就是原值的后 42個bit留下為有效的,這步完成后后面還有22個bit可用;
  • (workerId << workerIdShift) 同理,這個是將 workerId 左移12位,12位為sequence的bit數,這步完成后后面還有12個bit可用,供sequence使用,sequence在末位,不用移位;
  • ((timestamp - twepoch) << timestampLeftShift) | (workerId << workerIdShift) | sequence 或運算,將時間戳和 workerID和sequence 的bit位進行計算、整合;
  • 最后64個bit都整合完畢,為64個bit,8個byte

這個程序一定要搞明白,如果搞不明白先去復習下二進制運算,這個搞明白后可以幫你在業務上做一些別的事情的,比如 Zookeeper客戶端的 auth位、redis的 bitmap等等,

6、生成的 id是單調遞增、趨勢遞增的,會出現第2次拿到的比第1次拿到的id小嗎?

基本不用考慮這個問題,生成的id是單調遞增、趨勢遞增的,在極高并發的情況下,比如有兩個workerID,1和2,前提是同一毫秒,先去2拿到的是大值,再去1拿到的是小值,這樣計算的話,我們的并發至少得有2000了,

而且,如果出現了這種情況,不會影響業務使用的,可能會受影響的只有 InnoDB中 B+tree出現先小后大的效率差問題不過有這個時間還是想想如何優化業務代碼吧,如果單論技術的話,業務從我這里拿走的id,不一定怎么處理呢,可能會因為業務的原因,導致大的先進表了,小的后進去,所以不要假裝在這里鉆研技術,實際上業務代碼寫的一團糟,

為什么會影響 InnoDB的 B+tree?

比如葉子節點的某一個頁中放了1000個主鍵id,首先,葉子節點中這些id是有序遞增排列的,如果你后邊來了一個小的,那就有可能之前的頁中放不下了,需要重排列和分頁,

7、生成 id的長度有多長?

最長19位!一定不會超!表中的主鍵id bigint(20)足夠用!19位就是百億億了!

id的大小區間是:[1, 9223372036854775807]
最小的id是:1(twepoch為當前時間,并且workerId是0,序列號為1)
最大的id是:9223372036854775807(64個bit,第1個bit是0不變,其余位都占滿,即是最大數,為9223372036854775807,也就是java Long型別的 MAX_VALUE)

8、這個 id的位數分配規則,自己能調整嗎?

當然可以,根據自己的業務情況調整,我們這兒將 bit位數分配調整為:1+42+5+16

  • 1個bit 用來表示0,正數;
  • 42個bit 用來表示毫秒時間戳;42個bit,最大是4398046511103,4398046511103個毫秒值,換算大約是 139年,也就是說從開始投入使用,可以使用 139年;
  • 5個bit 用來表示workerID;最大31,也就是目前支持最多31個worker,一般小單位沒有這個量級,如果有這種體量了,再調整也可以的,不用怕重復,因為時間戳是在高位,并且時間戳肯定是遞增的,高位的大小決定了數字的大小;
  • 16個bit 用來表示sequence,自增值;同一毫秒,同一 worker上,最多生成 65536個,也就是不考慮外界條件的話,單純的這塊,純理論每秒可以出 65536000個id,大約是 6553萬個,

9、workerId怎么計算的?

美團代碼中,依賴 zookeeper + 本地檔案快取 雙機制來生成 workerId,詳細參考美團文章(https://github.com/Meituan-Dianping/Leaf),講的很清楚,這里不再贅述,

三、安全問題

上邊的搞清楚之后再來看安全問題,1和2 的問題都可以參考美團文章(https://github.com/Meituan-Dianping/Leaf),上邊講的很清晰了,這里不再贅述,

1、時鐘回撥,即時間走著走著卻倒回去了,如何解決?

2、新起的節點中,機器時間不對,那就壓根不能提供服務,如何校正?

3、業務上,通過 getById 介面遍歷能拿走多少越權資料?

首先雪花演算法生成的id不是+1遞增的,比依賴資料庫的自增id要安全很多,另外還要看你的業務設計上,資料權限的控制是否存在漏洞,

4、友商是否可以決議你的 id大概計算出你的業務量?

不存在,首先有 twepoch存在,我不是時間戳,你決議出來只是數字,無法知道具體時間的;另外,后面的自增 sequence,不同的ms內,是隨機生成的,不是都從0開始的,無法知道我的業務量;這兩個條件加起來,足以保證 id的安全性,


【總結】本文我們主要聊了雪花演算法到底是怎么算出來一個 id的,其實基本功是二進制運算,基礎扎實的話,很快就可以 get到它的設計思想,但是,一定要清楚,所有的技術都是為了解決業務問題,也不存在一種技術設計完全適用所有公司的所有業務場景,具體使用的時候根據自己的情況進行調整,但就意味著你必須清楚原理,別瞎改,否則 3.25甚至更慘,哈哈,對自己的每一行代碼負責是技術人的默認選項,

努力改變自己和身邊人的生活,

特別希望本文可以對你有所幫助,原創不易,感謝你留個贊和關注,道阻且長,我們并肩前行!

轉載請注明出處,感謝大家留言討論交流,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/283202.html

標籤:其他

上一篇:2021年大資料常用語言Scala(十一):基礎語法學習 方法引數

下一篇:Hadoop之Hive函式

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more