流量控制与RateLimiter

一背景

如何提高系统的稳定性,简单来说除了加机器外就是服务降级、限流。加机器就是常说的分布式,从整个架构的稳定性角度看,一般SOA每个接口的所能提供的单位时间服务能力是有上限。假如超过服务能力,一般会造成整个接口服务停顿,或者应用挂了,将延迟传递给服务调用方造成整个系统的服务能力丧失。要是对外的公开 API 接口服务,Rate limiting 应该是一个必备的功能,否极有可能被恶意调用导致服务宕掉,所以限流是必要的。这里本文就整理下常见的限流原理及方案。
流量控制更专业的叫法是:流量整形(traffic shaping),典型作用是限制流出某一网络的某一连接的流量与突发,使这类报文以比较均匀的速度向外发送。

二 常用方法

令牌桶(Token Bucket)和漏桶(leaky bucket)是 最常用的两种限流的算法。

2.1 漏桶算法

漏桶(Leaky Bucket)算法思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率.示意图如下:


可见这里有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate),在某些情况下,漏桶算法不能够有效地使用网络资源。因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使某一个单独的流突发到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。而令牌桶算法则能够满足这些具有突发特性的流量。通常,漏桶算法与令牌桶算法可以结合起来为网络流量提供更大的控制。

2.2令牌桶算法


令牌桶算法(Token Bucket)和 Leaky Bucket 效果一样但方向相反的算法,更加容易理解.随着时间流逝,系统会按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token(想象和漏洞漏水相反,有个水龙头在不断的加水),如果桶已经满了就不再加了.新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务.
令牌桶的另外一个好处是可以方便的改变速度. 一旦需要提高速率,则按需提高放入桶中的令牌的速率. 一般会定时(比如100毫秒)往桶中增加一定数量的令牌, 有些变种算法则实时的计算应该增加的令牌的数量.

三 guava RateLimiter

3.1RateLimiter 简介

Google开源工具包Guava提供了限流工具类RateLimiter,该类基于令牌桶算法(Token Bucket)来完成限流,非常易于使用.RateLimiter经常用于限制对一些物理资源或者逻辑资源的访问速率.它支持两种获取permits接口,一种是如果拿不到立刻返回false,一种会阻塞等待一段时间看能不能拿到.

RateLimiter经常用于限制对一些物理资源或者逻辑资源的访问速率。与Semaphore 相比,Semaphore 限制了并发访问的数量而不是使用速率。(注意尽管并发性和速率是紧密相关的,比如参考Little定律)

通过设置许可证的速率来定义RateLimiter。在默认配置下,许可证会在固定的速率下被分配,速率单位是每秒多少个许可证。为了确保维护配置的速率,许可会被平稳地分配,许可之间的延迟会做调整。
可能存在配置一个拥有预热期的RateLimiter 的情况,在这段时间内,每秒分配的许可数会稳定地增长直到达到稳定的速率。

有一点很重要,那就是请求的许可数从来不会影响到请求本身的限制(调用acquire(1) 和调用acquire(1000) 将得到相同的限制效果,如果存在这样的调用的话),但会影响下一次请求的限制,也就是说,如果一个高开销的任务抵达一个空闲的RateLimiter,它会被马上许可,但是下一个请求会经历额外的限制,从而来偿付高开销任务。注意:RateLimiter 并不提供公平性的保证。

3.2 code

我们要实现一个基于速率的单机流控框架的时候,RateLimiter 是一个完善的核心组件,下面是demo

import java.util.concurrent.ConcurrentMap;import com.google.common.collect.Maps;
import com.google.common.util.concurrent.RateLimiter;public class TrafficShaper {//key-value(serverice,qps)private static final ConcurrentMap<String, Double> resourceMap = Maps.newConcurrentMap();//userkey-service limiterprivate static final ConcurrentMap<String, RateLimiter> userresourceLimiterMap = Maps.newConcurrentMap();static {//initresourceMap.put("aaa", 50.0);}public static void updateResourceQps(String resource, double qps) {resourceMap.put(resource, qps);}public static void removeResource(String resource) {resourceMap.remove(resource);}public static int enter(String resource,String userkey)  {long t1 = System.currentTimeMillis();double qps = resourceMap.get(resource);//服务不限流if (qps == 0.0) {return 0;}String keyser = resource+userkey;RateLimiter keyserlimiter = userresourceLimiterMap.get(keyser);//if null,new limiter if(keyserlimiter == null){keyserlimiter =RateLimiter.create(qps);RateLimiter putByOtherThread = userresourceLimiterMap.putIfAbsent(keyser, keyserlimiter);if (putByOtherThread != null) {keyserlimiter = putByOtherThread;}keyserlimiter.setRate(qps);}//tryacquireif (!keyserlimiter.tryAcquire()) {        	System.out.println("use:"+(System.currentTimeMillis()-t1)+"ms;"+resource+"  visited  too frequently  by key:"+userkey);return 99;}else{System.out.println("use:"+(System.currentTimeMillis()-t1)+"ms;");return 0;}}public static void main(String[] args) throws InterruptedException {// TODO Auto-generated method stubint i=0;while(true){i++;long t2 = System.currentTimeMillis();System.out.println(t2+":qq:"+i);	int res =	TrafficShaper.enter("aaa", "qq");System.out.println((System.currentTimeMillis()-t2)+":qq:"+i);		if(res ==99){					i=0;Thread.sleep(1000);}}		}
}
简单说明下,这里核心方法是enter,入参是两个,分别是服务名称跟用户key.预期效果就是开放API对于用户来说某个服务只允许调用最大次数。

运行结果:


3.3 API接口

修饰符和类型 方法和描述
doubleacquire()
从RateLimiter获取一个许可,该方法会被阻塞直到获取到请求
doubleacquire(int permits)
从RateLimiter获取指定许可数,该方法会被阻塞直到获取到请求
static RateLimitercreate(double permitsPerSecond)
根据指定的稳定吞吐率创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少查询)
static RateLimitercreate(double permitsPerSecond, long warmupPeriod, TimeUnit unit)
根据指定的稳定吞吐率和预热期来创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少个请求量),在这段预热时间内,RateLimiter每秒分配的许可数会平稳地增长直到预热期结束时达到其最大速率。(只要存在足够请求数来使其饱和)
doublegetRate()
返回RateLimiter 配置中的稳定速率,该速率单位是每秒多少许可数
voidsetRate(double permitsPerSecond)
更新RateLimite的稳定速率,参数permitsPerSecond 由构造RateLimiter的工厂方法提供。
StringtoString()
返回对象的字符表现形式
booleantryAcquire()
从RateLimiter 获取许可,如果该许可可以在无延迟下的情况下立即获取得到的话
booleantryAcquire(int permits)
从RateLimiter 获取许可数,如果该许可数可以在无延迟下的情况下立即获取得到的话
booleantryAcquire(int permits, long timeout, TimeUnit unit)
从RateLimiter 获取指定许可数如果该许可数可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可数的话,那么立即返回false (无需等待)
booleantryAcquire(long timeout, TimeUnit unit)
从RateLimiter 获取许可如果该许可可以在不超过timeout的时间内获取得到的话,或者如果无法在timeout 过期之前获取得到许可的话,那么立即返回false(无需等待)

3.4 源码分析

RateLimiter主要源码分析
两个create函数用于构建不同形式的RateLimiter
public static RateLimiter create(double permitsPerSecond)
用于创建SmoothBursty类型的RateLimiter
public static RateLimiter create(double permitsPerSecond,long warmupPeriod,TimeUnit unit)
用于创建SmoothWarmingUp类型的RateLimiter.API注释上比较长,如下:
根据指定的稳定吞吐率和预热期来创建RateLimiter,这里的吞吐率是指每秒多少许可数(通常是指QPS,每秒多少查询),在这段预热时间内,RateLimiter每秒分配的许可数会平稳地增长直到预热期结束时达到其最大速率(只要存在足够请求数来使其饱和)。同样地,如果RateLimiter 在warmupPeriod时间内闲置不用,它将会逐步地返回冷却状态。也就是说,它会像它第一次被创建般经历同样的预热期。返回的RateLimiter 主要用于那些需要预热期的资源,这些资源实际上满足了请求(比如一个远程服务),而不是在稳定(最大)的速率下可以立即被访问的资源。返回的RateLimiter 在冷却状态下启动(即预热期将会紧跟着发生),并且如果被长期闲置不用,它将回到冷却状态。
下面以acquire为例子,看下源码的实现
 public double acquire() {return acquire(1);}public double acquire(int permits) {long microsToWait = reserve(permits);stopwatch.sleepMicrosUninterruptibly(microsToWait);//<span style="color: rgb(0, 128, 0); font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; line-height: 1.42857143; background-color: rgb(245, 245, 245);"><span style="font-size:10px;">等待,当未达到限制时,microsToWait为0</span></span>
return 1.0 * microsToWait / SECONDS.toMicros(1L);}final long reserve(int permits) {checkPermits(permits);//<span style="color:#006600;">参数校验>0</span>synchronized (mutex()) {//<span style="color:#006600;">并发的情况下同步</span>return reserveAndGetWaitLength(permits, stopwatch.readMicros());//<span style="color:#006600;">获取需要等待的时间</span>}}
  final long reserveAndGetWaitLength(int permits, long nowMicros) {long momentAvailable = reserveEarliestAvailable(permits, nowMicros);return max(momentAvailable - nowMicros, 0);}
 abstract long reserveEarliestAvailable(int permits, long nowMicros);
这是个抽象接口,我们看下具体实现类SmoothRateLimiter:
  @Overridefinal long reserveEarliestAvailable(int requiredPermits, long nowMicros) {resync(nowMicros);//<span style="color:#006600;">补充令牌</span>long returnValue = nextFreeTicketMicros;double storedPermitsToSpend = min(requiredPermits, this.storedPermits);//<span style="color:#006600;">本次请求消耗的令牌数</span>double freshPermits = requiredPermits - storedPermitsToSpend;long waitMicros = storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)+ (long) (freshPermits * stableIntervalMicros);this.nextFreeTicketMicros = nextFreeTicketMicros + waitMicros;//<span style="color:#006600;">计算下次可用时间</span>this.storedPermits -= storedPermitsToSpend;//<span style="color:#006600;">消耗令牌</span>return returnValue;}
 private void resync(long nowMicros) {//<span style="color:#006600;">补充令牌数,及更新下次可用令牌毫秒数</span>
// if nextFreeTicket is in the past, resync to now
if (nowMicros > nextFreeTicketMicros) {
storedPermits = min(maxPermits,
storedPermits + (nowMicros - nextFreeTicketMicros) / stableIntervalMicros);
nextFreeTicketMicros = nowMicros;
}
}

对于 storedPermitsToWaitTime,这是一个抽象接口,
  /*** Translates a specified portion of our currently stored permits which we want to* spend/acquire, into a throttling time. Conceptually, this evaluates the integral* of the underlying function we use, for the range of* [(storedPermits - permitsToTake), storedPermits].** <p>This always holds: {@code 0 <= permitsToTake <= storedPermits}*/abstract long storedPermitsToWaitTime(double storedPermits, double permitsToTake);

RateLimiter实际上由两种实现策略,其实现分别见SmoothBursty和SmoothWarmingUp。

3.4.1SmoothBursty

SmoothBursty使用storedPermits不需要额外等待时间。并且默认maxBurstSeconds为1,因此maxPermits为permitsPerSecond,即最多可以存储1秒的剩余令牌,比如QPS=4,则maxPermits=4.
<span style="font-size:12px;"> static final class SmoothBursty extends SmoothRateLimiter {/** The work (permits) of how many seconds can be saved up if this RateLimiter is unused? */final double maxBurstSeconds;     SmoothBursty(SleepingStopwatch stopwatch, double maxBurstSeconds) {super(stopwatch);this.maxBurstSeconds = maxBurstSeconds;}  @Overridevoid doSetRate(double permitsPerSecond, double stableIntervalMicros) {double oldMaxPermits = this.maxPermits;maxPermits = maxBurstSeconds * permitsPerSecond;if (oldMaxPermits == Double.POSITIVE_INFINITY) {// if we don't special-case this, we would get storedPermits == NaN, belowstoredPermits = maxPermits;} else {storedPermits = (oldMaxPermits == 0.0)? 0.0 // initial state: storedPermits * maxPermits / oldMaxPermits;}}  @Overridelong storedPermitsToWaitTime(double storedPermits, double permitsToTake) {return 0L;}}</span>
 RateLimiter 允许某次请求拿走超出剩余令牌数的令牌,但是下一次请求将为此付出代价,一直等到令牌亏空补上,并且桶中有足够本次请求使用的令牌为止 2 。这里面就涉及到一个权衡,是让前一次请求干等到令牌够用才走掉呢,还是让它先走掉后面的请求等一等呢?Guava 的设计者选择的是后者,先把眼前的活干了,后面的事后面再说。这里我看网上举了例子便于理解,以每秒qps=4,头两步消耗4个,剩余存储4个。在第三步的时候之前存储了4个,加上本次的共8个,但是本次请求了10个,所以透支了2个,第四次请求的时候,需要补上2个,等待0.5秒。
(1).t=0,这时候storedPermits=0,请求1个令牌,等待时间=0;
(2).t=1,这时候storedPermits=3,请求3个令牌,等待时间=0;
(3).t=2,这时候storedPermits=4,请求10个令牌,等待时间=0,超前使用了2个令牌;
     (4).t=3,这时候storedPermits=0,请求1个令牌,等待时间=0.5;

3.4.2SmoothWarmingUp

static final class SmoothWarmingUp extends SmoothRateLimiter {private final long warmupPeriodMicros;/*** The slope of the line from the stable interval (when permits == 0), to the cold interval* (when permits == maxPermits)*/private double slope;private double halfPermits;SmoothWarmingUp(SleepingStopwatch stopwatch, long warmupPeriod, TimeUnit timeUnit) {super(stopwatch);this.warmupPeriodMicros = timeUnit.toMicros(warmupPeriod);}@Overridevoid doSetRate(double permitsPerSecond, double stableIntervalMicros) {double oldMaxPermits = maxPermits;maxPermits = warmupPeriodMicros / stableIntervalMicros;halfPermits = maxPermits / 2.0;// Stable interval is x, cold is 3x, so on average it's 2x. Double the time -> halve the ratedouble coldIntervalMicros = stableIntervalMicros * 3.0;slope = (coldIntervalMicros - stableIntervalMicros) / halfPermits;if (oldMaxPermits == Double.POSITIVE_INFINITY) {// if we don't special-case this, we would get storedPermits == NaN, belowstoredPermits = 0.0;} else {storedPermits = (oldMaxPermits == 0.0)? maxPermits // initial state is cold: storedPermits * maxPermits / oldMaxPermits;}}@Overridelong storedPermitsToWaitTime(double storedPermits, double permitsToTake) {double availablePermitsAboveHalf = storedPermits - halfPermits;long micros = 0;// measuring the integral on the right part of the function (the climbing line)if (availablePermitsAboveHalf > 0.0) {double permitsAboveHalfToTake = min(availablePermitsAboveHalf, permitsToTake);micros = (long) (permitsAboveHalfToTake * (permitsToTime(availablePermitsAboveHalf)+ permitsToTime(availablePermitsAboveHalf - permitsAboveHalfToTake)) / 2.0);permitsToTake -= permitsAboveHalfToTake;}// measuring the integral on the left part of the function (the horizontal line)micros += (stableIntervalMicros * permitsToTake);return micros;}private double permitsToTime(double permits) {return stableIntervalMicros + permits * slope;}}
maxPermits等于热身(warmup)期间能产生的令牌数,比如QPS=4,warmup为2秒,则maxPermits=8.halfPermits为maxPermits的一半.

这个图还不是很理解,对比上一个实现方式,就是不能透支,需要的资源就等待。这里待测试验证。

四 其他常见实现方式

4.1Proxy 层的实现,针对部分 URL 或者 API 接口进行访问频率限制

Nginx 模块

limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
server {location /search/ {limit_req zone=one burst=5;}

 详细参见:  ngx_http_limit_req_module

Haproxy 提供的功能

详细参见:  Haproxy Rate limit 模块

4.2基于 Redis 功能的实现

这个在 Redis 官方文档有非常详细的实现。一般适用于所有类型的应用,比如 PHP、Python 等等。Redis 的实现方式可以支持分布式服务的访问频率的集中控制。Redis 的频率限制实现方式还适用于在应用中无法状态保存状态的场景。

参见:Redis INCR rate limiter


参考:
http://xiaobaoqiu.github.io/blog/2015/07/02/ratelimiter/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/28981.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

异常流量检测

项目目标是为了检测网络异常流量&#xff0c;防止网络攻击行为&#xff0c;本人参与了初期的工作&#xff0c;进行了文献阅读-数据处理-模型构建-参数优化工作。 网络攻击行为主要分为Dos、U2R、Probe等&#xff0c;其对应的流量异常特征为集合异常、点异常、上下文异常。 点异…

网络流量监控分析工具ntopng的安装与使用

我写这篇文章的起因&#xff1a;网上介绍ntopng这款工具的博客不算很多&#xff0c;而且安装方法基本没一个行得通&#xff08;可能是版本更新太快了&#xff09;&#xff0c;我在安装过程中遇到了一些问题&#xff0c;想跟大家分享下&#xff1b;其次&#xff0c;在讲使用方法…

流量异常检测

https://mp.weixin.qq.com/s/9h-hOt630W6k077Rupc9CA 流量异常检测主要有以下三个难点&#xff1a; 流量的大小会随着用户行为发生变化。对于大部分百度云上的业务&#xff0c;白天的访问流量较高&#xff0c;深夜的访问流量较低。这使得流量水位值存在上下文相关性&#xff0…

Android应用流量统计——NetworkStatsManager使用

在没有Root的情况下&#xff0c;Android应用流量统计在6.0之前一直没有太好的办法&#xff0c;官方虽然提供了TrafficStats&#xff0c;但其主要功能是设备启动以来流量的统计信息&#xff0c;和时间信息无法很好的配合。最近再看TrafficStats类时&#xff0c;发现说明中提到&a…

仿设置流量使用——细讲android获取流量使用情况,以及解决调用流量接口不准问题(非TrafficStats,而是NetworkStatsHistory)

不积跬步无以至千里 流量使用情况,好多软件都会带这个功能,比如360的流量监控,好多之类的,手机管家都会带上这个流量计算的功能,连系统应用设置里面也会带一个流量使用情况的查看功能,为什么呢?因为流量的使用关乎到用户使用流量的计费,当流量使用了很多,会给用…

vnstat流量统计(2.8版本)

vnstat流量统计&#xff08;2.8版本&#xff09; vnStat 是一个基于控制台的 Linux 和 BSD 网络流量监视器&#xff0c;它为所选接口保留网络流量日志。它使用内核提供的网络接口统计信息作为信息源。这意味着 vnStat 实际上不会嗅探任何流量&#xff0c;并且无论网络流量率如…

中职流量包分析attack/capture(1)

我希望网络安全的世界大家可以贡献自己的一部分&#xff0c;而不是拿来自私自利 作者拿到的流量包和题目是有出入的&#xff0c;但是因为出的题大同小异所以能分析出来 attack 1. 分 析 attack.pcapng 数 据 包 文 件 &#xff0c;通 过 分 析数据 包 attack.pcapng 找出恶意…

抓包部分软件时无网络+过代理检测 解决办法 安卓黄鸟httpcanary+vmos

解决软件抓包时无网络和代理检测&#x1f680; 需要准备的工具&#xff1a; 安卓手机 vmos pro 需要抓包的软件 第一步&#xff1a;下载好相应版的本的vmos room 第二步&#xff1a;文件中转站->我要导入->导入对应真机需要抓包APP 第三步&#xff1a;测试软件在vmos…

测试apk-异常管控NetTraffic攻击者开发

1. 目的 基于《软件绿色联盟应用体验标准》中 NetTraffic 资源的定义&#xff0c;对 NetTraffic 后台多次小流量数据包的行为模拟。旨在触发手机中异常功耗管控机制。 本次灭屏NetTraffic使用次数至少超过的二个等级:30次,60次&#xff0c;执行如下判断&#xff1a; 绿线不管控…

雷电模拟器无法修改网络,没有出现修改网络的选项,导致fiddler无法连接

对于一个小白来说&#xff0c;可能这就能耗掉一个下午的时间了&#xff0c;比如我&#xff0c;&#xff0c;&#xff0c;&#xff0c;要命的是这种问题对于绝大多数小白还完全不是问题&#xff0c;所以找了很久都没有解决答案&#xff0c;所以我是。。小白中的小白。。 模拟器…

TrackingNet上进行评估

TrackingNet上进行评估 说明&#xff1a;在目标跟踪测试数据集中&#xff0c;在TrackingNet和GOT-10K上的评估结果需要通过在线评估的方式获取。 website&#xff1a;Welcome - EvalAI 自行注册账户&#xff0c;注册好后按照以下操作就可以进行评估了。 在All Changes中找到…

ARP欺骗攻击(流量图片)——dsniff与driftnet使用

ARP欺骗攻击&#xff08;流量&图片&#xff09; 原理&#xff1a; 首先我们![请添加图片描述](https://img-blog.csdnimg.cn/7de7923387224bcda1ea4be958032ae9.png 要明白何为ARP&#xff08;地址解析协议&#xff09;&#xff1a;是根据 IP地址 获取 物理地址 的一个 TC…

Google pixel 原生安卓出现 WiFi 网络受限、优化网速、网络无法连接问题

谷歌从 Android 5.0 开始就引入了「Captive Portal」机制&#xff0c;主要用来检测 WiFI 网络认证是否正常&#xff0c;默认检测访问的是谷歌服务器。 众所周知谷歌服务器是需要404工具才能正常访问&#xff0c;所以如果你没有404工具的情况下&#xff0c;WiFi 就会出现网络受…

悉尼科技大学计算机专业就业,悉尼科技大学计算机专业怎么样

悉尼科技大学计算机科学是一门包含各种各样与计算和信息处理相关主题的系统学科&#xff0c;从抽象的算法分析、形式化语法等等&#xff0c;到更具体的主题如编程语言、程序设计、软件和硬件等。信息化产业的今天&#xff0c;这类专业的重要性也愈加显现。悉尼科技大学的互联网…

悉尼大学计算机专业本科2019,2019申请悉尼大学读本科有哪些要求

悉尼大学是澳洲名校&#xff0c;每年都有不少学生慕名前来留学。那你们知道申请悉尼大学读本科有哪些要求呢? 大师兄留学网【留学网 dsxliuxue.com】小编为大家带来悉尼大学申请条件&#xff0c;希望对大家有帮助。 悉尼大学本科申请条件&#xff1a; 学术要求&#xff1a; 对…

悉尼大学理学院计算机科学,澳洲悉尼大学理学院中国留学生

1 悉尼大学理学院简介 据立思辰留学360介绍&#xff0c;悉尼大学理学院的正式建立是1882年。在之后的50年内&#xff0c;悉尼大学理学院一共培养了353名本科学生&#xff0c;以及聘用了6名在物理&#xff0c;化学&#xff0c;动物学&#xff0c;地质学&#xff0c;植物学&#…

悉尼大学计算机专业新生,2020年悉尼大学计算机科学专业课程设置难不难

悉尼大学计算机科学专业课程设置难不难 阅读&#xff1a;786次 更新时间&#xff1a;2016-10-19 09:06:03 添加时间&#xff1a;2016-10-19 编辑&#xff1a;jingwen 来源&#xff1a; 悉尼大学 索取招生简章 已发送786份2020年招生简章 我对该学校感兴趣&#xff0c;请发资料给…

悉尼大学商业数据科学与计算机学院,悉尼大学数据科学专业

悉尼大学的数据科学硕士&#xff0c;比较适合热衷于从数据中挖掘有价值信息&#xff0c;并借此推动商业决策制定和研究成果的人士。悉尼大学数据科学硕士项目旨在培养学生的分析能力、专业技能&#xff0c;引导学生利用数据科学在专业领域作出战略性决策。同时&#xff0c;该项…

悉尼大学理学院计算机科学,悉尼大学理学院本科申请

悉尼大学理学院(Faculty of Science)共开设有以下11个学位项目&#xff0c;国际学生均可申请&#xff0c;分别是&#xff1a; 课程名称 课程英文名 学制 IELTS要求 预科GPA A-level IB课程 通识教育与科学学士 B Liberal Arts and Science 3年 6.5 (6.0) 6.7 BBC 27 医学科学学…

悉尼科大计算机专业,2020年悉尼科技大学专业排名

悉尼科技大学(University of Technology Sydney)&#xff0c;简称“悉尼科大”(UTS)&#xff0c;世界百强名校。是一所位于澳大利亚第一大城市悉尼的著名公立研究型大学。学校在2020年与美国匹兹堡大学并列QS世界大学排名第140名&#xff0c;2019年获得世界五星级高校认证。 悉…