REFERENCE

https://dev.to/aurelmegn/setting-up-distributed-database-architecture-with-postgresql-261

https://www.postgresql.org/docs/9.5/sql-createforeigntable.html

https://www.postgresql.org/docs/9.3/ddl-foreign-data.html

A distributed database is a database in which data is stored across different physical locations. It may be stored in multiple computers located in the same physical location (e.g. a data centre); or maybe dispersed over a network of interconnected computers.

Some basic information and keyword

Master server
Slave Server
Foreign Table
Config file location:
postgres config file location vary from postgres version and server
To find where is config file location, do some simple command

find / -name “postgresql.conf”
find / -name “pg_hba.conf”

If you need more info, you can do some other search over the whole server
find / -name “postgre*”

Setting up the master server (VietNam ‘server)

We will use the foreign table ** feature of postgres to be able to access the **Lagos’s database tables remotely from the master server . To be able to do this, we should create the postgres_fdw extension in our database. This action should be done only by an administrator, so let’s connect to the database as the administrator postgres user and do:

/!\ There are many alternatives to foreign table use, such as the use of materialized views + triggers or postgres partitioning feature.
create extension postgres_fdw;

create server master_server foreign data wrapper postgres_fdw options (host ‘{ip address of the lagos postgres server}’, port ‘5432’ , dbname ‘dd_test’);

create user mapping for master_user server master_server options (user ‘{our username on lagos server}’, password ‘{our password on lagos server}’);

alter server master_server owner to master_user;
First, we create the extension postgres_fdw and after a “foreign data server” on the master postgres server. We now create a user mapping to be able to query the Lagos server.

Now, let’s create the foreign tables located on the master server which map to the shard on the Lagos servers.
drop foreign table if exists booksample_lagos cascade;
create foreign table booksample_lagos (check(location=’lagos’)) inherits(booksample) server master_server;
drop foreign table if exists lend_lagos cascade;
create foreign table lend_lagos () inherits(lend) server master_server;
In its actual state, the master server will fill the the table booksample and lend when a query like this is executed.
insert into booksample values(1, ‘new’,’paris’,1)
This is not a good behavior as the new partitions we created will not hold any data. To fix this situation, we will use “triggers” to redirect the row into their normal destination.

The trigger bellows is to redirect the booksample insertion into the correct partition: either booksample_lagos or booksample_paris based on the value of attribute location:
— trigger on insert booksample
create or replace function booksample_trigger_fn() returns trigger as
$$
begin

if new.location = ‘paris’ then
insert into booksample_paris values(new.*);
elsif new.location = ‘lagos’ then
insert into booksample_lagos values(new.*);
end if;

return null;
end
$$
language plpgsql;

drop trigger if exists booksample_trigger on booksample;
create trigger booksample_trigger before insert on booksample for each row execute procedure booksample_trigger_fn();

Now, we would like to redirect the queries on the table lend to the correct partition. Here we store the row into the site where the booksample belongs to.

create or replace function lend_trigger_fn() returns trigger as
$$
declare
vbooksample booksample%rowtype;
begin
— select the booksample referenced by the booksample_id
select * into vbooksample from booksample where id=new.booksample_id;

— get the location to use and save the row
if vbooksample.location = ‘paris’ then
insert into lend_paris values(new.*);
elsif vbooksample.location = ‘lagos’ then
insert into lend_lagos values(new.*);
end if;

return null;
endtut
$$
language plpgsql;

drop trigger if exists lend_trigger on lend;
create trigger lend_trigger before insert on lend for each row execute procedure lend_trigger_fn();
Our database is now functional.

Setting up the slave server (Singapore ‘s server)

Let’s create the database
create database dd_test;
Here we are going to set up the postgres server to listen to the other network interfaces. This is done by modifying the configuration file located at (on most Linux os)

vim /var/lib/pgsql/11/data/postgresql.conf

#——————————————————————————
# CONNECTIONS AND AUTHENTICATION
#——————————————————————————

# – Connection Settings –

listen_addresses = ‘*’ # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to ‘localhost’; use ‘*’ for all
# (change requires restart)

The next step is to allow a user to connect through the network interfaces by modifying
vim /var/lib/pgsql/11/data/pg_hba.conf

# TYPE DATABASE USER ADDRESS METHOD

# IPv4 local connections:
host all test_user all md5

Let’s create now the partitions tables:
— booksample_lagos
drop table if exists booksample_lagos cascade;
create table booksample_lagos(id int, state varchar, lendable bool default false, location varchar, book_id int);

— lend_lagos
drop table if exists lend_lagos cascade;
create table lend_lagos(student_id int, booksample_id int, at date, returned_at date);

Keyword for distributed database

Distributed database
Kien truc he phan tan
co so du lieu phan tan (csdl phan tan)
Master server
Slave server
Foreign table
Foreign data
Foreign data wrapper (fdw)
User mapping

REFERENCE

https://dev.to/aurelmegn/setting-up-distributed-database-architecture-with-postgresql-261

https://www.postgresql.org/docs/9.5/sql-createforeigntable.html

https://www.postgresql.org/docs/9.3/ddl-foreign-data.html

If you surfering the internet with the keyword “why choose golang” , you might go to a short brief why most people choose go lang for their project

Five reasons to start with Golang include:

+ Golang is advanced and reliable, offering great built-in ways to handle errors.
+ It is efficient, compiling down to one binary.
+ Speed, Go enhances the availability and reliability of services.
+ Go increases code readability through its simplicity
+ Developers can easily learn and adapt to Golang and quickly become productive.

For me, I choose go lang to develop my next app generation because of
+ Golang Is Fast
+ Golang Is Well-Scaled (global scale available)
+ & Go concurrency is way too amazing

Reference:

Why You Should Use Golang and How to Get Started

SQL Server vs PostgreSQL Comparison Table

Here are some of the Comparison:

The Basis Of Comparison  SQL Server PostgreSQL
Basic Difference SQL server is a database management system which is mainly used for e-commerce and providing different data warehousing solutions. PostgreSQL is an advanced version of SQL which provides support to different functions of SQL like foreign keys, subqueries, triggers, and different user-defined types and functions.
Updateable Views Views can be updatable even if 2 table views are updated. If the tables have different keys and the update statement does not involve more than one table then it will be updated automatically. The user can also make use of triggers to update complex views. Views in PostgreSQL can be updated but not automatically unlike SQL server. The user must write rules against different views to update them. Also, complex views can be easily created.
Computed Columns SQL server does provide computed columns but views are preferred over computed columns. Computed columns have a very limited use as they are not capable of holding different roll-ups. PostgreSQL does not provide computed columns. PostgreSQL, on the other hand, has functional indexes which work just as a view.
Replication SQL server can replicate all sorts of data. This can be log shipping, mirroring, snapshot, and transactional and merge etc. and can even have non-SQL Server windows-based subscribers. Replication in Postgres is in the form of reports and is supposed to be least polished of the bunch. Although there are different third-party options to choose from the ones that are free and not free. PostgreSQL 8.4 or a higher slated version can have built-in replication feature.
Support stored procedures and stored functions in different languages SQL server does support this feature. It can be done with any language which complies with CLR like VB, C#, Python, etc. TO get this done successfully user must first compile the code into all first. Here there is no need to create a dull first. A user who has created the code can easily see what the code is doing. The server which is downside must host the language the environment is using.
Dynamic actions in SQL SQL server does not support this feature. But instead of this user can use the stored procedure and call these from select statements so it is much more limiting than PostgreSQL. PostgreSQL does provide this feature and just by using select statements a user can perform really all operations and retrieve and do all other jobs easily.
Materialized Views Yes, it provides the facilities to run materialized views. The functioning though varies depending on where the query is being run. It can be SQL Express, Workgroup, etc. Postgres does not provide facility to run materialized views. Instead of this, they have a module called mat views which helps in rebuilding any materialized view.
Case sensitivity By default SQL server is considered to be case insensitive but if a user wants to change the same they can do it by going down to the column level. By default, PostgreSQL is case sensitive and it is difficult to make it insensitive. Changes can be made in it but they are not exposed and are not ANSI compliant hence making it a delirious job to use it on MS Access, PHP Gallery, etc. where SQL is regarded to be case insensitive.

Conclusion

In this SQL Server vs PostgreSQL article, we have seen Both SQL Server vs PostgreSQL are database management tools. They help in managing all data properly and efficiently. But when it comes to different features PostgreSQL is always at the upper hand. It is an advanced version of SQL and hence provides many additional features.  All these features are for free, unlike SQL server. Also, it is cross-platform and can be used with any operating system.

 

Oracle vs PostgreSQL  Comparison Table

The primary Comparison between Oracle vs PostgreSQL Performance are discussed below:

The Basis Of Comparison  Oracle PostgreSQL
The total cost of ownership The price of acquisition and product support for the Oracle database is high, and we need to pay in addition for every extra feature we need, which is having a high price. So TCO is high for the Oracle database. As PostgreSQL is open-source, there is no fee for acquisition and product support which are absolutely free of cost. We can get all the available features of the PostgreSQL database for free as it is open-source.
Support Customer support for the Oracle database is not free; it is almost one-fourth of the license cost and increases 3 to 5 % annually. Customer support for PostgreSQL is free, but it will take time to resolve the issue as it will be solved by the developer’s community. We can opt for paid service by PostgreSQL professionals, which will be less costly than Oracle DB support cost.
Productivity Oracle database productivity is more due to its technical superiority. Oracle database provides more transactions per second than PostgreSQL. PostgreSQL productivity is less than Oracle database as it provides less number of transactions per second than Oracle DB.
Safety Oracle database has more security or advanced security, but we need to purchase as part of the editions provided by Oracle corporation, which have some features that protect the database. PostgreSQL has good security support but not as advanced as the Oracle database, but those features are not relevant to worse conditions of the database, i.e. the total collapse of technical support or database crash or shutdown.
Scalability Oracle database offers four sockets with standard edition for scalability, but for high workload projects, we need to buy enterprise edition, which is a little costly. PostgreSQL offers scalability support for free of cost expansions such as proxy from Skype allocating information in database clusters, cluster-based storage solutions based on PostgreSQL.
Updates Oracle database release new versions or updated versions once in two to three years with quality changes with respect to demand in the market. PostgreSQL releases new versions or updated versions once in four to five years, but they continuously add new features and updates to be up to date with market trends and requirements.
Handling large data volume Oracle database enterprise edition handles a large amount of data effectively than PostgreSQL based on other equal conditions and machine types. So it is not fair to compare as productivity depends on various factors. PostgreSQL database handles a large amount of data effectively, which boosts the productivity of 10 to 30 pages on machines having large volumes of memory. So it depends on various factors.

Conclusion

Finally, It’s an overview of Oracle vs PostgreSQL comparison in different aspects. I hope you will have a better understanding of these topics after reading this Oracle vs PostgreSQL article. We have seen the Difference Between Oracle and PostgreSQL, and I can say that PostgreSQL is more powerful than Oracle in many instances, being open-source, compatibility with other RDBMS and ease of use with a large community of developers. We can decide the database based on the concrete project. PostgreSQL is being used in many industries such as Hospital applications, patient genetic, B2B applications etc.

 

 

Reference:
https://www.postgresql.org/docs/

https://developer.okta.com/blog/2019/07/19/mysql-vs-postgres

SQL Server vs PostgreSQL

Oracle vs PostgreSQL

 

What is in this article ?

In this artivle, we’ll try to build a bookstore REST API that provides book data and performs CRUD operations.

Let’s start by initializing a new Go module. This will enable us to manage the dependencies that are specifically installed for this project.

<pre>

Note: you can use the command go env to know where your GOPATH locate

or set in with this command

echo “export GOPATH=/root/go” >> ~/.bash_profile

</pre>

$ go mod init api

Now let’s install some dependencies : gonic and gorm

go get github.com/gin-gonic/gin github.com/jinzhu/gorm

After the installation is complete, your folder should contain two files: go.mod and go.sum.

Screen Shot 2021-05-17 at 5.40.45 PM

 

Both of these files contain information about the packages you installed, which is helpful when working with other developers.

If somebody wants to contribute to the project, all they need to do is run the go mod download command on their terminal to install all the required dependencies on their machine.

 

Setting up the server

Let’s start by creating a Hello World server inside the main.go file.


package main

import (
  "net/http"
  "github.com/gin-gonic/gin"
)

func main() {
  r := gin.Default()

  r.GET("/", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{"data": "hello world"})    
  })

  r.Run()
}

 

To test it out, we’ll start our server by running the command below.
$ go run main.go

Then run this command on another command windows

curl localhost:8080

Result

{"data":"hello world"}

Setting up the database

The next thing we need to do is to build our database models.

Model is a class (or structs in Go) that allows us to communicate with a specific table in our database. In Gorm, we can create our models by defining a Go struct. This model will contain the properties that represent fields in our database table. Since we’re trying to build a bookstore API, let’s create a Book model.

// models/book.go

package models

import (
  "github.com/jinzhu/gorm"
)

type Book struct {
  ID     uint   `json:"id" gorm:"primary_key"`
  Title  string `json:"title"`
  Author string `json:"author"`
}

Our Book model is pretty straightforward. Each book should have a title and the author name that has a string data type, as well as an ID, which is a unique number to differentiate each book in our database.

We also specify the tags on each field using backtick annotation. This allows us to map each field into a different name when we send them as a response since JSON and Go have different naming conventions.

To organize our code a little bit, we can put this code inside a separate module called models.

Next, we need to create a utility function called ConnectDatabase that allows us to create a connection to the database and migrate our model’s schema. We can put this inside the setup.go file in our models module.

// models/setup.go

package models

import (
  "github.com/jinzhu/gorm"
  _ "github.com/jinzhu/gorm/dialects/sqlite"
)

var DB *gorm.DB

func ConnectDataBase() {
  database, err := gorm.Open("sqlite3", "test.db")

  if err != nil {
    panic("Failed to connect to database!")
  }

  database.AutoMigrate(&Book{})

  DB = database
}

Inside this function, we create a new connection with the gorm.Open method. Here, we specify which kind of database we plan to use and how to access it. Currently, Gorm only supports four types of SQL databases. For learning purposes, we’ll use SQLite and store our data inside the test.db file. To connect our server to the database, we need to import the database’s driver, which is located inside the github.com/jinzhu/gorm/dialects module.

We also need to check whether the connection is created successfully. If it doesn’t, it will print out the error to the console and terminate the server.

Next, we migrate the database schema using AutoMigrate. Make sure to call this method on each model you have created.

Lastly, we populate the the DB variable with our database instance. We will use this variable in our controller to get access to our database.

In main.go, we need to call the following function before we run our app.

package main

import (
  "net/http"
  "github.com/gin-gonic/gin"

  "github.com/rahmanfadhil/gin-bookstore/models" // new
)

func main() {
  r := gin.Default()

  models.ConnectDatabase() // new

  r.Run()
}

RESTful Routes

We’re almost there!

The last thing we need to do is to implement our controllers. In the previous section, we learned how to create a route handler (i.e., controller) inside our main.go file. However, this approach makes our code much harder to maintain. Instead of doing that, we can put our controllers inside a separate module called controllers.

First, let’s implement the FindBooks controller.

// controllers/books.go

package controllers

import (
  "github.com/gin-gonic/gin"
  "github.com/rahmanfadhil/gin-bookstore/models"
)

// GET /books
// Get all books
func FindBooks(c *gin.Context) {
  var books []models.Book
  models.DB.Find(&books)

  c.JSON(http.StatusOK, gin.H{"data": books})
}

Here, we have a FindBooks function that will return all books from our database. To get access to our model and DB instance, we need to import our modelsmodule at the top.

Next, we can register our function as a route handler in main.go.

package main

import (
  "net/http"
  "github.com/gin-gonic/gin"

  "github.com/rahmanfadhil/gin-bookstore/models"
  "github.com/rahmanfadhil/gin-bookstore/controllers" // new
)

func main() {
  r := gin.Default()

  models.ConnectDatabase()

  r.GET("/books", controllers.FindBooks) // new

  r.Run()
}

Pretty simple, right?

Make sure to add this line after the ConnectDatabase. Otherwise, your controller won’t be able to access the database.

Now, let’s run our server and hit the /books endpoint.

{
  "data": []
}

If you see an empty array as the result, it means your applications are working. We get this because we haven’t created a book yet. To do so, let’s create a create book controller.

To create a book, we need to have a schema that can validate the user’s input to prevent us from getting invalid data.

type CreateBookInput struct {
  Title  string `json:"title" binding:"required"`
  Author string `json:"author" binding:"required"`
}

The schema is very similar to our model. We don’t need the ID property since it will be generated automatically by the database.

Now we can use that schema in our controller.

// POST /books
// Create new book
func CreateBook(c *gin.Context) {
  // Validate input
  var input CreateBookInput
  if err := c.ShouldBindJSON(&input); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
  }

  // Create book
  book := models.Book{Title: input.Title, Author: input.Author}
  models.DB.Create(&book)

  c.JSON(http.StatusOK, gin.H{"data": book})
}

We first validate the request body by using the ShouldBindJSON method and pass the schema. If the data is invalid, it will return a 400 error to the client and tell them which fields are invalid. Otherwise, it will create a new book, save it to the database, and return the book.

Now, we can add the CreateBook controller in main.go.

func main() {
  // ...

  r.GET("/books", controllers.FindBooks)
  r.POST("/books", controllers.CreateBook) // new
}

So, if we try to send a POST request to /books endpoint with this request body:

{
  "title": "Hello world title",
  "author": "Viet Huy"
}

The response should looks like this:

{
  "data": {
    "id": 1,
    "title": "Hello world title",
    "author": "Viet Huy"
  }
}

We’ve successfully created our first book. Let’s add controller that can fetch a single book.

// GET /books/:id
// Find a book
func FindBook(c *gin.Context) {  // Get model if exist
  var book models.Book

  if err := models.DB.Where("id = ?", c.Param("id")).First(&book).Error; err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})
    return
  }

  c.JSON(http.StatusOK, gin.H{"data": book})
}

Our FindBook controller is pretty similar to the FindBooks controller. However, we only get the first book that matches the ID that we got from the request parameter. We also need to check whether the book exists by simply wrapping it inside an if statement.

Next, register it into your main.go.

func main() {
  // ...

  r.GET("/books", controllers.FindBooks)
  r.POST("/books", controllers.CreateBook)
  r.GET("/books/:id", controllers.FindBook) // new
}

To get the id parameter, we need to specify it from the route path, as shown above.

Let’s run the server and fetch /books/1 to get the book we just created.

{
  "data": {
    "id": 1,
    "title": "Hello world title",
    "author": "Viet Huy"
  }
}

So far, so good. Now let’s add the UpdateBook controller to update an existing book. But before we do that, we need to define the schema for validating the user input first.

struct UpdateBookInput {
  Title  string `json:"title"`
  Author string `json:"author"`  
}

The UpdateBookInput schema is pretty much the same as our CreateBookInput, except that we don’t need to make those fields required since the user doesn’t have to fill all the properties of the book.

To add the controller:

// PATCH /books/:id
// Update a book
func UpdateBook(c *gin.Context) {
  // Get model if exist
  var book models.Book
  if err := models.DB.Where("id = ?", c.Param("id")).First(&book).Error; err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})
    return
  }

  // Validate input
  var input UpdateBookInput
  if err := c.ShouldBindJSON(&input); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
  }

  models.DB.Model(&book).Updates(input)

  c.JSON(http.StatusOK, gin.H{"data": book})
}

First, we can copy the code from the FindBook controller to grab a single book and make sure it exists. After we find the book, we need to validate the user input with the UpdateBookInput schema. Finally, we update the book model using the Updates method and return the updated book data to the client.

Register it into your main.go.

func main() {
  // ...

  r.GET("/books", controllers.FindBooks)
  r.POST("/books", controllers.CreateBook)
  r.GET("/books/:id", controllers.FindBook)
  r.PATCH("/books/:id", controllers.UpdateBook) // new
}

Let’s test it out! Fire a PATCH request to the /books/:id endpoint to update the book title.

{
  "title": "The Infinite Game"
}

The result should be as follows.

{
  "data": {
    "id": 1,
    "title": "The Infinite Game",
    "author": "Viet Huy"
  }
}

The last step is to implement to delete book feature.

// DELETE /books/:id
// Delete a book
func DeleteBook(c *gin.Context) {
  // Get model if exist
  var book models.Book
  if err := models.DB.Where("id = ?", c.Param("id")).First(&book).Error; err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})
    return
  }

  models.DB.Delete(&book)

  c.JSON(http.StatusOK, gin.H{"data": true})
}

Just like the update controller, we get the book model from the request parameters if it exists and delete it with the Delete method from our database instance, which we get from our middleware. Then, return true as the result since there is no reason to return a deleted book data back to the client.

func main() {
  // ...

  r.GET("/books", controllers.FindBooks)
  r.POST("/books", controllers.CreateBook)
  r.GET("/books/:id", controllers.FindBook)
  r.PATCH("/books/:id", controllers.UpdateBook)
  r.DELETE("/books/:id")
}

Let’s test it out by sending a DELETE request to the /books/1 endpoint.

{
  "data": true
}

If we fetch all books in /books, we’ll see an empty array again.

{
  "data": []
}

Reference

https://www.digitalocean.com/community/tutorials/how-to-install-the-apache-web-server-on-ubuntu-18-04

https://github.com/rahmanfadhil/gin-bookstore

Building a REST API with Golang using Gin and Gorm

https://github.com/jinzhu/gorm

What is in this article ?

How to install nginx on centos 7

Some of the basics of NGINX as a refresher

Logging, explains that monitoring for errors and access patterns are fundamental to running a server.

Rewrites, covers how rewrites work and also specific implementations of many of the common scenarios. It will be full of specific, practical examples based on real-world scenarios.

Reverse Proxy: Configuring NGINX as a simple reverse proxy

Rate Limit with Nginx

Load Balancing, talks about the load balancing components of NGINX and how to implement them for specific scenarios.

How to install nginx on centos 7

Quite simple, Use the script below

echo "1. install postgresql11-server:"
yum install epel-release -y
yum install nginx -y

echo "2. Enable nginx on start "
systemctl enable nginx

echo "3. Start nginx"
systemctl start nginx

echo "4. Enable firewall for http and https"

firewall-cmd --permanent --zone=public --add-service=http 
firewall-cmd --permanent --zone=public --add-service=https
firewall-cmd --reload
# then, you can continue check the status and version
echo "5. Check service status"
service nginx status
netstat -tlpun

echo "6. Check version"
nginx -v

echo "7. Check stub status module"
nginx -V 2>&1 | grep -o with-http_stub_status_module

Result

Screen Shot 2021-06-01 at 4.06.37 PM

Loging

Here’s our NGINX configuration for local logging:

server {
listen 80;
server_name test.tranhuy.com;
access_log syslog:server=unix:/dev/log;
error_log syslog:server=unix:/dev/log;
location /favicon.ico { access_log off; log_not_found off; }
root /var/www;
}

We can confirm it’s working as expected by viewing the last line in our syslog after accessing the website:

tail -f /var/log/syslog
hoặc
tail -n 1 /var/log/syslog

or
vim /etc/nginx/nginx.conf

#more code by Huy
        access_log /var/log/nginx/access_log combined;
        error_log /var/log/nginx/error_log debug;
        location /nginx_status {
            stub_status on;
            allow 127.0.0.1;
            deny all;
        }

then, try to view the log here
systemctl nginx restart
tail -f /var/log/nginx/access_log
tail -f /var/log/nginx/error_log

or try
curl http://127.0.0.1/nginx_status
Result
Active connections: 1
server accepts handled requests
549 549 21583
Reading: 0 Writing: 1 Waiting: 0

On a Debian / Ubuntu-based system, this will be /var/log/syslog. If you run a RedHat / CentOS-based system, this will be logged to /var/log/messages.

Logging POST data

When we have form submissions, errors in this become difficult to replay and debug if we don’t know the value of the data. By default, NGINX doesn’t log POST data, as it can be very bulky. However, there are certain situations where getting access to this data is vital to debugging issues.

In order to log POST data, we need to define a custom log format:

log_format post_logs ‘[$time_local] “$request” $status ‘
‘$body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” [$request_body]’;
By logging $request_body, we’ll be able to see the contents of a POST submission.

To enable our POST log format, all we need to do is specify the log format for the access logs:

access_log /var/log/nginx/postdata-access.log post_logs;

Configure logging format

It is also possible to log the metrics that you are interested in. To do that, Create a custom log format and just add it in the HTTP section of your NGINX configuration file. The following section defines a custom log format by the name custom_format that can be used in any NGINX server block by specifying its name with access_log directive.

http {


log_format custom_format ‘$remote_addr – $remote_user [$time_local]”$request” $status $body_bytes_sent “$http_referer” “$http_user_agent” rt=$request_time rt=”$upstream_response_time”‘;


}
Next add access_log and error_log directive in your specific NGINX virtual host file

# vi your_nginx_virtual_host.conf
server {


access_log /var/log/nginx/access.log custom_format;
error_log /var/log/nginx/error.log warn;


}
Check the configuration files for any syntactical error and restart NGINX.

# nginx -t
# systemctl restart nginx
The metrics will be available immediately in the amplify dashboard. Use the tabs at the top of the page to view the metrics that are appropriate for you.

Redirect

Redirecting all calls to HTTPS to secure your site

SSLs help your site more secure
This is especially critical if you’re handling private data or payment information, which could be mandated by law to ensure the transmissions of the data is encrypted.
To ensuring that all calls to your site or application are always encrypted, we need to redirecting all calls to HTTPS

Thankfully, enforcing HTTPS is simple to do.

Now, using two server blocks is the most efficient method:

server {
listen 80;
server_name ssl.tranhuy.com;
return 301 https://ssl.tranhuy.com$request_uri;
}

server {
listen 443 ssl;
server_name ssl.tranhuy.com;
ssl_certificate /etc/ssl/public.pem;
ssl_certificate_key /etc/ssl/private.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;

access_log /var/log/nginx/ssl-access.log combined;

location / {
root /var/www;
index index.html index.htm;
}
}

Reverse Proxy: Configuring NGINX as a simple reverse proxy

One of the most powerful features of NGINX is its ability to act as a reverse proxy. As opposed to a forward proxy, which sits between the client and the internet, a reverse proxy sits between a server and the internet.

Here’s a visual representation:

Screen Shot 2021-05-17 at 3.27.39 PM

A reverse proxy can provide a multitude of features. It can load balance requests, cache content, rate limit, provide an interface to a Web Application Firewall (WAF), and lots more. Basically, you can greatly increase the number of features available to your system by running it through an advanced reverse proxy

Here’s our server block directive to proxy all requests through to port 8000 on the localhost:

server {
listen 80;
server_name proxy.tranhuy.com;
access_log /var/log/nginx/proxy-access.log combined;

location / {
proxy_pass http://127.0.0.1:8000;
}
}

Rate limiting with nginx

If you have an application or site where there’s a login or you want to ensure fair use between different clients, rate limiting can help to help protect your system from being overloaded.

By limiting the number of requests (done per IP with NGINX), we lower the peak resource usage of the system, as well as limit the effectiveness of attacks which are attempting to brute force your authentication system.

Follow these steps for rate limiting:

1. Firstly, we need to define a shared memory space to use for tracking the IP addresses. This needs to be added in the main configuration file, outside the standard server block directive. Here’s our code:
limit_req_zone $binary_remote_addr zone=basiclimit:10m rate=10r/s;
2. Then, within the server block, you can set which location you wish to limit. Here’s what our server block directive looks like:
server {
listen 80;
server_name limit.tranhuy.com;
access_log /var/log/nginx/limit-access.log combined;

location / {
limit_req zone=basiclimit burst=5;
proxy_pass http://127.0.0.1:8000;
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}
}
We can run Apache Benchmark (a simple web benchmarking tool) under a few different scenarios to test the effectiveness. The first is to use a single connection and make 200 requests:
“ ab -c 1 -n 200 http://limit.tranhuy.com/
This gives us the following results:

Concurrency Level: 1
Time taken for tests: 20.048 seconds
Complete requests: 200
Failed requests: 0
Total transferred: 5535400 bytes
HTML transferred: 5464000 bytes
Requests per second: 9.98 [#/sec] (mean)
Time per request: 100.240 [ms] (mean)
Time per request: 100.240 [ms] (mean, across all concurrent
requests)
Transfer rate: 269.64 [Kbytes/sec] received
As the results show, we didn’t receive any errors and averaged 9.98 requests per second.

In the next test, we’ll increase the number of concurrent requests to 4 at a time:
ab -c 4 -n 200 http://limit.tranhuy.com/
This gives us the following results:

Concurrency Level: 4
Time taken for tests: 20.012 seconds
Complete requests: 200
Failed requests: 0
Total transferred: 5535400 bytes
HTML transferred: 5464000 bytes
Requests per second: 9.99 [#/sec] (mean)
Time per request: 400.240 [ms] (mean)
Time per request: 100.060 [ms] (mean, across all concurrent
requests)
Transfer rate: 270.12 [Kbytes/sec] received
Even with the increased request rate, we still received responses at a rate of 10 requests per second.

Load Balancing

Screen Shot 2021-05-17 at 3.35.09 PM

The three scheduling algorithms which NGINX supports are round-robin, least connections, and hashing.
Round-robin load balancing : distribute requests across the servers in a sequential basis; the first request goes to the first server, the second request to the second server, and so on

Least connected load balancing : NGINX distributes the requests to the servers with the least amount of active connections. This provides a very rudimentary level of load-based distribution; however, it’s based on connections rather than actual server load.

Hash-based load balancing : uses a key to determine how to map the request with one of the upstream servers. Generally, this is set to the client’s IP address, which allows you to map the requests to the same upstream server each time.

## Reference
https://www.digitalocean.com/community/tutorials/how-to-install-the-apache-web-server-on-ubuntu-18-04

What is in this article ?
Install rabbitMQ server
Connecting to a broker
Producing messages
Consuming messages
Broadcasting messages
Guaranteeing message processing
Distributing messages to many consumers
Using message properties
Messaging with transactions
Handling unroutable messages

Install rabbitMQ server on centos7

You can see a download list here
https://www.rabbitmq.com/install-rpm.html#downloads
Some basic step to install can be as describe below


echo "1. We can install EPEL using yum:"
sudo yum install epel-release -y

echo "Step 2: Install Erlang"
cd ~
wget http://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
sudo rpm -Uvh erlang-solutions-1.0-1.noarch.rpm
sudo yum install erlang

echo "Verify your installation of Erlang with command: erl"

#erl

echo "Step 3: Install RabbitMQ"
cd ~
#download
#https://www.rabbitmq.com/install-rpm.html#downloads
echo "Download"
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.16/rabbitmq-server-3.8.16-1.el7.noarch.rpm
echo "Signature"
sudo rpm --import https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.16/rabbitmq-server-3.8.16-1.el7.noarch.rpm.asc
echo "Install"
sudo yum install rabbitmq-server-3.8.16-1.el7.noarch.rpm

echo "Step 4: Modify firewall rules"
sudo firewall-cmd --zone=public --permanent --add-port=4369/tcp --add-port=25672/tcp --add-port=5671-5672/tcp --add-port=15672/tcp  --add-port=61613-61614/tcp --add-port=1883/tcp --add-port=8883/tcp
sudo firewall-cmd --reload


echo "5. Enable the rabbitmq-server service on boot"
sudo systemctl start rabbitmq-server.service
sudo systemctl enable rabbitmq-server.service

echo "6. Check the service"
sudo rabbitmqctl status

For futher access, create an account

echo "Step 7: Enable and use the RabbitMQ management console"
sudo rabbitmq-plugins enable rabbitmq_management
sudo chown -R rabbitmq:rabbitmq /var/lib/rabbitmq/

echo "Step 8: add user mqadmin with pass password  and set_user_tags as administrator"
sudo rabbitmqctl add_user mqadmin password
sudo rabbitmqctl set_user_tags mqadmin administrator

sudo rabbitmqctl set_permissions -p / mqadmin ".*" ".*" ".*"
echo "List user for more info"
rabbitmqctl list_users

Screen Shot 2021-05-14 at 6.18.26 PM

And now, login to your rabbitMQ admin page
http://[your-vultr-server-IP]:15672/
It will be like this
Screen Shot 2021-05-14 at 6.10.57 PM

Connecting to a broker

Every application that uses AMQP needs to establish a connection with the AMQP broker. By default, RabbitMQ (as well as any other AMQP broker up to version 1.0) works over TCP as a reliable transport protocol on port 5672, that is, the IANA-assigned port.

In order to create a Java client that connects to the RabbitMQ broker, you need to perform the following steps:
Below is the example code wrote in java

1. Import the needed classes from the Java RabbitMQ client library in the program namespace:
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
2. Create an instance of the client ConnectionFactory:
ConnectionFactory factory = new ConnectionFactory();
3. Set the ConnectionFactory options:
factory.setHost(rabbitMQhostname);
4. Connect to the RabbitMQ broker:
Connection connection = factory.newConnection();
5. Create a channel from the freshly created connection:
Channel channel = connection.createChannel();”
6. As soon as we are done with RabbitMQ, release the channel and the connection:
channel.close();
connection.close();

Producing messages

After connecting to the broker, as seen in the previous recipe, you can start sending messages performing the following steps:

1.Declare the queue, calling the queueDeclare() method on com.rabbitmq.client.Channel:
String myQueue = "myFirstQueue";
channel.queueDeclare(myQueue, true, false, false, null);
2. Send the very first message to the RabbitMQ broker:
String message = "My message to myFirstQueue";
channel.basicPublish("",myQueue, null, message.getBytes());
S3. end the second message with different options:
channel.basicPublish("",myQueue,MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes());

Notes:
To check the rabbitMQ status on the server, use this command
sudo rabbitmqctl status

Consuming messages

In order to consume the messages sent, perform the following steps:

1. Declare the queue where we want to consume the messages from:
String myQueue="myFirstQueue";
channel.queueDeclare(myQueue,true, false, false, null);
2. Define a specialized consumer class inherited from DefaultConsumer:
public class ActualConsumer extends DefaultConsumer {
  public ActualConsumer(Channel channel) {
    super(channel);
  }
  @Override
  public void handleDelivery(
    String consumerTag, 
    Envelope envelope, 
    BasicProperties properties, 
    byte[] body) throws java.io.IOException {
      String message = new String(body);
      System.out.println("Received: " + message);
    }
}
3. Create a consumer object, which is an instance of this class, bound to our channel:
ActualConsumer consumer = new ActualConsumer(channel);
4. Start consuming messages:
String consumerTag = channel.basicConsume(myQueue, true, consumer);
5. Once done, stop the consumer:
channel.basicCancel(consumerTag);

We are now ready to mix all together, to see the recipe in action:
Start one instance of the Java producer; messages start getting published immediately.
Start one or more instances of the Java/Python/Ruby consumer; the consumers receive only the messages sent while they are running.
Stop one of the consumers while the producer is running, and then restart it; we can see that the consumer has lost the messages sent while it was down.

Here is the diagram of what is happening
Screen Shot 2021-05-16 at 5.48.19 PM

Using body serialization with JSON

Using RPC with messaging

Broadcasting messages

In this example, we are preparing four different codes to broadcast a message to many different consumer:
The Java publisher
The Java consumer
The Python consumer
The Ruby consumer

1. Declare a fanout exchange:
channel.exchangeDeclare(myExchange,“fanout");
2. Send one message to the exchange:
channel.basicPublish(myExchange, "", null, jsonmessage.getBytes());

Then to prepare a Java consumer:

 
1. Declare the same fanout exchange declared by the producer:
channel.exchangeDeclare(myExchange, "fanout");
2. Autocreate a new temporary queue:
String queueName = channel.queueDeclare().getQueue();
3. Bind the queue to the exchange:
channel.queueBind(queueName, myExchange, "");
4. Define a custom, non-blocking consumer, as already seen in the Consuming messages recipe.
Consume messages invoking channel.basicConsume()

Guaranteeing message processing

A message is stored in a queue until one consumer gets the message and sends the ack back to the broker.

The ack can be either implicit or explicit. In the previous examples we have used theimplicit ack.

In order to guarantee that the messages have been acknowledged by the consumer after processing them, you can perform the following steps:

Declare a queue:
channel.queueDeclare(myQueue, true, false, false,null);
Bind the consumer to the queue, specifying false for the autoAck parameter of basicConsume():
ActualConsumer consumer = new ActualConsumer(channel);
boolean autoAck = false; // n.b.
channel.basicConsume(MyQueue, autoAck,consumer);
Consume a message and send the ack:
public void handleDelivery(String consumerTag,Envelope envelope, BasicPropertiesproperties,byte[] body) throws java.io.IOException {

String message = new String(body);
this.getChannel().basicAck(envelope.getDeliveryTag(),false);

Distributing messages to many consumers

Using message properties

Messaging with transactions

Handling unroutable messages

Use rabbitMQ

Additional information: RabbitMQ vs MQTT Comparison

 

RabbitMQ vs MQTT Comparison Table

Let’s discuss the top comparison between RabbitMQ vs MQTT:

RabbitMQ MQTT
Designed as a general-purpose messaging protocol that can be used for message-oriented middleware and for peer-to-peer data transfer. It has been adopted by many big companies/organizations like JP Morgan, NASA (for Nebula Cloud Computing) and Google. In fact, it also finds usage in India’s Aadhar Project, which is the largest biometric database in the world. Designed for IOT devices. Ideal for remote low power devices sending messages over a bandwidth-constrained network. In fact, Facebook uses it because it draws lesser power and is lighter on the bandwidth.
It supports powerful message routing. It is useful when we need to run the same job on a specific server, group of servers or all servers. The application sends one message, and exchange will route it. It doesn’t support complex message routing.
Not wire-efficient and requires more effort for implementing on a client. In order to publish messages to a node, the first step is to establish a link, then enable flow over that link and finally send the messages. It is wire-efficient, and the efforts for implementing on a client are lesser.
It supports both points to point and pub-sub messaging techniques. It supports only the pub-sub messaging technique. It doesn’t support message queues.
It implements SASL mechanisms, thereby enabling users to choose the security they want to (E.g. Kerberos v5) without changing the protocol. It also supports proxy security servers, therefore allowing organizations to use nested firewalls, gatekeepers, etc. In terms of user security, it allows short passwords and usernames that don’t provide enough security in the modern world. In case of any policy change or security weakness, it would require a new version of the protocol.
It doesn’t support LVQs out of the box. It supports Last-Value-Queues (LVQs), which allows a new Consumer to skip previous messages, get the latest ones and then receive updates on the same. A typical use case would be stock prices, where one would be interested in the latest values.
It can have multiple message namespaces, and each of them supports different ways of finding messages. Its only message namespace is a topic, and all messages will go into it.

Conclusion

Both RabbitMQ and MQTT are popular and widely used in the industry. You would prefer RabbitMQ when there is a requirement for complex routing, but you would prefer MQTT if you are building an IOT application. For larger systems, you would probably use a combination of the two so that you can utilize the benefits of both.

## Keyword
AMQP: Advanced Message Queuing Protocol

### Reference

RabbitMQ vs MQTT


https://www.cloudamqp.com/blog/part1-rabbitmq-for-beginners-what-is-rabbitmq.html
https://www.rabbitmq.com/install-rpm.html#downloads
https://github.com/rabbitinaction/sourcecode

Some basic questions about CDN and what for

1. What are the seven requirements of end users that relate to Content Networking?
The seven requirements of end users that relate to Content Networking are performance, availability, anonymity, ubiquity/accessibility, security, privacy, and personalization/relevancy.
2. What are the nine requirements of service providers that relate to Content Networking?
The nine requirements of service providers that relate to Content Networking are security, control, manageability, scalability, flexibility, diversity, customer demographics/data, differentiation, and profitability.
3. What was the original driving factor that led to today’s concept of Content Networking?
The original driving factor that led to today’s concept of Content Networking was performance requirements and to void peering congestion and server constraints.
4. What is a “health check?”
A health check is a test connection of some type sent to a system—often a server, but not always—to ascertain if that service on that system is functioning as expected. A failure means that service on that system won’t be used and a different healthy system must be used instead.

5. What was the original load balancing metric used?
The original load balancing metric used was round robin.
6. What is the most prevalent load balancing metric used? The most prevalent load balancing metric used is Least
Connections–LeastConns.
7. Are server agents an effective tool to improve load balancing metrics?
Server agents are not an effective tool to improve load balancing metrics. The benefit is small for most companies, compared to the cost involved with the type of detailed analysis and management required to make them beneficial rather than useless or even detrimental.
8. What are the most common functions performed by Content Networking devices?
The most common functions performed by Content Networking devices are load balancing, bandwidth management, caching, offload, redirection, and filtering.
9. What is the best data replication method?
The best data replication method depends on the environment and the needs of the business. Many factors must be considered such as data update frequency, purpose of replication (performance vs. availability), and content types.
10. What are the three major types of CDN service?
The three major types of CDN service are Internet CDN, subscriber CDN,
and enterprise CDN.
11. What are the three major types of Internet CDN implementation styles?
The three major types of Internet CDN implementation styles are overlay, peering, and hosting.
12. What are the two main purposes of CDNs?
The two main purposes of CDNs are higher performance and availability.

There are around 21 design patterns and categorize in 3 categories that we will mention here
First, just have a look at the list and categorize it

Creational patterns: Creational patterns support the creation of objects
Singleton pattern
Builder pattern
Factory pattern
Abstract Factory Pattern
Prototype Pattern

Structural patterns: Structural patterns concern class and object compositions
The bridge pattern
The facade pattern
The proxy design pattern
Adapter Pattern
Composite Pattern
Decorator Pattern
Flyweight Pattern

Behavioral patterns: Behavioral patterns concern communication between classes
Observer Pattern
The command design pattern,
The strategy pattern
Chain of Responsibility Pattern
Iterator Pattern
Mediator Pattern
Memento Pattern
State Pattern
Strategy Pattern
Visitor Pattern
Template Method Pattern

And the full list here:
Observer Pattern
Builder Pattern
Model – View – View – Model Pattern
Factory Pattern
Adapter Pattern
Interactor Pattern
Prototype Pattern
State Pattern
Milticast Delegate Pattern
Facade Pattern
Flyweight Pattern
Mediator Pattern
Composite Pattern
Command Pattern
Chain of Responsibility Pattern
Coordinator Pattern