短连接服务原理和系统设计
项目源码地址github
原理
长链连接映射, 301/302
算法
- hash算法
- 原子自增(mysql/redis)[进制法]
- 元数据中心发号器(zk/etcd)[进制法]
hash算法
todo
redis原子自增分布式
负载均衡器+n个短连接服务
比如起10个短连接服务, 每个分别以0~9结尾, 负债均衡器采用轮训方式转发请求, 每次短连接服务由单点的自增1改为自增10
这样, 就可以分布式部署并且保持id递增, 即使机器挂了, 可以重启机器并且设置起始生成id为当前同个数量级的或者后面数量级的数字, 继续作为发号器服务
etcd/zk元数据中心号段发放分布式
负载均衡器+n个短连接服务
短连接服务启动时会先获取分布式锁, 然后去元数据中心取id号段, 并且更新元数据中心id号段
- etcd作为元数据中心存储已分发id的id段区间(比如区间是10000, 0~10000 10001~20000…)
- 各个发号服务启动时到etcd/zk取id区间, 并且更新etcd/zk的id段区间为下一阶段(同一个事务/分布式锁)
- 即使有发号服务挂了/重启也只是丢失一段id区间, id还是保持递增
分布式部署
redis原子自增分布式
负载均衡器+n个短连接服务
比如起10个短连接服务, 每个分别以0~9结尾, 负债均衡器采用轮训方式转发请求, 每次短连接服务由单点的自增1改为自增10
这样, 就可以分布式部署并且保持id递增, 即使机器挂了, 可以重启机器并且设置起始生成id为当前同个数量级的或者后面数量级的数字, 继续作为发号器服务
etcd/zk元数据中心号段发放分布式
负载均衡器+n个短连接服务
短连接服务启动时会先获取分布式锁, 然后去元数据中心取id号段, 并且更新元数据中心id号段
基于etcd+发号服务组成的分段分发, etcd作为元数据中心存储已分发id的id段区间(比如区间是10000), 各个发号服务到etcd取id区间, 并且更新etcd的id段区间为下一阶段(同一个事务) 所以, 即可有发号服务挂了也只是丢失一段id区间, id还是保持递增
优化
- 读写分离,分库分表(可以借助中间件)
- 缓存
- 防攻击
- 限流
- 短码反推?(不希望:洗牌算法, 希望:固定位插入字符,还原时删除就行)
测试
nginx反向代理
```nginx
upstream domain {
server 172.16.7.16:9097 weight=1;
server 172.16.7.16:9098 weight=1;
server 172.16.7.16:9099 weight=1;
}
server {
listen 80;
server_name shortlink.test.com;
access_log /var/www/nginx_access.log main;
location / {
proxy_pass http://domain;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
}
}
```
启动三个发号服务
若是单机端口号记得修改
```shell
./shortlink #172.16.7.16:9097
./shortlink #172.16.7.16:9098
./shortlink #172.16.7.16:9099
```
curl请求短连接服务生成长连接的短连接
```shell
curl -XPOST elk.code.com/v1/shorten -d '{"longLink":"https://www.google.com/search?q=22"}'
curl -XPOST elk.code.com/v1/shorten -d '{"longLink":"https://www.google.com/search?q=23"}'
curl -XPOST elk.code.com/v1/shorten -d '{"longLink":"https://www.google.com/search?q=24"}'
```
mysql中长短连接的映射
etcd元数据变化
```shell
etcdctl --endpoints "http://172.16.7.16:9002,http://172.16.7.16:9004,http://172.16.7.16:9006" get /shortLink/
```
启动三个发号器服务的对比:
```shell
{"startNum":31,"endNum":40}
{"startNum":41,"endNum":50}
{"startNum":51,"endNum":60}
```
可以看到每启动一个发号器服务就会去etcd元数据中心取id段并且更新元数据的id段为下一段; 通过分布式锁可以实现每个时刻只会有一个发号服务可用修改etcd元数据中心的id段; 从而实现分布式发号服务.