I haven’t seen you for a long time. I have been busy preparing for my new job for a long time over the weekend, so I didn’t spend any time writing articles. I have a schedule today, but I still want to spare some time to write an article summarizing the technical stack of this project.

Before the article begins, I’d like to say a few words about my idea of finding a job. With the influence of the open source community and some Youtube programmers UP, for my next job, it should be a job THAT I enjoy and have an English working environment. Happy coding can make a really popular program: -d and you won’t feel tired. I look forward to one day having an open source project as popular as Redis.

The following content is the project construction and configuration of the production environment of real enterprises. Due to the special population of the project, the system usage is not high and the concurrency is not large, so the complex design is not adopted. The default configuration also meets the pressure test requirements, so the configuration is not optimized too much.

System Architecture Diagram

The system architecture diagram above is the most common system architecture in Internet companies. This kind of system often deals with the concurrency is not high, and the business is not complex, so the function of doing cluster (including application system cluster, Redis cluster, MySQL master and slave) is only to ensure its high availability. There is a message queue used in the system, but the requirements are not high, we directly use the List structure in Redis to achieve. Simple things can be done in a simple way, there is no need to use professional MQ (RocketMQ, RabbitMQ) for simple requirements, otherwise it will increase the complexity of the system.

Overall request flow diagram

Because Ali Cloud has cooperation agreement with customers, so the server resources are from Ali Cloud. Readers can also get an overview of the network architecture of the entire system through the above request flow diagram.

Detailed request flow diagram

The large rectangular box in the figure above represents a server, with several rectangular boxes representing several components in the same server. All requests are made through Nginx, including the user browsing HTML/ images/other static resources, JS requests to the server, so Nginx has three outputs. Here, the sentinel mode of Redis is used instead of the cluster mode, mainly considering that the system only uses Redis as Session sharing and message queue (the number of messages is relatively small), and the overall amount of data is very small, so the sentinel mode of simpler is used. Instead of considering the Redis Cluster model, which scatters data across different servers (via slot). Additional information on the Redis Cluster model Is available to the reader.

After the reader has a general understanding of the system framework through the above 3 figures, the following is attached with the steps of building all the components, a project named IURC.

Component deployment and configuration steps

1. Build a basic server environment

1.1 Creating robin users for All Servers

Assume that the IP addresses of nine servers are 10.210.111.12 to 10.210.111.20. The real environment needs to be logged in through fortress computer, assuming that you can directly log in to the server.

Log in to server 10.210.111.12 using SSH as user root and create the init_server.sh script

vim init_server.sh

#Create user Robin
adduser -m robin
#Changing a User password
passwd robin
#Install the telent
yum -y install telnet
Copy the code

Create the send_all_Servers. sh script to distribute init_server.sh to all servers

vim send_all_servers.sh

#Write the distribution command to the script (this step is to save time creating users, but you still need to log into each server to execute the script)SCP $1 [email protected]:/root/ SCP $1 [email protected]:/root/ SCP $1 [email protected]:/root/ SCP $1 [email protected]:/root/ SCP $1 [email protected]:/root/ SCP $1 [email protected]:/root/ SCP $1 [email protected]: / root/SCP $1 [email protected]: / root /Copy the code

Execute the send_all_Servers. sh script (the password of the target server needs to be entered after the script is executed.)

chmod +x ./send_all_servers.sh
bash ./send_all_servers.sh ./init_server.sh
Copy the code

Run the init_server.sh script on all servers

chmod +x ./init_server.sh
bash ./init_server.sh
Copy the code

1.2 All Servers Authorize Robin users

Example Add write permission to the sudoers file

chmod u+w /etc/sudoers
Copy the code

Modify the sudoers file

vim /etc/sudoers
Copy the code

Find the figure below in the sudoers file

Add the following below the root line

robin ALL=(ALL) ALL
Copy the code

Revoke the write permission on sudoers files

chmod u-w /etc/sudoers
Copy the code

⚠️ All ECS require login to perform authorization operations

1.3 Restoring the Server host name

Example Change the 10.210.111.12 server host name

hostnamectl set-hostname nginx_01
reboot
Copy the code

You are advised to change all host names to services provided by the server to facilitate subsequent o&M. I set the host name as follows:

The IP address system The host name
10.210.111.12 CentOS7.x nginx_01
10.210.111.13 CentOS7.x nginx_02
10.210.111.14 CentOS7.x redis_01
10.210.111.15 CentOS7.x redis_02
10.210.111.16 CentOS7.x redis_03
10.210.111.17 CentOS7.x db_01
10.210.111.18 CentOS7.x db_02
10.210.111.19 CentOS7.x app_02
10.210.111.20 CentOS7.x app_02

2. Nginx installation and configuration

Server Configuration

The IP address system function
10.210.111.12 CentOS7.x Nginx
10.210.111.13 CentOS7.x Nginx

2.1 install Nginx

Log in to the server as Robin user nginx_0110.210.111.12 using SSH, download Nginx, and unzip it.

CD/home/robin wget http://nginx.org/download/nginx-1.20.1.tar.gz tar - ZXVF nginx - 1.20.1. Tar. Gz && CD nginx - 1.20.1Copy the code

Install the precompiled environment

sudo yum update
sudo yum -y install gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel
Copy the code

Compile the installation are replaced with the following configuration/usr/local/nginx/conf/nginx. The content in the conf

CD /home/robin/ nginx-1.20.1. /configure --prefix=/usr/local/nginx make sudo make installCopy the code

2.2 configure Nginx

Replace with the following configuration/usr/local/nginx/conf/nginx. The content of the conf

worker_processes 2; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name localhost; location @router{ rewrite ^.*$ /iurc/index.html break; } location ^~/iurc { root /usr/local/nginx/html; try_files $uri $uri/ @router; } location ^~/iurc/api { proxy_pass http://iurcProxy/iurc/api/channel/http.do; proxy_send_timeout 1800; proxy_read_timeout 1800; proxy_connect_timeout 1800; client_max_body_size 2048m; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-Port $remote_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location @router_admin{ rewrite ^.*$ /iurc-admin/index.html break; } location ^~/iurc-admin {allow 192.168.10.0/24; Allow 192.168.12.0/24; Allow 192.168.30.0/24; Allow 192.168.160.0/24; deny all; root /usr/local/nginx/html; try_files $uri $uri/ @router_admin; } location ^~/iurc-admin/ API {allow 192.168.10.0/24; Allow 192.168.12.0/24; Allow 192.168.30.0/24; Allow 192.168.160.0/24; deny all; proxy_pass http://iurcAdminProxy/iurc/admin/api/channel/http.do; proxy_send_timeout 1800; proxy_read_timeout 1800; proxy_connect_timeout 1800; client_max_body_size 2048m; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-Port $remote_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location = /50x.html { root html; Upstream {server 10.210.111.19:30068; Server 10.210.111.20:30068; } upstream iurcAdminProxy {server 10.210.111.19:30070; Server 10.210.111.20:30070; }}Copy the code

2.3 start the Nginx

sudo /usr/local/nginx/sbin/nginx
Copy the code

⚠️ Install and configure Nginx on the nginx_0210.111.13 server by following steps 2.1-2.3

2.4 Creating an HTML Directory

sudo mkdir /usr/local/nginx/html/iurc
sudo mkdir /usr/local/nginx/html/iurc-admin
Copy the code

If changed the/usr/local/nginx/conf/nginx. The content in the conf, can use the following command to restart the nginx, make the new configuration take effect.

sudo /usr/local/nginx/sbin/nginx -s reload
Copy the code

3. Redis cluster installation and configuration (Sentinel mode)

Server Configuration

The IP address system function
10.210.111.14 CentOS7.x Redis, sentry
10.210.111.15 CentOS7.x Redis, sentry
10.210.111.16 CentOS7.x Redis, sentry

3.1 installation Redis

Log in to server redis_0110.210.111.14 as robin user, download Redis and unzip it.

CD/home/robin wget https://download.redis.io/releases/redis-5.0.9.tar.gz tar - ZXVF redis - 5.0.9. Tar. Gz && CD redis - 5.0.9Copy the code

Install the precompiled environment and install

sudo yum update
sudo yum -y install gcc
make
sudo make install PREFIX=/usr/local/redis
Copy the code

⚠️ Install and configure Redis on the redis_0210.111.15 server by following Step 3.1

⚠️ Install and configure Redis on the redis_0310.210.111.16 server by following Step 3.1

3.2 configure Redis

In 10.210.111.14, copy redis.conf from the redis source directory to the redis installation directory

Sudo cp /home/robin/redis-5.0.9/redis.conf /usr/local/redis/bin/&& CD /usr/local/redis/bin/Copy the code

In 10.210.111.14, modify the redis.conf file:

sudo vim redis.conf
Copy the code

Change daemonize no to daemonize yes

Comment out the default loopback address. By default, it cannot be accessed by other machines

To disable the protection mode, change the value from yes to no

Distribute the redis. Conf file modified in 10.210.111.14 to 10.210.111.15 and 10.210.111.16

SCP/usr/local/redis/bin/redis. Conf [email protected]: / usr/local/redis/bin /#The root password of 10.210.111.15 is requiredSCP/usr/local/redis/bin/redis. Conf [email protected]: / usr/local/redis/bin /#The root password of 10.210.111.16 is required
Copy the code

In 10.210.111.15, edit redis.conf

sudo vim /usr/local/redis/bin/redis.conf
#Add the following on the last lineReplicaof 10.210.111.14 6379Copy the code

In 10.210.111.16, edit redis.conf

sudo vim /usr/local/redis/bin/redis.conf
#Add the following on the last lineReplicaof 10.210.111.14 6379Copy the code

3.3 Configuring Redis Sentinel

In 10.210.111.14, install redis-sentinel

sudo mkdir -p /usr/local/redis-sentinel
sudo cp -r /usr/local/redis/* /usr/local/redis-sentinel
Copy the code

In 10.210.111.14, copy sentinel.conf

Sudo cp/home/robin/redis - 5.0.9 / sentinel. Conf/usr/local/redis - sentinel/binCopy the code

In 10.210.111.14, modify sentinel.conf

sudo vim /usr/local/redis-sentinel/sentinel.conf

#Change daemonize from no to yes
daemonize yes
#Specifies the number of milliseconds after the primary node does not reply to sentinel. At this point, sentinel subjectively considers the primary node to be offline. The default value is 30000 milliseconds, which is changed to 3000 milliseconds
sentinel down-after-milliseconds mymaster 3000
Copy the code

Copy sentinel 10.210.111.14 to 10.210.111.15 and 10.210.111.16

SCP -r /usr/local/redis-sentinel/ [email protected]:/usr/local scp-r /usr/local/redis-sentinel/ [email protected]: / usr/localCopy the code

In 10.210.111.15, modify the redis.conf file

vim /usr/local/redis-sentinel/bin/sentinel.conf

#Change the IP address of the primary Redis node monitored by Sentinel to 10.210.111.14Sentinel Monitor MyMaster 10.210.111.14 6379 2Copy the code

In 10.210.111.16, modify the redis.conf file

sudo vim /usr/local/redis-sentinel/bin/sentinel.conf

#Change the IP address of the primary Redis node monitored by Sentinel to 10.210.111.14Sentinel Monitor MyMaster 10.210.111.14 6379 2Copy the code

3.4 Enabling Redis and Redis Sentinel upon Startup

In 10.210.111.14, add the Redis startup service

sudo vim /etc/systemd/system/redis.service

#Copy and paste the following
[Unit]
Description=redis-server
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/bin/redis.conf
PrivateTmp=true

[Install]
WantedBy=multi-user.target
Copy the code

In 10.210.111.14, added the Redis Sentinel startup service

sudo vim /etc/systemd/system/redis-sentinel.service

[Unit]
Description=redis-sentinel
After=network.target

#Copy and paste the following
[Service]
Type=forking
ExecStart=/usr/local/redis-sentinel/bin/redis-sentinel /usr/local/redis-sentinel/bin/sentinel.conf
PrivateTmp=true

[Install]
WantedBy=multi-user.target
Copy the code

The configuration is explained as follows:

#[Unit]: indicates the service Unit
#Description: Describes the service
#After: Describes the service category

#[Serivce]: indicates the setting of service running parameters
#Type=forking: is the form of background running
#ExecStart: specifies the running command of the service
#ExecReload: restart command of the service
#ExecStop: Stop the service
#PrivateTmp=True: Independent temporary space is allocated to the service
#⚠️ Note: The start, restart, and stop commands of [Service] require absolute paths

#[Install]: sets the operating level for service installation. You can set it to multiple users, that is, set the operating level to 3
Copy the code

⚠️ repeat the above steps in 10.210.111.15 and 10.210.111.16 to add Redis Startup service and Redis Sentinel startup service.

3.5 Starting Redis and Redis Sentinel

In 10.210.111.14, start Redis and add boot autoboot

sudo systemctl daemon-reload
sudo systemctl start redis.service 
sudo systemctl enable redis.service
Copy the code

In 10.210.111.14, start Redis Sentinel and add boot autostart

sudo systemctl start redis-sentinel.service 
sudo systemctl enable redis-sentinel.service
Copy the code

⚠️ repeat the above steps in 10.210.111.15 and 10.210.111.16 to start Redis and add startup startup and start Redis Sentinel and add startup startup steps.

3.6 test

Go to the Redis console on main Redis10.210.111.14

sudo /usr/local/redis/bin/redis-cli
Copy the code

Type the command

info
Copy the code

If the following results appear, the two slaves are connected, it means that the installation of Redis master-slave (Sentinel mode) is successful

⚠️ The result of the info command due to network or synchronization status,connected_slavesIt doesn’t have to be 2 in real time. You can check it several times.

4. MySQL installation and configuration (master/slave mode)

Server Configuration

The IP address system function
10.210.111.17 CentOS7.x The master database
10.210.111.18 CentOS7.x From the database

Install MySQL 4.1

Log in to server db_0110.210.111.17 as robin user and install MySQL through YUM source.

The following links are detailed installation steps on the official website, readers can follow the steps in the installation of MySQL

Dev.mysql.com/doc/refman/…

4.2 Setting a Remote connection for MySQL

Set MySQL to only two APP SERVER10.210.111.19 and 10.210.111.20

#Enter the following command on the MYSQL command line
GRANT ALL PRIVILEGES ON *.* TO 'root'@'10.210.111.19' IDENTIFIED BY 'P@ssw0rd' WITH GRANT OPTION; 
GRANT ALL PRIVILEGES ON *.* TO 'root'@'10.210.111.20' IDENTIFIED BY 'P@ssw0rd' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO 'root'@'10.210.111.14' IDENTIFIED BY 'P@ssw0rd' WITH GRANT OPTION; 
GRANT ALL PRIVILEGES ON *.* TO 'root'@'10.210.111.15' IDENTIFIED BY 'P@ssw0rd' WITH GRANT OPTION;
FLUSH PRIVILEGES; 
Copy the code

⚠️ MySQL 10.210.111.17 has been installed. Please log in to 10.210.111.18 and refer to steps [4.1-4.2] to install MySQL on 10.210.111.18.

4.3 Setting primary/secondary Synchronization

⚠️ set 10.210.111.17 to the primary database and 10.210.111.18 to the secondary database

mysql -uroot -p
#Enter the password
CREATE USER 'slave'@'%' IDENTIFIED BY 'slaveP@ssw0rd';
GRANT ALL PRIVILEGES ON *.* TO 'slave'@"%" IDENTIFIED BY "slaveP@ssw0rd";
Copy the code

Modify the my.cnf configuration file in 10.210.111.17

sudo vim /etc/my.cnf
#Add two lines
log-bin=mysql-bin
server-id=1
Copy the code

instructions

#Enable binary logging, which is used to write log files at transaction commit time. The default size is 1 gb, followed by 001,002.
log-bin=mysql-bin

#Each instance of mysql is configured differently. This value defaults to 0, and if it is 0, the master server rejects any connections from the slave server.
server-id=1

#Other configurations (not required) :

#Specify which DATABASE is recorded in the mysql binlog. Configure multiple databases to be synchronized. If this parameter is not set, synchronize all databases.Binlog-do-db =db_001 (primary database configuration)
#You can configure multiple databases that are not synchronized.Binlog-ignore-db =mysql (primary database configuration)
#Set the binlog format
binlog_format=mixed

#Read-only 0 indicates no read-only, and 1 indicates read-only
read-only=0

#Used to set the ID conflict of the auto-increment column in the case of dual master, mainly used to set the auto-increment step
auto-increament-increment=10

#Indicates the serial number of the server. The value starts from 1 and does not exceed auto-increament-increment
auto-increment-offset=1
Copy the code

Restart MySQL at 10.210.111.17

sudo systemctl restart mysqld
Copy the code

Modify the my.cnf configuration file in 10.210.111.18

sudo vim /etc/my.cnf
#Add two lines
server-id=2
relay_log=mysql-relay-bin
Copy the code

Restart MySQL at 10.210.111.18

systemctl restart mysqld.service
Copy the code

Obtain the binlog information of MySQL 10.210.111.17

mysql -uroot -p
#Enter the password
show master status;
Copy the code

Enter MySQL Settings in 10.210.111.18 to synchronize with the primary database

mysql -uroot -p
#Enter the passwordchange master to Master_host = '10.210.111.17, master_user =' slave ', master_password = 'slaveP @ ssw0rd, master_log_file =' 000001 'mysql - bin. master_log_pos=154;Copy the code

⚠️ Pay attention to the following instructions

Master_user and master_password are the user names slave and password created on the primary server. Master_log_file is the value of the File field in MySQL Binlog Information queried on the primary server. For example, mysql-bin.000001 master_log_pos is the Position field in mysql Binlog Information queried on the primary server. Like 154 in the figure aboveCopy the code

Start the MySQL slave thread 10.210.111.18

start slave;
Copy the code

Check the slave status of MySQL 10.210.111.18

show slave status \G
Copy the code

Seeing two Yes’s in the red box means that the slave server has successfully synchronized data from the master server.

4.4 Primary/secondary Verification

Perform database creation and table creation on 10.210.111.17 active MySQL to verify that the primary/secondary mode is successfully deployed

Mysql -uroot -p # create database test; use test; Create table user_test(id int comment' id ',name VARCHAR(20) comment' id ', Create_time TIMESTAMP DEFAULT now() comment' create time '); insert INTO user_test value(1,"A",NOW());Copy the code

Check from MySQL on 10.210.111.18 to see if there are tables and data created in primary MySQL

Mysql -uroot -p database; use test; show tables; select * from user_test;Copy the code

The result shows that the data has been synchronized from the primary MySQL to the secondary MySQL, indicating that the primary/secondary mode has been successfully deployed. Delete test data from 10.210.111.17 primary MySQL.

drop database test;
Copy the code

5. Install static resources synchronously

This part of the content is for reference only, because now look at the design actually has some problems. Nginx allows static files to be accessed directly through Nginx and backup files to be accessed through the Static resource Synchronization service. This is fine for public static resources, but if static resources uploaded by users are not public, there is a great risk that an attacker could download users’ private information directly through Nginx.

To sum up, two suggestions can be made:

  • For private files, OSS services can be used if necessary. If you can unconditionally refer to the following static resource synchronization service, I think there should be a better choice in addition to my following service, readers can find it by themselves;
  • Static resources that can be exposed can be obtained directly through Nginx. For private files, remember not to configure Nginx directly.

Server Configuration

The IP address system function
10.210.111.13 CentOS7.x Rsync server
10.210.111.12 CentOS7.x Rsync client

5.1 Rsync Server

Install rsync at 10.210.111.13

cd /opt
sudo yum install -y rsync
Copy the code

Configure the/etc/rsyncd. Conf

#Record file transfer logs
transfer logging = yes
#Specifying log files
log file = /var/log/rsyncd.log
#Pid file path
pid file = /var/run/rsyncd.pid
#Lock the path
lock file = /var/run/rsync.lock
#The user running the rsync daemon
uid = robin
#The group that runs the rsync daemon
gid = robin
#Whether to allow chroot to improve security. If the client is connected to the module, chroot must go to the directory specified in the module path parameter. If the value of chroot is yes, the root permission must be used and connection files outside the path cannot be backed up
use chroot = yes
#Ignore the error
ignore errors
#read-only
read only = no
#Set the timeout period, in seconds
timeout = 60
ignore nonreadable = yes

#Module, can configure more than one
[sync_file]
#Module root directory, synchronization directory, need to pay attention to permissions
path = /home/robin/static
#User name for module authentication. Multiple user names can be separated by Spaces or commas
auth users = sync
#Module authentication password file, which can be placed in global configuration
secrets file = /etc/rsyncd.secrets
#Set a white list, to specify the IP segment (172.18.50.1/255.255.255.0), the IP segment separated by SpacesHosts allow = 10.210.111.12 hosts deny = *#Whether module content is allowed to be listed
list = no
Copy the code

Create /etc/rsyncd.secrets where robin is the user using the synchronization service

#Perform this operation as the root roleecho "robin:infoP@ssw0rd" > /etc/rsyncd.secrets
sudo -i
#Enter the password as root
echo "sync:123456" > /etc/rsyncd.secrets
#Switch back to normal user
su robin
Copy the code

Setting file Permissions

sudo chmod 600 /etc/rsyncd.secrets
Copy the code

Start the service

sudo systemctl restart rsyncd
Copy the code

5.2 Rsync Client

Install rsync at 10.210.111.12

cd /opt
sudo yum install -y rsync
Copy the code

Create /etc/rsync.passwd and run the following command:

#Perform this operation as the root roleecho "infoP@ssw0rd" > /etc/rsync.passwd
sudo -i
#Enter the password as root
echo "123456" > /etc/rsync.passwd
#Switch back to normal user
su robin
Copy the code

⚠️ The rsync client requires only the password, which is the password of user Robin

Change the permissions

sudo chmod 600 /etc/rsync.passwd
Copy the code

The installation way

The inotify-tools tool detects file additions, deletions, and modifications.

sudo yum install -y inotify-tools
Copy the code

Write the startup script inotify_start.sh

cd /home/robin
Copy the code

The script content is as follows:

#! /bin/bash

Path=/home/robin/static
#Set host to the IP address of the rsync serverServer=10.210.111.13 User=sync module=sync_file /usr/bin/inotifywait-mrq --format '%w%f' -e create,close_write,delete $Path | while read line do if [ -f $line ]; then rsync -az $line --delete ${User}@${Server}::${module} --password-file=/etc/rsync.passwd else cd $Path &&\ rsync -az  ./ --delete ${User}@${Server}::${module} --password-file=/etc/rsync.passwd fi doneCopy the code

The test command

Sudo rsync-avz --delete /home/robin/static/ [email protected]::sync_file --password-file=/etc/rsync.passwdCopy the code

5.3 Writing a Service Startup Script

Write inotifyd.service and copy it to /usr/lib/systemd/system/ as follows

[Unit]
Description=inotify rsync script
After=network.target
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=root
Group=root
PIDFile=/var/run/inotify.pid
ExecStart=/usr/bin/nohup /home/robin/inotify_start.sh > /home/robin/inotify.log 2>&1 &
ExecReload=
ExecStop=/usr/bin/ps -ef | /usr/bin/grep inotify | /usr/bin/grep -v grep | /usr/bin/awk '{print $2}' | /usr/bin/xargs /usr/bin/kill -9
PrivateTmp=true

[Install]
WantedBy=multi-user.target
Copy the code

Start the service

sudo systemctl start inotifyd.service
Copy the code

Allow auto start

sudo systemctl enable inotifyd.service
Copy the code

Re-read the restart script

sudo systemctl daemon-reload
Copy the code