Java生成短鏈接 (文章)
https://www.cnblogs.com/xijin-wu/p/8483649.html
https://www.seoxiehui.cn/article-156919-1.html
https://search.gitee.com/?skin=rec&type=repository&q=%E7%9F%AD%E7%BD%91%E5%9D%80&repo=&reponame=&lang=java
Java netcore
1. Wei.TinyUrl
https://github.com/a34546/Wei.TinyUrl
1.1shorturl
https://github.com/wjup/shorturl
2. ShortURL
https://github.com/zhaopeiym/ShortURL
3.基於JavaFx搭建的實用小工具集合
https://github.com/864381832/xJavaFxTool
4.Alkaids/shortcut ***
https://github.com/Alkaids/shortcut
******************************************************************************************************************************************
1.Twitter的分布式雪花算法 SnowFlake 每秒自增生成26個萬個可排序的ID (Java版)
https://blog.csdn.net/yanpenglei/article/details/79542768
2.Twitter的雪花算法(snowflake)自增ID
https://www.cnblogs.com/jifeng/p/9802142.html
*******************************************************************************************************************************************
__________________________________________________________________________________________________
在知乎看到這篇貼子談論短地址生成的方法。 主要步驟為兩個:
- 實現一個不會重復的發號器
- 每個新的請求都給它一個新的號碼,轉換成62進制,62進制是帶有阿拉伯數字,英文大小寫的格式,比較適合作為短地址的 url.
發號器
直接不造輪子了,用 Twitter 的雪花算法。
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
- 1位標識,由於long基本類型在Java中是帶符號的,最高位是符號位,正數是0,負數是1,所以id一般是正數,最高位是0
- 41位時間截(毫秒級) 一般來說這個時間能夠使用69年.
- 10位的數據機器位,可以部署在1024個節點
- 12位序列,毫秒內的計數,12位的計數順序號支持每個節點每毫秒(同一機器,同一時間截)產生4096個ID序號
- 加起來剛好64位,為一個Long型。
進制轉換
通過上述發號器得到的Long類型的數據,轉換為62進制,比如
6628238651141500928
轉換為
7TDp0rS917i
下面這個字符串就是需要的短地址。
重定向
通過 curl -i http://127.0.0.1:9527/7TDhjcamrAI
應用會匹配末端的字符串,去redis里面拿到url,然后通過狀態碼 302 重定向即可。
二維碼生成
使用 Google 的 zxing 做的二維碼轉換,詳細代碼可參考這里。
性能測試
使用 JMH 做性能基准測試,環境為 CPU: 2.2 GHz Intel Core i7; Memory: 16 GB; OS: Mac OSX
。
Options options = new OptionsBuilder().include(BenchmarkTest.class.getName()+".*")
.warmupIterations(1) // 預熱
.warmupTime(TimeValue.seconds(1))
.measurementIterations(5)// 一共測試10輪
.measurementTime(TimeValue.seconds(5))// 每輪測試的時長
.forks(1)// 創建幾個進程來測試
.threads(16)// 線程數
.build();
測試結果如下:
Benchmark Mode Cnt Score Error Units
BenchmarkTest.httprequest thrpt 5 1948.349 ± 2028.032 ops/s
BenchmarkTest.serviceRequest thrpt 5 3945.100 ± 1185.980 ops/s
httprequest
是通過okhttp
構造post
請求,直接請求本地前端控制方法。qps
大概 2000 左右。serviceRequest
是直接調用本地方法服務得到短地址,qps
大概是http
測試的兩倍,有 4000 左右,比較理想。
進一步的優化空間可以關注一下進制轉換部分,有不必要的基本類型轉換。
____________________________________________________________________________________________________________________________
原理:
Ø 通過發號策略,給每一個請求的長地址分配一個唯一編號,小型系統直接利用數據庫的自增主鍵就可以。
Ø 如果大型應用,可以考慮實現分布式發號器,不斷自增就行。第一個使用這個服務的人得到的短地址是http://www.shururl.com/0 第二個是 http:// www.shururl.com /1 第10個是 http://www.shururl.com /a 第依次往后.
實現處理流程:
A. 核心步驟:
- 實現唯一發號器.
- 每個請求獲取一個唯一編號,轉換成62進制,62進制是由 英文字母(大小寫)、阿拉伯數字等格式組合,作為短地址的短碼.
B. 發號器規則:
計算的來源思路: Twitter 雪花算法
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
- 1位標識,由於long基本類型在Java中是帶符號的,最高位是符號位,正數是0,負數是1,所以id一般是正數,最高位是0.
- 41位時間截(毫秒級) 這個是毫秒級的時間,一般實現上不會存儲當前的時間戳,而是時間戳的差值(當前時間-固定的開始時間),這樣可以使產生的ID從更小值開始;41位的時間戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年;
- 5位的數據中心,可以存在在32個數據中心
- 5位的機器位,每1個數據中心可以部署32個節點
- 12位序列號,毫秒內的計數,12位的計數順序號支持每個節點每毫秒(同一機器,同一時間截)產生4096個ID序號
- 加起來剛好64位,為一個Long型。
C. 進制轉換:
通過上述發號器得到的Long類型的數據,轉換為62進制,比如:6628238651141500928 轉換為: 7TDp0rS917i 下面這個字符串就是需要的短地址,http://127.0.0.1/7TDp0rS917i
詳細思路:
1. 根據發號器的數量,在mongo中建立一張表
發號器Id |
發號器名稱 |
機器標識 |
數據中心標識[LP3] |
應用描述信息 |
XXX |
1號發號器 |
1 |
1 |
Desc. |
XXX |
2號發號器 |
2 |
1 |
Desc. |
XXX |
3號發號器 |
3 |
1 |
Desc |
XXX |
1號發號器 |
1 |
2 |
Desc |
XXX |
2號發號器 |
2 |
2 |
Desc |
指定數據中心的發號器的個數,及配置信息相關.
2. 根據上面[實現處理流程-B] 的處理思路:
1符號位+41位時間截+5位的數據中心位+5位的機器位+12位序列號=64位,一個Long型.
3. 將2步計算獲取的10進制數字轉換為62進制, 用如:數字10000給它的短地址對應的編號是9999,我們將通過雪花算法獲取的9999,做一個10進制到62進制的轉換。
4. 解決發號器的大並發高可用問題,就是將發號器做成分布式,那么多節點要保持同步加1,根據CAP的理論,多點同時寫入保證一致性(Consistency),是不可能真正做到的。解決辦法: 可以實現多個發號器,根據上面的原則我們可以實現32個邏輯發號器,分別發尾號為0到31的號。每發一個號,在5位機器號的基礎上,不斷加1,這些發號器互相獨立,互不干擾。
5. 跳轉用301還是302。301是永久重定向,302是臨時重定向。短地址一經生成就不會變化,所以用301是符合http語義的。同時對服務器壓力也會有一定減少。但是如果使用了301,我們就無法統計到短地址被點擊的次數了。而這些信息的捕捉,是數據分析的重要來源。雖然302會增加服務器壓力,但卻是一個最好的選擇。