`
shixiaomu
  • 浏览: 383818 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

linux 简单限速 tc iptables

 
阅读更多
/sbin/tc qdisc add dev eth0 root tbf rate  20kbit latency 50ms burst 1540
限制速度20k(适合我的特定环境),问一下,tc是控制出网卡的速度是吧?
(附件:htb队列指南)


LINUX HTB队列规定是LINUX QOS 内容的部分, 主要是配合TC工具进行流量控制的一种算法, 和CBQ 比HTB有它自身的特点, 有关CBQ的资料相对比较多一些. 这是HTB网站上的一篇用户手册;

LINUX HTB队列规定用户指南

HTB Linux queuing discipline manual - user guide
Martin Devera aka devik (devik@cdi.cz)
Manual: devik and Don Cohen
Last updated: 5.5.2002
译者:龚关 gongguan008@163.com
1. Introduction 介绍
2. Link sharing 链路共享
3. Sharing hierarchy 共享层次
4. Rate ceiling 速率限度
5. Burst 突发
6. Priorizing bandwidth share 带宽分配优先
7. Understanding statistics 查看统计
8. Making, debugging and sending error reports 开发,调试和错误报告
1. Introduction 介绍
HTB 意味着是一个更好理解更容易掌握的可以快速替换LINUX CBQ 队列规定的队列, CBQ和HTB都可以帮助你限制你的链路上的出口带宽;他们允许你把一条物理链路模拟成几条更慢的链路或者是把发出的不同类型的流量模拟成不同的连接,在他们的实际应用中, 你必须指定怎么分配物理链路给各种不同的带宽应用并且如何判断每种不同的应用的数据包是怎么样被发送的;

这篇文章将告诉你怎么使用 HTB . 这里有很多的例子和分析图以及一些特殊问题的讨论.

这个HTB的发布版本已经有更多的升级, 详细情况请看HTB 的主页.

请先查阅: TC 工具 (不仅仅是HTB ) 有关速率的单位换算:

kbps = kilo bytes kbit = kilo bits

2. Link sharing 链路共享

案例: 我们有两不同的用户A和B, 都通过网卡 eth0 连接到 internet ,我们想分配 60 kbps的带宽给B 和 40 kbps的带宽给A, 接下来我们想对A用户的带宽再做一个分配, 给30 kbps的带宽给WWW服务, 30 kbps的带宽给其他用途; 任何没有用的带宽可以分配和其他需要带宽类 (在分配的总带宽允许的范围内的部分)

HTB 可以保障提供给每个类带宽的数量是它所需求的最小需求或者等于分配给它的数量.当一个类需要的带宽少于分配的带宽时,剩余的带宽被分配给其他需要服务的类.

注: 这里这种情况被称为”借用”剩余带宽, 我们以后将用这个术语, 但无论如何,好像很不好因为这个”借用”是没有义务偿还的.

上面所提到的不同类型的流量在HTB里表现为类, 上面是一个简单的分布图.

我们来看看所用到的命令:

tc qdisc add dev eth0 root handle 1: htb default 12
这条命令分配了HTB队列规定给 eth0 并且指定了一个名称为(handle" 1 句柄 1: , 这个名称用于标识它下面的子类, default 12 的意思是没有被分类的流量被分配到类 1:12

注: 一般 (不仅仅是HTB其他所有TC的队列和类),句柄都被写成 X:Y 这里X是队列规定的整数型的标识符,Y是这个队列规定的类的整数型标识符,队列规定的句柄标识符的Y必须是0,而句柄的类的标识符的数值必须是一个非零的整数. "1:" 等同于 "1:0".

tc class add dev eth0 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 30kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:11 htb rate 10kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:12 htb rate 60kbps ceil 100kbps
第一行在队列1:下创建了一个根类1:1,并且定义了HTB队列规定作为这个根类的父类,一个根类可以像队列规定下其他类一样允许它的子类相互借用带宽, 但是根类之间不能相互借用带宽,我们可以在HTB队列下直接创建三个类,但是其中一个类的剩余带宽不能够借用给其他需要的类,在这种情况下我们想允许带宽借用,所以我们为根类创建扩展类并且让这些类在根类的范围内发送数据,我们定义了下面的三行, ceil参数我们在以后将讲述.

注: 有时候人们会问我为什么他们必须重复dev eth0 描述在他们已经定义并使用了handle 或者parent ,原因是本地接口比如eth0 和eth1他们各自都可能会有类的句柄表示为1:1.

我们还必须描述那些数据包属于那个类, 有关详细内容请查看有关TC 过虑器的相关文档. 命令看起来像下面这样:

tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
match ip src 1.2.3.4 match ip dport 80 0xffff flowid 1:10
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 \
match ip src 1.2.3.4 flowid 1:11
(We identify A by its IP address which we imagine here to be 1.2.3.4.)

(我们根据它的IP地址进行分类识别,这里我们假设为1.2.3.4)

注:U32过虑器有一个非文档化的设计会导致在你使用U32分类器”tc filter show”命令时会显示出不同的prio的值.

你可能会注意到我们没有为类1:12创建过虑, 很明显,这个例子中被用作缺省, 就是没有被上面两条分类规则定义的任何数据包 (任何原地址非1.2.3.4)将被发送到类1:12

现在我们可以很方便的为队列规定分配子类, 如果没有指定缺省是pfifo

tc qdisc add dev eth0 parent 1:10 handle 20: pfifo limit 5
tc qdisc add dev eth0 parent 1:11 handle 30: pfifo limit 5
tc qdisc add dev eth0 parent 1:12 handle 40: sfq perturb 10


这是我们所需要的全部命令, 让我们来看看有什么事情发如果我们给每个类发送90kbps的数据然后停止发送其中一个类在某一时刻.在图的底部标有"0:90k". 标签中央水平位置 (在9附近.同时标有红色1)现实了数据流量随时间的变化情况.冒号之前是类的标识符;(0表示类1:10, 1 表示类 1:11, 2 表示类 1:12)冒号之后是新的速率在那个时间有标注. 比如类0在时间0的时候速率改变为90K ;在时间3为0K (0= 0k) ,在时间6时返回90K;

最初所有的类共同流量为90kb. 以后以被指定更高的速度传输, 每一个类都被限制在其被指定的速率, 在时间3的时候我们停止传送类0的数据, 分配给类0的速率被分配给其他两个类.如图所示1至6内的类1和类2 (很难看出类1的增长因为它只有4kbps.) 同样在时间9时类1流量停止它的带宽被分配到另外两个类(类0的增长同样很难看出), 在时间15类2被分配给类0和类1, 在时间18 类1和类2 同时停止,所以类0得到它所需要的所有90 kbps.带宽.

现在是个接触quantums概念的很好的时机.实际上当一些想借用带宽的类服务于其他竞争的类之前相互给定的一定数量的字节, 这个数量被称为quantums . 你应该明白如果一些竞争的类是可以从它的父类那里得到所需的quantums; 精确的指定quantums的数量尽可能的小并其大于MTU是很重要的.

一般你不需要手工指定一个quantums因为HTB会根据计算选择数值.计算类的quantum相对于用r2q参数分配; 它的缺省的值是10因为典型的MTU是1500,缺省值很适合速率为15 kBps (120 kbit).当你创建队列最小的速率指定r2q 1, 比较适合速率为12 kbit;如果你需要手工指定quantum 当你添加或者更改类,如果预想计算的值是不适合的你可以清除日志里的警告. 当你用命令行指定了quantum 类的r2q将被忽略.

如果A和B是不同的客户这个解决方案看起来很好, 但是如果A 付了40kbps 他可能更希望他不用的WWW的带宽可以用在自己的其他服务上而并不想分享个B. 这种需求是可以通过HTB的类的层次得到解决的.

3. Sharing hierarchy 共享层次


前面章节的问题在这一节里通过类层次结构来得到解决, 用户A 可以很清楚的表达自己的类; 回到前面我们说过提供给每个类带宽的数量是它所需求的最小需求或者等于分配给它的数量. 这样可以用在其他非父类的HTB类里. 我们叫他们为子类, 对于HTB的父类来说我们称为内部类, 规则是使用服务的总量最小而且总量等于他的子类所请求的总和.这里我们分配40kbps给用户A ,这就意味着如果A的需求少于分配的WWW带宽, 那么剩下的将被用来服务于A的其他应用.(如果有需要), 至少总和为40kbps.

注:数据包的分类规则可以分配给内部节点, 也可以有分配其他的过虑器给内部节点,最终应该到达子类或者是特定的类class 1:0 ;父类提供的速率应该是它所有子类的总和.

现在的命令如下:

tc class add dev eth0 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:2 htb rate 40kbps ceil 100kbps



tc class add dev eth0 parent 1:2 classid 1:10 htb rate 30kbps ceil 100kbps
tc class add dev eth0 parent 1:2 classid 1:11 htb rate 10kbps ceil 100kbps
tc class add dev eth0 parent 1:1 classid 1:12 htb rate 60kbps ceil 100kbps
我们现在来看看流量图显示的我们用层次结构的解决方案. 当A的WWW流量停止, 它所分配的带宽被二次分配到它的其他流量上, 所以A的总带宽仍然为40kbps.如果A的总请求带宽小于40kbps.那么剩余的流量将被分配给B.

4. Rate ceiling 速率限度


参数ceil指定了一个类可以用的最大带宽, 用来限制类可以借用多少带宽.缺省的ceil是和速率一样.(也是我们为什么必须在上面的例子里指定它用来显示借用带宽的上限)我们改变前面例子里的类 1:2 (A) 和1:11 (A's other) ceil 100kbps 分别为ceil 60kbps 和ceil 20kbps.

和前面的图显示不同, 在时间3 (WWW 流量停止) 因为A 的其他流量限制在20kbps. 所以用户A得到仅仅总带宽20kbps没有用的20kbps被分配给了B .

第二个不同是在时间15时B停止, 因为没有ceil, 所有它的带宽被给了A , 但是现在A 仅仅允许使用60kbps,所以剩余的40kbps 闲置.

这个特性对于ISP是很有用的, 因为他们一般限制被服务的用户的总量即使其他用户没有请求服务.(ISPS 很想用户付更多的钱得到更好的服务) ,注根类是不允许被借用的, 所以没有指定ceil

注: ceil的数值应该至少和它所在的类的速率一样高, 也就是说ceil应该至少和它的任何一个子类一样高

5. Burst 突发
网络硬件只能在一个时间发送一个包这仅仅取决于一个硬件的速率. 链路共享软件可以利用这个能力动态产生多个连接运行在不同的速度. 所以速率和ceil不是一个即时度量只是一个在一个时间里发送包的平均值. 实际的情况是怎样使一个流量很小的类在某个时间类以最大的速率提供给其他类. burst 和cburst 参数控制多少数据可以以硬件最大的速度不费力的发送给需要的其他类.

如果cburst 小于一个理论上的数据包他形成的突发不会超过ceil 速率, 同样的方法TBF的最高速率也是这样.

你可能会问, 为什么需要bursts . 因为它可以很容易的提高向应速度在一个很拥挤的链路上. 比如WWW 流量是突发的. 你访问主页. 突发的获得并阅读. 在空闲的时间burst将再"charge"一次.

注: burst 和cburst至少要和其子类的值一样大.

如图, 接着前一章的例子,我改变burst给红和黄(agency A)类20 kb但cburst仍然为缺省(cca 2 kb).绿色的峰出现在时间13由于在SMTP类设置了burst;A类在限度下自从时间9并且聚集了20 kb的突发流量,峰高于20 kbps(被ceil参数限制因为它的cburst接近包的尺寸),聪明的读者可能会问为什么在时间7处没有红色和黄色的峰;因为黄色已经接近ceil所以没有空间用于突发;有一个不必要的人为的低谷在时间4, 那是因为我忘记添加burst 给根连接到(1:1)类;峰从时间1并且当时间4蓝色的类想借用黄色的速率被拒绝并且自己补偿;

局限性: 当你在计算机上用一个小的时间片操作一个高速链路 你需要为所有的类设置很小的burst 和cburst . 在i386系统上是10ms 在Alphas.系统是1ms ;最小的burst可以max_rate*timer 被估算出来; 所以10Mbit的速率在i386 系统上 burst为 12kb

如果你设置太小的burst 你可能会得到比你设置更小的速率, 后来TC 工具在你没有指定burst.时将估计并且设置一个最小且可能的burst.

6. Priorizing bandwidth share 带宽分配优先


带宽分配的优先级包括两个方面, 首先它影响到子类剩余带宽的分配, 到现在我们已经知道剩余带宽按照速率比例来分配, 我以第三节的配置为例(没有设置ceiling 和 bursts的层次结构 )除了SMTP (green)的优先权改为0(更高) 其他所以类都改为1

从视图我们可以看到类得到了所有剩余带宽, 规则是优先权越高的类越优先得到剩余带宽., 但必须是在rate 和 ceil得到保障的前提下.

另一个方面的问题,包的延时, 在以太网里的延时度量是很困难的,但有一个简单的办法.我们添加一个带宽小于100 kbps的HTB类.第二个类(我们测量的)作为一个子类,然后我们模仿成更慢并且延时比较大的链路.

出于简单的原因, 我们用两个有关联的类;

# qdisc for delay simulation
tc qdisc add dev eth0 root handle 100: htb
tc class add dev eth0 parent 100: classid 100:1 htb rate 90kbps

# real measured qdisc
tc qdisc add dev eth0 parent 100:1 handle 1: htb
AC="tc class add dev eth0 parent"
$AC 1: classid 1:1 htb rate 100kbps
$AC 1:2 classid 1:10 htb rate 50kbps ceil 100kbps prio 1
$AC 1:2 classid 1:11 htb rate 50kbps ceil 100kbps prio 1
tc qdisc add dev eth0 parent 1:10 handle 20: pfifo limit 2
tc qdisc add dev eth0 parent 1:11 handle 21: pfifo


limit 2


注: 另一个HTB的子类和同一个HTB内的子类是不一样的, 因为HTB的类发送数据和硬件发送能力一样的, 所以在限度以内的数据发送仅仅取决于设备速度而不是上级类; HTB下的HTB类输出是模拟一个逻辑硬件; (大的延时)



假定速率同为50 kbps的两个类在时间3S 时执行命令如下:

tc class change dev eth0 parent 1:2 classid 1:10 htb \
rate 50kbps ceil 100kbps burst 2k prio 0

你可以看到WWW的延时趋近于0而SMTP的延时增大. 当你的优先级别更高而其他类的延时就更大.稍后在7S 时,模仿WWW以60 kbps和SMTP 以40 kbps.发送数据.你可以看到另一个有趣的现象.当WWW越限之后HTB首先是限制带宽.

什么样的类需要优先权? 一般需要延时低的类; 比如视频和音频流; (你必须使用正确的流量速率防止流量相互淹没. ) 或者是交互性(TELNET .SSH )流量正常突发并且不影响其他的流量.

提高ICMP的优先权可以得到一个很好的PING的延时返回, 但这是一个假相, 因为从技术角度来说在测试联通性时这种情况并不是你想要的.



7. Understanding statistics 查看统计
TC 工具允许你对LINUX队列规定进行统计; 不幸的是统计结果作者没有解释所以你不能经常用到他们; 这里我尽力解释来帮助理解HTB的状态; 首先是HTB的整体状态. 下面是第三节里的一个片段;

# tc -s -d qdisc show dev eth0
qdisc pfifo 22: limit 5p
Sent 0 bytes 0 pkts (dropped 0, overlimits 0)

qdisc pfifo 21: limit 5p
Sent 2891500 bytes 5783 pkts (dropped 820, overlimits 0)

qdisc pfifo 20: limit 5p
Sent 1760000 bytes 3520 pkts (dropped 3320, overlimits 0)

qdisc htb 1: r2q 10 default 1 direct_packets_stat 0
Sent 4651500 bytes 9303 pkts (dropped 4140, overlimits 34251)

前三个规定是HTB的子队列, 我们跳过他们因为PFIFO的状态是自我解释的. Overlimit告诉你有多少次队列延时了数据包; direct_packets_stat 告诉你有多少包直接通过队列被送出; 其他的解释是自我解释型的, 让我们看看类的状态;

tc -s -d class show dev eth0
class htb 1:1 root prio 0 rate 800Kbit ceil 800Kbit burst 2Kb/8 mpu 0b
cburst 2Kb/8 mpu 0b quantum 10240 level 3
Sent 5914000 bytes 11828 pkts (dropped 0, overlimits 0)
rate 70196bps 141pps
lended: 6872 borrowed: 0 giants: 0

class htb 1:2 parent 1:1 prio 0 rate 320Kbit ceil 4000Kbit burst 2Kb/8 mpu 0b
cburst 2Kb/8 mpu 0b quantum 4096 level 2
Sent 5914000 bytes 11828 pkts (dropped 0, overlimits 0)
rate 70196bps 141pps
lended: 1017 borrowed: 6872 giants: 0

class htb 1:10 parent 1:2 leaf 20: prio 1 rate 224Kbit ceil 800Kbit burst 2Kb/8 mpu 0b
cburst 2Kb/8 mpu 0b quantum 2867 level 0
Sent 2269000 bytes 4538 pkts (dropped 4400, overlimits 3635
rate 14635bps 29pps
lended: 2939 borrowed: 1599 giants: 0


我删除了类1:11 和 1:12 以便输出更简单扼要; 可以看到有我们设置的参数, 还有level 和 DRR quantum 信息;

overlimits 显示了有多少次类要求被发送数据而被rate/ceil 限制不能发送;(现在显示的仅仅是子类)

rate, pps 告诉你通过类实际的速率(10秒的平均值) 他和你选择的速率是一样的.

Lended 这个类借出的包 ; borrowed 则是被借入的数据包从父类;

Giants 显示了大于TC命令设置的MTU的数据包的数量;HTB和其协调工作,否则将会影响速率的精确性,, 添加 MTU 到你的TC命令里 (缺省是1600 bytes)

8. Making, debugging and sending error reports
开发, 调试和发送错误报告
如果你拥有kernel 2.4.20或者更新的内核你就不必要打补丁, 但你需要更新TC 工具从HTB 3.6 包里得到并且使用它;

为了和老内核工作协调, 下载内核源码, 用patch -p1 -i htb3_2.X.X.diff装载补丁程序, 然后用 make menuconfig;make bzImage; 编译内核时不要忘了选中QoS 和 HTB.

我将非常感激如果你认为在使用发现了HTB错误. 我需要详细的输出; 在队列规定出现异常行为时请在tc qdisc add .... htb.后面加上参数debug 3333333 ; 它将会在系统日志里记录一些调试记录,为此你可能需要在你的/etc/syslog.conf. 文件里加上kern.debug -/var/log/debug这一行. 通过压缩包电邮给我,并且付上问题描述和时间.





译者的说明:

由于工作需要用到HTB相关的资料,所以将此文进行了翻译, 因本人英文水平有限,晦涩难懂的地方翻译的并非理想, 希望能起到抛砖引玉的作用, 也希望网友不惜赐教.
分享到:
评论

相关推荐

    linux系统下通过tc命令实现对端口限速的脚本,自写脚本

    自己项目上有这样的需求,由于某个端口的业务功能占用的带宽太大影响了其他的业务模块,所以需要将端口进行网络流量的限制,经过翻阅资料发现linux系统下可通过tc命令实现对端口限速的脚本,所以自己写了这样一个...

    TC+IPTables实现下载和上传带宽限制脚本

    ### TC+IPTables 实现下载和上传带宽限制脚本详解 #### 一、概述 在 Linux 系统中,网络流量控制是一项重要的系统管理任务。通过对带宽进行合理分配和限制,可以有效地提高网络资源的利用率,保障关键业务的服务...

    LinuxTC流量限速[借鉴].pdf

    此外,Linux TC 流量限速还可以与其他网络技术结合使用,例如 iptables、NAT 等,从而实现更加复杂的网络流量控制和优化。 Linux TC 流量限速是一种功能强大且灵活的流量控制技术,它可以帮助我们实现网络流量的...

    linux流控 TC设置 超详细解析TC命令,流控原理

    Linux系统默认使用pfifo_fast排队规则,这是一种简单但比先进先出(FIFO)队列稍复杂的规则。pfifo_fast使用三个独立的FIFO队列,根据数据包的类型优先级进行处理。而流量控制子系统提供了更复杂的队列规则,如Token...

    LinuxTC流量限速.pdf

    根据给定文件内容,本文主要讨论Linux系统中使用Traffic Control (TC) 工具进行流量限速的技术和方法,具体知识点如下: 1.流量控制工具TC的介绍: TC是Linux内核提供的一套用于控制网络带宽的工具,它能够对网络...

    [Linux]使用linux下的TC进行服务器流量控制.pdf

    TC允许用户对通过网络接口的数据包进行控制,例如限速、延迟、丢包等。TC是Linux提供的一种强大的流量控制手段,通常与网络队列调度器(qdisc)和类别(class)相关联。 qdisc是Linux流量控制的基础构件,全称是...

    基于Linux下TC的网络流量管理.pdf

    TC模块是Linux内核提供的一种强大的工具,用于确保网络服务质量(QoS),它允许管理员对不同类型的网络流量进行分类、限速和优先级排序,以保证关键业务的顺畅运行。 TC的核心组成部分包括队列规定(Queuing ...

    一种基于Linux下TC的流量控制管理架构

    例如,可以使用`tc qdisc add`命令添加一个新的队列调度器,`tc class add`命令设置流量分类和限速,以及`tc filter add`命令定义过滤规则,将特定类型的数据包分到指定的类。 此外,TC还可以与iptables等防火墙...

    Linux下利用TC工具控制网络流量[收集].pdf

    【Linux TC工具详解】 Linux TC(Traffic Control)工具是一个强大的网络流量控制工具,它允许管理员在Linux内核级别对网络流量进行精细化管理。TC工具主要应用于优化网络性能、限制带宽、实现QoS(Quality of ...

    inux下TC+HTB流量控制.doc

    当结合iptables使用时,可以通过mangle链对数据包进行标记,然后通过TC进行分类和限速,实现更精细的流量控制。例如,当上行带宽满载时,下载速度会显著降低,因为ACK数据的传输速度受到影响。通过TC和iptables的...

    linux下简单nat及带宽控制实现

    Linux内核的`tc`(Traffic Control)工具提供了一种机制,可以创建规则来限制不同类型的网络流量的速率。 在C++实现NAT时,可能使用了以下库和接口: - **libipq**:这个库提供了与Netfilter的用户空间交互的能力,...

    局域网限速

    4. **Linux服务器限速**:对于拥有Linux服务器的用户,可以使用iptables、tc等命令行工具来配置网络限速规则,这需要一定的技术基础。 在实施限速时,应注意以下几点: 1. **公平性原则**:合理分配带宽,避免完全...

    Linux 高级路由和流量控制-lartc(Linux Advanced Routing & Traffic Control H

    7. **流量整形与限速工具**:除了上述技术,还有一些实用工具如tc(Traffic Control)、iproute2等,它们提供了命令行接口,方便用户配置和管理LARTC相关设置。 8. **应用场景**:LARTC广泛应用于ISP(Internet ...

    linux高级路由和流量控制.zip

    5. 流量标记(Marking):使用`iptables`或`ipset`可以标记特定的流量,然后用`tc`根据这些标记实施QoS策略。 三、实际应用案例 1. 高可用性网络:通过路由策略,可以实现故障切换和负载均衡,提高网络的可靠性。 ...

    ros.2.9.27限速脚本

    这通常在Linux系统中通过`iptables`或`ip link`命令完成。例如,你可以使用`tc`(Traffic Control)工具来设置带宽限制。 5. **测试与优化**:实施限速后,需要通过监控工具检查效果,如`netstat`、`nethogs`或ROS...

    关于Linux系统服务器站点流量限制的解决方案

    本文介绍的方案主要利用了Linux内核中的`traffic control`(简称`tc`)工具,这是一种非常强大且灵活的网络流量管理工具,能够实现对特定类型的数据包进行限速、优先级调整等功能。此外,我们还将结合`iptables`命令...

    LINUX操作系统流控

    学习LINUX流控需要理解网络原理,熟悉iptables和tc命令的用法,并能够根据网络需求设计和实施流控策略。LARTC手册会提供详细步骤和实例,帮助你掌握这些技能。通过实践和调试,你可以逐步优化你的网络环境,提高网络...

Global site tag (gtag.js) - Google Analytics