Analysis of MySQL example DTID master-slave principle

Analysis of MySQL example DTID master-slave principle

1. Basic Concepts of GTID

Supported since MySQL 5.6.5, a global transaction identifier (GTID (Global Transaction ID)) is a unique identifier created and associated with each transaction committed on the source (primary) server.
This identifier is not only unique, but also unique across all servers in a given replication setup.
There is a one-to-one mapping between all transactions and all GTIDs.
It is composed of the server ID and the transaction ID.
This global transaction ID is not only unique on the original server, but also unique on all MySQL servers that have a master-slave relationship.
It is precisely because of this feature that MySQL's master-slave replication becomes simpler and database consistency becomes more reliable.
A GTID is executed only once on a server to avoid repeated execution that may cause data confusion or inconsistency between the master and the slave.

2. GTID Advantages

Ensure that the same transaction is executed only once on a slave, and gtid transactions that have not been executed will always be executed.
There is no need to ensure the accuracy of binlog coordinates as in traditional replication, because binlog and coordinates are not needed at all.
It is very convenient when failing over to a new master and simplifies many tasks.
It is easy to determine whether the data of the master and slave are consistent. As long as the transaction submitted on the master is also submitted on the slave, it must be consistent.

3. How GTID works

insert image description here

1. When a transaction is executed and committed on the master database, a GTID is generated and recorded in the binlog log.
2. After the binlog is transferred to the slave and stored in the slave's relaylog, the value of the GTID is read to set the gtid_next variable, which tells the slave the next GTID value to be executed.
3. The sql thread obtains the GTID from the relay log, and then compares the binlog on the slave side to see if there is the GTID.
4. If there is a record, it means that the transaction of the GTID has been executed and the slave will ignore it.
5. If there is no record, the slave will execute the GTID transaction and record the GTID to its own binlog. Before reading and executing the transaction, it will check whether other sessions hold the GTID to ensure that it is not executed repeatedly.
6. During the parsing process, it will be determined whether there is a primary key. If so, the secondary index will be used. If not, a full scan will be used.

4. Advantages of GTID over traditional replication

1. Easier to implement failover, no need to find log_file, log_pos

2. Easier to build master-slave replication

3. More secure

4.GTID is continuous without gaps, so when a conflict occurs in the main database, you can skip it by adding an empty event

5. Startup method

  • Method 1: If it is a newly built server, just start it directly
  • Method 2: If the server is running, you need to restart the mysql server

Before starting, turn off the master's write to ensure that the master and slave data remain synchronized. All slaves need to add the configuration parameter skip_slave_start=1 to avoid using the previous replication protocol after starting.

6.GTID (one master and one slave) configuration

6.1 Environment:

centos8.0 ip: 192.168.136.239 with data hostname: mysql01

centos8.0 ip: 192.168.136.219 no data hostname: mysql02

#Binary installation and mysql self-starting service are omitted

6.2 Authorize the slave database on the master database:

mysql> grant replication slave on *.* to 'slave'@'192.168.136.219' identified by 'slave';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
#Turn off firewalls on both servers [root@mysql01 ~]# systemctl stop firewalld
[root@mysql01 ~]# setenforce 0
[root@mysql02 ~]# systemctl stop firewalld
[root@mysql02 ~]# setenforce 0
Test the connection from the library:
[root@mysql02 ~]# mysql -u slave -p'slave' -h192.168.136.239
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> 

6.3 Ensure data consistency operation

1. Lock the main database table mysql> flush tables with read lock;
2. Prepare the main database [root@mysql01 ~]# mysqldump -uroot -A > /clq/all-databases-20210519.sql
3. Copy to the slave host [root@mysql01 ~]# scp /clq/all-databases-20210519.sql [email protected]:/backup/
[root@mysql02 backup]# ll
-rw-r--r--. 1 root root 873527 May 19 16:40 all-databases-20210519.sql
4. Restore the master database from the database [root@mysql02 backup]# mysql -uroot -pHuawei0917@ < all-databases-20210519.sql 

6.4 Configure the main library

[mysqld]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
user = mysql
pid-file = /opt/data/mysql.pid
skip-name-resolve
#skip-grant-tables
log-bin = master_bin #Open the master database log server-id = 10 #The unique ID of the service
gtid-mode = on #GTID mode on enforce_gtid_consistency = on #Force gtid mode consistency log-slave-updates = 1 #Slave database allows update logs and synchronizes operation logs binlog_format = row #binlog log format is row format, the default is mixed mixed mode skip_slave_start = 1 #Skip slave database and start with master database #Restart systemctl restart mysqld 

6.5 Configure the slave library

[root@mysql02 data]# cat /etc/my.cnf
[mysqld]
basedir = /usr/local/mysql 
datadir = /opt/data 
socket = /tmp/mysql.sock 
port = 3306
user = mysql
pid-file = /opt/data/mysql.pid
skip-name-resolve
#skip-grant-tables 
gtid_mode=on
enforce_gtid_consistency=on
server-id=20
log-bin=slave_binlog #Open slave log log_slave-updates=1 #Slave updates are allowed binlog_format=row #Format is row skip-slave_start=1   
#Restart systemctl restart mysqld 

Check the gtid status

mysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
8 rows in set (0.00 sec)

6.6 Configure master-slave replication

#Configure the slave database as root #help change master to You can view the help document example mysql> change master to
    -> master_host='192.168.136.239',
    -> master_user='slave',
    -> master_password='slave',
    -> master_port = 3306, #Master library port-> master_auto_position = 1; #Position#master_use_gtid = current_pos
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;  
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G; 
Slave_IO_Running: Connecting
            Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
Ensure system consistency and authorization consistency

(One master and one slave GTID) test :

Create a database test in the main library for testing and viewing

Create a database test02 from the library for testing

#Create a test database in the main databasemysql> create database test;
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
|mysql |
| performance_schema |
|sys|
| test |
+--------------------+
#Check the synchronization status from the database mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
|mysql |
| performance_schema |
|sys|
| test |
+--------------------+
6 rows in set (0.00 sec)

#Create test02 database from the librarymysql> create database test02;
Query OK, 1 row affected (0.00 sec)
#View on the main databasemysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
|mysql |
| performance_schema |
| sys | #There is no test02 library | test |
+--------------------+
5 rows in set (0.00 sec)

Summary: Data operations on the master database will be synchronized to the slave database, but data operations on the slave database have no connection with the master database.

7.GTID (one master and two slaves)

If the third MySQL is connected, configure it accordingly

The third mysql, version: centos8 ip: 192.168.136.230 host name: mysql03

[root@mysql03 ~]# cat /etc/my.cnf 
[mysqld]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
user = mysql
pid-file = /opt/data/mysql.pid
skip-name-resolve
#skip-grant-tables
# replication config
log-bin = master_bin
server-id = 21 #id must be different from the previous one gtid-mode = on
enforce-gtid-consistency = on
log-slave-updates = 1
binlog-format = row
skip-slave-start = 1
#Check gtid statusmysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
#Since only one IP address was authorized before, authorize another IP address on the mysql01 master database
mysql> grant replication slave on *.* to 'slave'@'192.168.136.230' identified by 'slave';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
#Test connection [root@mysql ~]# mysql -uslave -pslave -h192.168.136.239
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 17
Server version: 5.7.33-log MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> 
#mysql03 connects to the root user from the database and performs corresponding configuration [root@mysql03 ~]# mysql -uroot -p1
mysql> change master to
    -> master_host='192.168.136.239', #master database ip
    -> master_user='slave', #Ordinary user authorized by the master database-> master_password='slave',
    -> master_port=3306, #Master database port-> master_auto_position=1; #Position synchronization starts from 1#You can also view the help for configurationmysql> help change master to;
CHANGE MASTER TO
  MASTER_HOST='source2.example.com',
  MASTER_USER='replication',
  MASTER_PASSWORD='password',
  MASTER_PORT=3306,
  MASTER_LOG_FILE='source2-bin.001',
  MASTER_LOG_POS=4,
  MASTER_CONNECT_RETRY=10;
URL: https://dev.mysql.com/doc/refman/5.7/en/change-master-to.html

#Open mysql> start slave;
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.136.239
                  Master_User: slave
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master_bin.000002
          Read_Master_Log_Pos: 2172
               Relay_Log_File:mysql-relay-bin.000002
                Relay_Log_Pos: 2387
        Relay_Master_Log_File: master_bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes #If two yes are displayed, the operation is successful!
#mysql03 Check the database, and the database content is also synchronized successfullymysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
|mysql |
| performance_schema |
|sys|
| test |
+--------------------+
5 rows in set (0.00 sec)

8.GTID (two masters and one slave)

1. Latest environment

Version ip Hostname identity
centos8 192.168.136.239 master01 Main Library
centos8 192.168.136.219 master02 Main Library
centos8 192.168.136.230 slave From the library

2. All servers have their firewalls turned off or enabled

[root@master01 ~]# systemctl stop firewalld
[root@master01 ~]# systemctl disable firewalld
[root@master02 ~]# systemctl stop firewalld
[root@master02 ~]# systemctl disable firewalld
[root@slave ~]# systemctl stop firewalld
[root@slave ~]# systemctl disable firewalld

3. Authorized connection

master01 library authorizes ordinary users

mysql> grant replication slave on *.* to 'user'@'192.168.136.%' identified by 'user';

Slave connects

[root@slave ~]# mysql -uuser -p'user' -h192.168.136.239
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.7.33 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

master02 authorizes ordinary users

mysql> grant replication slave on *.* to 'app'@'192.168.136.%' identified by 'app';
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

Slave connects

[root@slave ~]# mysql -uapp -papp -h192.168.136.219
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.33 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> 

4. Modify the configuration files separately

#master01 host:
[root@master01 ~]# cat /etc/my.cnf 
[mysqld]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
user = mysql
pid-file = /opt/data/mysql.pid
skip-name-resolve
skip-grant-tables
log-bin = master_bin
server-id = 10
gtid-mode = on
enforce-gtid-consistency = on
log-slave-updates = 1
binlog-format = row
skip-slave-start = 1
#master02 host [mysqld]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
user = mysql
pid-file = /opt/data/mysql.pid
skip-name-resolve
                      #replication config
log-bin = master_bin
server-id = 11
gtid-mode = on
enforce-gtid-consistency = on
log-slave-updates = 1
binlog-format = row
skip-slave-start = 1
#slave host [mysqld]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
user = mysql
pid-file = /opt/data/mysql.pid
skip-name-resolve
log-bin = slave_bin
server-id = 13
gtid-mode = on
enforce-gtid-consistency = on
log-slave-updates = 1
binlog-format = row
skip-slave-start = 1

5. Restart separately

[root@master01 ~]# systemctl restart mysqld
[root@master02 ~]# systemctl restart mysqld
[root@slave ~]# systemctl restart mysqld

6. Before configuring GTID multiple masters and one slave, let’s introduce a concept

channel : Each channel is an independent slave service, with an IO_THREAD and SQL_THREAD. The principle is the same as that of normal replication, except that FOR Channel needs to be used after the change master to statement to distinguish the slaves.

When using channel, you need to set the master-info-repository and relay-log-info-repository of the slave library to table, otherwise an error will be reported.

Set the information repository to table format

Method 1 (setting in mysql):
set global master_info_repository='table';
set global relay_log_info_repository='table';
Method 2 (set in /etc/my.cnf):
3. Set master_info_repository = TABLE in my.cnf 
relay_log_info_repository = TABLE   
#Check if the change is successfulmysql> show variables where variable_name in ('relay_log_info_repository','master_info_repository');
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| master_info_repository | TABLE |
| relay_log_info_repository | TABLE |
+---------------------------+-------+

7.Slave logs in as root user to configure GTID

#slave configures two master libraries GTID replication on the slave library mysql> change master to
    -> master_host='192.168.136.219', #mysql02 master database ip
    -> master_user='app', #Ordinary user authorized by mysql02 master database-> master_password='app', #Ordinary user password authorized by mysql02 master database-> master_port=3306, #Master database port-> master_auto_position=1 for channel 'master01'; #Position synchronization starts from 1, and the first slave is named master01
mysql> change master to
    -> master_host='192.168.136.239', #mysql01 master database ip
    -> master_user='user',              
    -> master_password='user',          
    -> master_port=3306, #Master library port-> master_auto_position=1 for channel 'master02'; #Position synchronization starts from 1, and the first slave is named master01
#Check the status of two slavesmysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: 
                  Master_Host: 192.168.136.219
                  Master_User: app
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: 
          Read_Master_Log_Pos: 4
               Relay_Log_File: slave02-relay-bin-master1.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: 
             Slave_IO_Running: No
            Slave_SQL_Running: No #All are closed Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 0
              Relay_Log_Space: 154
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 0
                  Master_UUID: 
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: 
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: b4326a77-0a31-11ec-a991-000c298d3571:1-2,
d68b404d-0a35-11ec-9df1-000c29581959:1
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: master1
           Master_TLS_Version: 
*************************** 2. row ***************************
               Slave_IO_State: 
                  Master_Host: 192.168.136.239
                  Master_User: user
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: 
          Read_Master_Log_Pos: 4
               Relay_Log_File: slave02-relay-bin-master2.000001
                Relay_Log_Pos: 4
        Relay_Master_Log_File: 
             Slave_IO_Running: No
            Slave_SQL_Running: No
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 0
              Relay_Log_Space: 154
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 0
                  Master_UUID: 
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: 
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: b4326a77-0a31-11ec-a991-000c298d3571:1-2,
d68b404d-0a35-11ec-9df1-000c29581959:1
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: master2
           Master_TLS_Version: 
2 rows in set (0.00 sec)
#Open two slaves
mysql> start slave;
# Check the status again

GTID (two masters and one slave) test:

#master01 main library creates a test databasemysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
|mysql |
| performance_schema |
|sys|
| test |
+--------------------+
5 rows in set (0.00 sec)
#View the master02 database on mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
|mysql |
| performance_schema |
| sys | #No content+--------------------+
4 rows in set (0.00 sec)
#slave view from the librarymysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
|mysql |
| performance_schema |
|sys|
| test | #The test library has been synchronized+--------------------+
5 rows in set (0.00 sec)
#Create a RHCA database in the mysql02 main databasemysql> create database RHCA;
Query OK, 1 row affected (0.01 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
|RHCA|
|mysql |
| performance_schema |
|sys|
+--------------------+
5 rows in set (0.00 sec)
#slave from the library mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
|RHCA|
|mysql |
| performance_schema |
| sys | #With the test library of mysql01 main library and the RHCA library of mysql02 | test |
+--------------------+
6 rows in set (0.00 sec)

Slave related commands:

show slave status; //View all slave status

show slave status for channel 'naem'; //View the status of a single slave

reset slave; #Reset all slaves

reset slave for channel 'master1'; #Reset a single slave

stop slave for channel 'master1'; #Stop a single slave

start slave for channel 'master1'; #Start a single slave

Although I did not encounter any errors in the process, the following is the most common error

After configuration, an error occurs when starting slave

mysql> start slave;
ERROR 1872 (HY000): Slave failed to initialize relay log info structure from the repository

Solving the problem

Since the mysql.slave_relay_log_info table retains the previous replication information, the corresponding file cannot be found when the new slave library is started. In this case, we can clear the records in the table.

mysql> reset slave;
Query OK, 0 rows affected (0.00 sec)

The above is the detailed content of the analysis of the MySQL example DTID master-slave principle. For more information about the MySQL example DTID master-slave principle, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • The implementation principle of Mysql master-slave synchronization
  • Interpretation of MySQL master-slave configuration and its principle analysis (Master-Slave)
  • Detailed explanation of the role and working principle of MySQL master-slave replication
  • MySQL master-slave principle and configuration details
  • Introduction to MySQL master-slave synchronization principle
  • MySQL master-slave replication principle and practice detailed explanation

<<:  Vue makes a simple random roll call

>>:  Minio lightweight object storage service installation and browser usage tutorial

Recommend

Install MySQL (including utf8) using Docker on Windows/Mac

Table of contents 1. Docker installation on Mac 2...

Detailed explanation of MLSQL compile-time permission control example

Preface The simple understanding of MySQL permiss...

Detailed explanation of the knowledge points of using TEXT/BLOB types in MySQL

1. The difference between TEXT and BLOB The only ...

Detailed explanation of JavaScript to monitor route changes

Table of contents history pushState() Method push...

Detailed explanation of the process of docker packaging Python environment

The steps of docker packaging Python environment ...

Implementation of dynamic particle background plugin for Vue login page

Table of contents The dynamic particle effects ar...

Using an image as a label, the for attribute does not work in IE

For example: Copy code The code is as follows: <...

CSS border half or partially visible implementation code

1. Use pseudo-classes to display half of the Bord...

How to create and run a Django project in Ubuntu 16.04 under Python 3

Step 1: Create a Django project Open the terminal...

CentOS7 uses rpm to install MySQL 5.7 tutorial diagram

1. Download 4 rpm packages mysql-community-client...

How to install MySQL for beginners (proven effective)

1. Software Download MySQL download and installat...

Windows Server 2008 R2 Multi-User Remote Desktop Connection Licensing

At work, we often need remote servers and often e...