AJAX state 和 readyState

Key

  • AJAX 中的 request 是由 XMLHttpRequest 這個類別的物件處理的
  • 所謂 AJAX 最主要就是要跟伺服器做溝通(request)

readyState

一個溝通一定會有幾個步驟,一開始在跟伺服器進行溝通時,我們需要透過檢查 readyState 這個 XMLHttpRequest 物件的屬性值,來判斷目前的溝通進行到第幾步驟,有以下幾個步驟:

  • 0 還沒開始
  • 1 存取中
  • 2 已存取
  • 3 資訊交換中
  • 4 一切完成

伺服器會回應目前溝通做到第幾步驟給 httpRequest,httpRequest 把回應的值放到 httpRequest.readyState 這個屬性中,所以我們可以透過檢查他的值來判斷現在是做到第幾步驟,其中步驟 4 在 XMLHttpRequest 中有定義一個屬性代表它,用來給我們做判斷

// 建立一個 XMLHttpRequest 物件叫做 httpRequest
var httpRequest = new XMLHttpRequest();

// (跟伺服器進行溝通中..)
...

// 檢查伺服器回應目前溝通做到第幾步驟    
// (下面 if 中把 XMLHttpRequest.DONE 替換成 4 效果一樣)
if(httpRequest.readyState == XMLHttpRequest.DONE){       
    // 一切 OK,完成溝通,繼續解析伺服器回傳結果
} else {
    // 還沒完成
}

state

確認溝通完畢後,接下來我們要做的就是解析伺服器回傳(response)了什麼給我們,第一個要檢查的就是回傳的結果是不是正常,如果正常我們才有必要進一步解析回傳的內容,不正常就要去檢查為什麼不正常,這個正不正常的狀態,就是透過 XMLHttpRequest 物件的 state 這個屬性的值判斷,我們又稱之為 HTTP status code(狀態碼),可以參考這裡有完整的狀態碼列表

所以我們可以繼續完成前面的程式:

// 建立一個 XMLHttpRequest 物件叫做 httpRequest
var httpRequest = new XMLHttpRequest();

// (跟伺服器進行溝通中..)
...

// 檢查是否到最後一個步驟了
if(httpRequest.readyState == XMLHttpRequest.DONE){
    // 一切 OK,完成溝通,繼續解析伺服器回傳結果
    if (httpRequest.status === 200) {
        // HTTP status 200 表示一切正常,可以安心解析伺服器回傳內容啦!
    } else {
        // 似乎有點問題。
        // 或許伺服器傳回了 404(查無此頁)
        // 或者 500(內部錯誤)什麼的
        // 或是 ...
    }
} else {
    // 還沒完成
}

[AWS ECS] 將建立的 EC2 instance 加入指定的 Cluster

要使用 ECS,需要先有 Cluster,然後才在 Cluster 中建立 Containers,在 Container 中才去開 task 運行服務

Create Cluster

先到 ECS 的介面,選擇 Cluster 去建立一個新的 Cluster,Cluster name 輸入完以後可以直接建立

不填寫其他項目的話勾選 Create an empty cluster


如此會建立一個不含任何 container instance 的 cluster


如果建立的不是 empty cluster,則預設會建立個 EC2 instance 到這個 cluster


可以發現後面也是用到 CloudFormation 來建構基礎架構


Launch Container Instance into cluster

http://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_container_instance.html

這裡我們直接到 EC2 console 去建立一個 instance,其中在 Step 3: Configure Instance Details 的地方:

1. 在 IAM 選 ecsInstanceRole

2. 在下面的 Advanced Details 設定 User data

#!/bin/bash
echo ECS_CLUSTER=[CLUSTER_NAME] >> /etc/ecs/ecs.config # 不可以寫成 ecs_config 喔!

這邊只要一個地方寫錯,就會自動變成開到 default cluster (原本沒有 default cluster 就會自動建立一個),而不是我們自己開的 cluster


  • Windows 的話是:
shell
<powershell>
Import-Module ECSTools
Initialize-ECSAgent -Cluster ‘[CLUSTER_NAME]’ -EnableTaskIAMRole
</powershell>

接著就一路 launch

NOTICE 1

etc/ecs/ecs.confog 這是 Optimized Linux 已經開好的檔案[由安裝 ecs-init 建立),使用別的 AMI 建立的 instance 沒有這個檔案,所以如果是其他 AMI 得話這步驟可以跳過,啟動 instance 後在 `sudo start ecs`[1] 之前再自己去建立並且填入資料

NOTICE 2

正常來說應該這樣就會在 Cluster 那邊見到有一個 Registered Container instances 了,但是卻沒有


Troubleshooting 的方式我們可以先 ssh 進去這個 instance

照理來說應該已經註冊了

我們去看 /var/log/ecs/ecs-init.log

bash
[ec2-user@ip-172–31–20–243 ~]$ cat /var/log/ecs/ecs-init.log
2017–11–21T09:07:12Z [INFO] Starting Amazon EC2 Container Service Agent
2017–11–21T09:07:14Z [INFO] Agent exited with code 1
2017–11–21T09:07:14Z [INFO] Container name: /ecs-agent
2017–11–21T09:07:14Z [INFO] Removing existing agent container ID: 3c5290616ea532736f2d8d02465b223a0d148eea4741b3453b7381f3ff563f26
2017–11–21T09:07:14Z [INFO] Starting Amazon EC2 Container Service Agent
2017–11–21T09:07:15Z [INFO] Agent exited with code 1
2017–11–21T09:07:15Z [INFO] Container name: /ecs-agent
2017–11–21T09:07:15Z [INFO] Removing existing agent container ID: 2f946d1903237e5380387032faef443e6a649e11f1066e7bceb7257420321949
2017–11–21T09:07:15Z [INFO] Starting Amazon EC2 Container Service Agent
2017–11–21T09:07:15Z [INFO] Agent exited with code 1
2017–11–21T09:07:15Z [INFO] Container name: /ecs-agent
2017–11–21T09:07:15Z [INFO] Removing existing agent container ID: 7d68f5125d14e73b820ce1eeef48f933c564e6ced416512ce7728ee61154ce2c
2017–11–21T09:07:15Z [INFO] Starting Amazon EC2 Container Service Agent
2017–11–21T09:07:16Z [INFO] Agent exited with code 1
2017–11–21T09:07:16Z [INFO] Container name: /ecs-agent
2017–11–21T09:07:16Z [INFO] Removing existing agent container ID: 8f69f81fa411317e28864da8a536b031cc2cc1bfbc6936400eb8e8b44abed603
2017–11–21T09:07:16Z [INFO] Starting Amazon EC2 Container Service Agent
.
.
.

可以發現一直是以 code 1 結束 (return 0 才是正常結束),接著我們去看 agent log:

$ [ec2-user@ip-172–31–20–243 ~]$ cat /var/log/ecs/ecs-agent.log.2017–11–21–09
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:50Z [INFO] Registering Instance with ECS
2017–11–21T09:11:50Z [ERROR] Could not register: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:50Z [CRITICAL] Could not create cluster: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:50Z [ERROR] Error registering: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:51Z [INFO] Loading configuration
2017–11–21T09:11:51Z [INFO] Loading state! module=”statemanager”
2017–11–21T09:11:51Z [INFO] Event stream ContainerChange start listening…
2017–11–21T09:11:51Z [WARN] Error getting valid credentials (AKID ): NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:51Z [INFO] Registering Instance with ECS
2017–11–21T09:11:51Z [ERROR] Could not register: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:51Z [CRITICAL] Could not create cluster: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
2017–11–21T09:11:51Z [ERROR] Error registering: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
.
.
.

一直都是 CredntialsChainVerboseErrors,就知道是權限沒有給,要到 EC2 去 Attach IAM Role `ecsInstancerole`



attach 後 cluster 那邊馬上就會更新了


NOTICE 3

如果是用一般的 AMI 起的 EC2 instance,到了 attach IAM role 完還是會沒有出現在 ECS cluster 中,這就是為什麼推薦使用 ECS optimized AMI 的原因

EC2 instance 要成為 Container instance 跑在 ECS 能管得到的 cluster 上,需要再 instance 中安裝 ECS agent,因為這個 AMI 已經安裝好 ECS agent,這樣你就不需要自己安裝 agent 了

**Use non-ECS optimized Amazon Linux AMI 起 Instance 加入 Cluster 完整步驟**

參考 Install ECS agent (both Amazon Linux or non-Amazon Linux) — https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-agent-install.html

1. 以一般方式起 Instance
2. 到 EC2 console 將 ecsInstanceRole 這個 IAM policy attach 到這個 instance
3. 連線進入這個 EC2 instance
4. sudo yum install -y ecs-init
5. touch /etc/ecs/ecs.config,然後 vim /etc/ecs/ecs.config 並且填入 ECS_CLUSTER=<指定的 cluster name>
6. sudo service docker start
7. sudo start ecs

NOTICE 4

Windows 的 EC2 instance 註冊到 Cluster 需要一段時間 (5~10 min)

ecsInstanceRole IAM Role

{
“Version”: “2012–10–17”,
“Statement”: [
{
“Effect”: “Allow”,
“Action”: [
“ecs:CreateCluster”,
“ecs:DeregisterContainerInstance”,
“ecs:DiscoverPollEndpoint”,
“ecs:Poll”,
“ecs:RegisterContainerInstance”,
“ecs:StartTelemetrySession”,
“ecs:Submit*”,
“ecr:GetAuthorizationToken”,
“ecr:BatchCheckLayerAvailability”,
“ecr:GetDownloadUrlForLayer”,
“ecr:BatchGetImage”,
“logs:CreateLogStream”,
“logs:PutLogEvents”
],
“Resource”: “*”
}
]
}

[Ruby on Rails] Rails Puma + Nginx 的組合

首先要認識一下兩者分別是什麼東西:

* Puma 是一個專為 Rails 設計的高併發 web server
* Nginx 是一個廣泛使用的 reverse proxy
這個時候可以去查一下什麼事 reverse proxy,就可以發現一張圖說明了兩者之間的關係


所謂的反向代理,是在 server-side 根據 client-side 的 request,向後端的 web server 取得資源,然後再將這些資源 response 給 client-side

另外所謂的前向代理,通常是在 client-side 的軟體,例如瀏覽器會代替 client web page (program)去向CDN請求資源

使用後端代理伺服器的好處是,假設你有很多個 web server,都統一要由單一入口給 client-side 存取,則可以把存取的工作交給 reverse proxy,例如:

Web Server:

* Home Page Web Server
* Forum Web Server
* Wiki Web Server

然後你的客戶會連線到 www.my.domain.com,此時應該存取 Home Page Web Server,但當他連線到 www.my.domain.com/forum 時,應該要存取 Forum Web Server,可是如果把你的網域綁定到 Home Page Web Server,就無法另外連線到不同伺服器了,因此可以改用反向代理伺服器,把網域綁定到這台機器上,當反向代理判斷是要存取 Home Page,就會由他向那台伺服器請求資源,而要存取 Forum 時,就另外再向論壇的伺服器請求資源

另外,反向代理伺服器還有一些對於網站應用程式來說有很大幫助的功能,例如 load balancing、auto-scaling、failover 等

load balancing 會在流量大增的時候進行分流的動作,例如你有多台 forum web server,平時每天流量上萬,為了確保伺服器能夠穩定運作,不會因為短時間的存取量太大導致伺服器處理不及而癱瘓,就可以設定將一部分的存取流量導向 standby 的那台伺服器

auto-scaling 則是可以為你正在服務的伺服器自動依據目前的流量或運算量,最大化可以分配的資源,簡單來說,你有一台伺服器的記憶體有 32GB,分配給網頁伺服器的使用量只有 2GB,如果你的網頁服務需要大量運算(例如線上資料處理或機器學習),很有可能短時間內就把 2GB用完了,因此你可以設定當監測到記憶體快要用罄,系統會自動配置更多的記憶體來應付突發的運算量

failover 則是為了免除網站服務最擔心的事 — 中斷服務(downtime),你的伺服器很有可能被 DDoS 攻擊,或是程式有 bug,使用者不小心觸發導致伺服器掛了,這個時候假如你有一台 standby 的伺服器,有設定好 failover 功能,則會在監控到主要伺服器中斷服務的時候,立刻將存取要求導向那台 standby 的伺服器,縮短 downtime 的時間

說到 DDoS 攻擊,load balancing 或其他相關功能也可以在監控到瞬間變大的流量時,自動將(不正常)流量導向其他地方,就有專門的業者,是提供流量接收的服務,讓一些容易被 DDoS 攻擊的網站服務公司將流量導像他們的伺服器,這個功能的設定也可以在反向代理完成

[OpenStack] 透過 DevStack 在 AWS EC2 Linux 上安裝 OpenStack

  1. Create a EC2 instance and login
  2. Create a stack user
$ sudo useradd -s /bin/bash -d /opt/stack -m stack
$ echo “stack ALL=(ALL) NOPASSWD: ALL” | sudo tee /etc/sudoers.d/stack
$ sudo su — stack

3. Download DevStack

git clone https://git.openstack.org/openstack-dev/devstack

4. create a local.conf in project

cd devstack
vim local.conf

然後

[[local|localrc]]
ADMIN_PASSWORD=secret
DATABASE_PASSWORD=$ADMIN_PASSWORD
RABBIT_PASSWORD=$ADMIN_PASSWORD
SERVICE_PASSWORD=$ADMIN_PASSWORD

5. start the install: ./stack.sh. This will take a 15–20 mins. Once the installation done, all is done.

=========================
DevStack Component Timing
(times are in seconds)
=========================
run_process 15
test_with_retry 2
apt-get-update 12
pip_install 287
osc 112
wait_for_service 15
git_timed 193
dbsync 23
apt-get 265
— — — — — — — — — — — — -
Unaccounted time 341
=========================
Total runtime 1265
This is your host IP address: 172.31.21.104
This is your host IPv6 address: ::1
Horizon is now available at http://172.31.21.104/dashboard
Keystone is serving at http://172.31.21.104/identity/
The default users are: admin and demo
The password: secret
WARNING: 
Using lib/neutron-legacy is deprecated, and it will be removed in the future
Services are running under systemd unit files.
For more information see:
https://docs.openstack.org/devstack/latest/systemd.html
DevStack Version: queens
Change: 28b4be186105888b72300d27166deb771857df06 Merge “Make stackenv file visible” 2018–01–03 23:19:46 +0000
OS Version: Ubuntu 16.04 xenial
2018–01–08 05:30:33.155 | stack.sh completed in 1265 seconds.

最後完成的訊息就這樣,就算完成安裝了

– DevStack 已經安裝好 keystone, glance, nova, cinder, neutron, 和 horizon,可以試著輸入指令看看
– Floating IPs will be available, guests have access to the external world.
– 可以試著存取 Web Interface horizon (URL 在最後的安裝訊息中)
– `source devstack/openrc 後會多了一個 openstack 指令來管理 DevStack
– You can cd `/opt/stack/tempest` and run tempest tests that have been configured to work with your devstack.
– You can make code changes to OpenStack and validate them.

Note for Using AWS EC2 Ubuntu 16.04

因為 EC2 是在 AWS VPC 中所建立的 VM,所以預設認知到的網卡也是區網內的 private IP,因此上面所匹配的 IP Address 173.x.x.x 是 private IP,只需要替換成這個 instance 的 Public IP 就可以成功連線到 dashboard portal 了



[AWS Elastic Beanstalk] 各平台 Proxy Server List

完整關於各個平台和版本採用的 Proxy Server 可以在[這裡](https://docs.aws.amazon.com/zh_cn/elasticbeanstalk/latest/dg/platform-history.html)找到:

Nginx

– Nodejs*
– Go
– Single Container Docker
– Java SE
– Ruby (看版本使用的 application servrer 可能是 puma 或 passenger,前者居多)

Apache

– Node.js*
– Tomcat
– Python
– PHP

Node.js

Node.js 預設是採用 nginx 作為 proxy server,但是官網[文件](https://docs.aws.amazon.com/zh_cn/elasticbeanstalk/latest/dg/create_deploy_nodejs.container.html)有提到可以利用 Ebextension 來設定改用 Apache 作為反向代理伺服器
**.ebextensions/node-settings.config**

option_settings:
aws:elasticbeanstalk:container:nodejs:
NodeCommand: “npm start”
ProxyServer: apache
GzipCompression: true
aws:elasticbeanstalk:container:nodejs:staticfiles:
/images: myimages

IIS

– Windows Server 上的 .NET

HTML5 data-*

這是 HTML5 新加入的屬性,讓你可以自己定義要存放在 element 中的資料,而不需要干擾 class, id, type, name 這些屬性的設置

例如:

== 原本 ==

<button id="good-1" onclick="getId(this);">
<button id="good-2" onclick="getId(this);">

<script>
  function getId(good){
    var id = good.id.split('-')[1];
  }
</script>

== 改寫 ==

<button id="good-1" data-id="1" onclick="getId(this);">
<button id="good-2" data-id="2" onclick="getId(this);">

<script>
  function getId(good){
    // native js
    good.getAttribute('data-id');

    // jQeury
    good.attr('good-id');
    good.data('id')    
  }
</script>

同一個 element 的 data-* 會被存放在一個叫做 dataset 的 object 中,我們可以透過 JavaScript 呼叫 element 的 getAttribute() 來存取對應的資料內容:good.getAttribute('data-id'),也可以呼叫此 element 的 dataset:good.dataset

为什么我们要用 data-* 呢,一个最大的好处是我们可以把所有自定义属性在 dataset 对象中统一管理,遍历啊神马的都哦很方便,而不至于零零散散了,所以用用还是不错的。

Reference:

  1. http://muki.tw/tech/html5-jquery-access-data/
  2. https://www.renfei.org/blog/html5-introduction-2-data-attribute.html

Rails Puma + Nginx 的組合

Rails Puma + Nginx 的組合

首先要認識一下兩者分別是什麼東西:

  • Puma 是一個專為 Rails 設計的高併發 web server
  • Nginx 是一個廣泛使用的 reverse proxy

這個時候可以去查一下什麼事 reverse proxy,就可以發現一張圖說明了兩者之間的關係

(Source: wikipedia)

所謂的反向代理,是在 server-side 根據 client-side 的 request,向後端的 web server 取得資源,然後再將這些資源 response 給 client-side

另外所謂的前向代理,通常是在 client-side 的軟體,例如瀏覽器會代替 client web page (program)去向CDN請求資源

使用後端代理伺服器的好處是,假設你有很多個 web server,都統一要由單一入口給 client-side 存取,則可以把存取的工作交給 reverse proxy,例如:

Web Server:

  • Home Page Web Server
  • Forum Web Server
  • Wiki Web Server

然後你的客戶會連線到 http://www.my.domain.com,此時應該存取 Home Page Web Server,但當他連線到 http://www.my.domain.com/forum 時,應該要存取 Forum Web Server,可是如果把你的網域綁定到 Home Page Web Server,就無法另外連線到不同伺服器了,因此可以改用反向代理伺服器,把網域綁定到這台機器上,當反向代理判斷是要存取 Home Page,就會由他向那台伺服器請求資源,而要存取 Forum 時,就另外再向論壇的伺服器請求資源

另外,反向代理伺服器還有一些對於網站應用程式來說有很大幫助的功能,例如 load balancingauto-scalingfailover

load balancing 會在流量大增的時候進行分流的動作,例如你有多台 forum web server,平時每天流量上萬,為了確保伺服器能夠穩定運作,不會因為短時間的存取量太大導致伺服器處理不及而癱瘓,就可以設定將一部分的存取流量導向 standby 的那台伺服器

auto-scaling 則是可以為你正在服務的伺服器自動依據目前的流量或運算量,最大化可以分配的資源,簡單來說,你有一台伺服器的記憶體有 32GB,分配給網頁伺服器的使用量只有 2GB,如果你的網頁服務需要大量運算(例如線上資料處理或機器學習),很有可能短時間內就把 2GB用完了,因此你可以設定當監測到記憶體快要用罄,系統會自動配置更多的記憶體來應付突發的運算量

failover 則是為了免除網站服務最擔心的事 — 中斷服務(downtime),你的伺服器很有可能被 DDoS 攻擊,或是程式有 bug,使用者不小心觸發導致伺服器掛了,這個時候假如你有一台 standby 的伺服器,有設定好 failover 功能,則會在監控到主要伺服器中斷服務的時候,立刻將存取要求導向那台 standby 的伺服器,縮短 downtime 的時間

說到 DDoS 攻擊,load balancing 或其他相關功能也可以在監控到瞬間變大的流量時,自動將(不正常)流量導向其他地方,就有專門的業者,是提供流量接收的服務,讓一些容易被 DDoS 攻擊的網站服務公司將流量導像他們的伺服器,這個功能的設定也可以在反向代理完成