ログ収集基盤に求められる要素技術を理解する

○○○じゃダメなのか

単なるアプリケーションサーバ
  • 秒間数百とか大量のデータを受け付ける場合に向いてない。
SQSじゃダメなのか
  • キューイングが目的だけど、SQSは大量のデータを受け付けることは目的としてない。
  • SQSは命令をつっこむ、別のworkerがそれを取得して処理をキックするみたいな使い方に向いている。

参考: Amazon SQS と Kinesis はどう違うのか?~ユーザが求めるキュー(queue)の姿~|AWSを使い倒せ | GiXo Ltd.

ストリームデータ処理

こういう、大量にリクエストがきて、低レイテンシで処理をしなきゃいけない場合は、ストリームデータ処理というジャンルの話になってくる。

ただし、単にストリームデータ処理といっても以下のような要素で構成されている。

  • 大量のデータを受け付ける口
  • メッセージキューイング、ユニークIDなどの付与
  • データ処理

AWSでストリームデータ処理するには

AWSであれば

  • 大量のデータを受け付ける -> kinesis
  • メッセージキューイング、ユニークIDなどの付与 -> kinesis
  • データ処理 -> EC2上のkinesis application とか Lambda

Amazon kinesisで広がるリアルタイムデータプロセッシングとその未来

GCPでストリームデータ処理するには

GCPであれば

  • 大量のデータを受け付ける -> pub/sub
  • メッセージキューイング、ユニークIDなどの付与 -> pub/sub
  • データ処理 -> Dataflow

Google Cloud Dataflow を理解する - #bq_sushi

Terraform入門 #2 Terraformはこわくない!!

Terraform入門 #1の続きです。

Terraformを始めるのに一番の障壁

  • 既存のインフラコードで試してみたいけどアクセスキーの準備とかアカウント申請が面倒だし、なんか壊しそうで怖い:scream:
  • 自分でやるにしても、AWS契約しないと試せないんでしょと思って面倒になる:frowning2:
  • もし自分のアカウントでやったときに高額請求されたらどうしよう:worried:

この怖さがTerraformへの障壁をあげてしまってる気がします。少なくともぼくはそうでした。

f:id:masato47744:20170707194957p:plain

簡単に試せるやつあるよ

terraformはAWSのものじゃないと、Terraform入門 #1で言いましたが、他にも適用できるものが用意されてます。もちろん、GCPやAzureなどもそうですが、GitHubなどのサービスに対しても用意されてます。気になった人は、他にはどんなProviderがあるか確認してみましょうHTTPリクエストしたときのresponse bodyを取得するなんてものもあります!!

要はAPI呼び出して何か作成するということをするサムシングがあればそれはterraform化することができると言っても過言ではありません。 その中で簡単に試せるのがDockerです。Macなら簡単にdocker環境は入れられます。みなさんもちろん入ってますよね:eye::eye:?

f:id:masato47744:20170707195051p:plain

DockerでTerraformを試してみよう!

Dockerの初歩的な知識と、Docker for Macはinstallされてる前提で始めます。terraformもhomebrewでさくっと入れておいてください。

それでは早速設定を書いて試していきましょう。

AWSや、GCPの場合でもそうですが、バックエンドにAPI呼び出しをするための設定情報を書きます。これはproviderというディレクティブに書いていきます。 providerさえ書いたらあなたはterraformの世界に入ったと思ってください:tada: Dockerの場合の書き方はTerraformのDocsをみればのっています。ここは最低限のMacのDockerに対して行う設定を書いてみます。

provider "docker" {
  host = "unix:///var/run/docker.sock"
}

Docker for Macの場合、unixドメインソケットで接続してあげるというわけですね。

:point_up:Tips: 最初につまづくのがファイルの命名規則。たいてい、main.tfとか、core.tf、common.tfとかあるんだけど、どうすりゃいいんだと悩みますが、正解はtfがついてればなんでもオーケー。試しにファイル名を好きなものにしてみましょう。

terraform plan

さぁ、あとは好きなだけterraform planコマンドを打ってみましょう! planというのが要はdry runです。絶対に環境を壊すことはないので安心してください。

terraformは現在の状態を保持するといいましたが、planを打つことでその差分を確認できます。 今の状態でterraform planを打ってみましょう。とりあえず何かメッセージが出てきたと思います。providerを書いただけなので、何も差分は出ていないはずです。

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, Terraform
doesn't need to do anything.

Terraformでnginxをたててみる

localhostで8080でdockerでnginxを動かしたい場合、こんな感じでdocker runで実行しますよね。

$ docker run -d --name my-nginx -p 8080:80 nginx:latest
a2c05579e456b51227d7878e6e05754fd76d13b8f7345f39ff97cdeb68458f12

runしたあとはlocalhost:8080にアクセスするとnginxのページが見れます。

$ curl localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

terraform化

このdockerのコマンドの内容をTerraformで表現するとこうなります。先ほどのコマンドがどんなresourceに対応してるかは、公式Docを見れば分かります。

# 最新のnginxイメージ
resource "docker_image" "nginx" {
  name = "nginx:latest"
}

# コンテナ起動
resource "docker_container" "nginx" {
  name  = "my-nginx"
  image = "${docker_image.nginx.latest}"
  ports {
    internal = 80
    external = 8080
  }
}

早速planしてみましょう

こんな感じの出力になったと思います。

$ terraform plan
.
.
+ docker_container.nginx
    bridge:                    "<computed>"
    gateway:                   "<computed>"
    image:                     "${docker_image.nginx.latest}"
    ip_address:                "<computed>"
    ip_prefix_length:          "<computed>"
    log_driver:                "json-file"
    must_run:                  "true"
    name:                      "my-nginx"
    ports.#:                   "1"
    ports.3862886908.external: "8080"
    ports.3862886908.internal: "80"
    ports.3862886908.ip:       ""
    ports.3862886908.protocol: "tcp"
    restart:                   "no"

+ docker_image.nginx
    latest: "<computed>"
    name:   "nginx:latest"


Plan: 2 to add, 0 to change, 0 to destroy.

それぞれ、+がついてるresourceは新しく追加されるreourceを表してます。他には、-が削除、~が変更、-/+というのは削除して新しく作り直すという記号があります。

最後の1行にも、2つのresourceが追加されるよと書いてありますね。

terraform applyしてみよう

実行すると、Applyが成功した出力がでてきたと思います。 ※ apply前に、さっきdocker runしたコンテナはkillしてrm -fしておきましょう。

$ terraform apply
docker_image.nginx: Creating...
  latest: "" => "<computed>"
  name:   "" => "nginx:latest"
docker_image.nginx: Creation complete (ID: sha256:c246cd3dd41d35f9deda43609cdeaa9a...658f9c5e38aad25c4ea5efee10nginx:latest)
docker_container.nginx: Creating...
  bridge:                    "" => "<computed>"
  gateway:                   "" => "<computed>"
  image:                     "" => "sha256:c246cd3dd41d35f9deda43609cdeaa9aaf04d3658f9c5e38aad25c4ea5efee10"
  ip_address:                "" => "<computed>"
  ip_prefix_length:          "" => "<computed>"
  log_driver:                "" => "json-file"
  must_run:                  "" => "true"
  name:                      "" => "my-nginx"
  ports.#:                   "" => "1"
  ports.3862886908.external: "" => "8080"
  ports.3862886908.internal: "" => "80"
  ports.3862886908.ip:       "" => ""
  ports.3862886908.protocol: "" => "tcp"
  restart:                   "" => "no"
docker_container.nginx: Creation complete (ID: 7d5ccd716c3de242af221588ea303b4382dd3ab789f4841f888e2b9b549eda76)

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
...

実際にコンテナがたってるかみてみましょう。動いてますね。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
7d5ccd716c3d        c246cd3dd41d        "nginx -g 'daemon ..."   7 seconds ago       Up 6 seconds        0.0.0.0:8080->80/tcp   my-nginx
$ curl localhost:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

tfstateができています

applyすると、terraform.tfstateというファイルがterraformによって作成されます。その中身がどうなってるか確認してみましょう。jsonファイルにいろんな情報が追加されてますね。この中に自分で指定したresourceの名前などが入ってることを確認してみましょう。

{
    "version": 3,
    "terraform_version": "0.9.9",
    "serial": 0,
    "lineage": "5ecb5960-880c-4d99-88b8-6495ad61c6ea",
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {
                "docker_container.nginx": {
                    "type": "docker_container",
                    "depends_on": [
                        "docker_image.nginx"
                    ],
                    "primary": {
                        "id": "7d5ccd716c3de242af221588ea303b4382dd3ab789f4841f888e2b9b549eda76",
                        "attributes": {
                            "bridge": "",
                            "gateway": "172.17.0.1",
...

差分を発生さてさるみる

先ほどの状態から、8080から8081にportを変更してみましょう。以下の変更を加えて

-     external = 8080
+     external = 8081

planをしてみましょう。

$ terraform plan
-/+ docker_container.nginx
    bridge:                    "" => "<computed>"
    gateway:                   "172.17.0.1" => "<computed>"
    image:                     "sha256:c246cd3dd41d35f9deda43609cdeaa9aaf04d3658f9c5e38aad25c4ea5efee10" => "sha256:c246cd3dd41d35f9deda43609cdeaa9aaf04d3658f9c5e38aad25c4ea5efee10"
    ip_address:                "172.17.0.2" => "<computed>"
    ip_prefix_length:          "16" => "<computed>"
    log_driver:                "json-file" => "json-file"
    must_run:                  "true" => "true"
    name:                      "my-nginx" => "my-nginx"
    ports.#:                   "1" => "1"
    ports.1078587976.external: "" => "8081" (forces new resource)
    ports.1078587976.internal: "" => "80" (forces new resource)
    ports.1078587976.ip:       "" => ""
    ports.1078587976.protocol: "" => "tcp" (forces new resource)
    ports.3862886908.external: "8080" => "0" (forces new resource)
    ports.3862886908.internal: "80" => "0" (forces new resource)
    ports.3862886908.ip:       "" => ""
    ports.3862886908.protocol: "tcp" => "" (forces new resource)
    restart:                   "no" => "no"


Plan: 1 to add, 0 to change, 1 to destroy.

赤い表示で、forces new resourceというものが出てきたと思います。これはどういうことかというと、該当のリソース(ここではコンテナ)を動かしたままportを変更することはできないため、作り直すよってことを言っています。 最後の1行にも英語で1つ追加して、1つ削除しますと書いてあります。

今回は手元のDockerなので作り直しばっちこいですが、もし、これがAWS上のデータベースだとしたら・・:scream:

Terraformを使っていれば、こんな感じで危険を察知できたり、次に何が起きるかが分かるようになります。

applyしてみよう

docker psでCONTAINER IDが変わっているので、再作成されたことが分かります。curlでも8081でちゃんとつながってますね。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
1bf5b57aa7a4        c246cd3dd41d        "nginx -g 'daemon ..."   3 seconds ago       Up 2 seconds        0.0.0.0:8081->80/tcp   my-nginx
$ curl localhost:8081
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

tfstate.backup

新しくterraform.tfstate.backupというファイルができていると思います。これは、前回のものをbackupしたものです。このように前回の状態も自動的に保存しておいてくれます。 applyでどうしようもない誤った変更をしてしまった(いい例が思いつきませんが、、)場合に、そのtfstate.backupファイルからまたresourceを作り直すことができます。やったことないけど、完全に復元とはいかないです。

変数とインターポレーション

先ほどは、1つのコンテナでしたが複数コンテナをたてたいとします。 その場合に、同じ文字列を設定する部分は変数にしたいという思いがおきてくると思います。

例えば、各コンテナの名前は別の名前を設定する必要がありますが、my-nginxというところは同じにして、後ろに1とか2とかをつけることで別名にしたいとします。 その場合は、まずvariableというディレクティブを使って、このように変数を宣言することができます。細かい文法はここは無視してこういう風に宣言すると思ってください。

variable "name" {
  default = "my-nginx"
}

そして、containerのリソース側で呼び出すときは、var.nameでアクセスできて、${}を使って変数展開できます。shの変数展開の書き方とそっくりですね。

resource "docker_container" "nginx_1" {
  name  = "${var.name}-1"
  image = "${docker_image.nginx.latest}"
  ports {
    internal = 80
    external = 8080
  }
}

resource "docker_container" "nginx_2" {
  name  = "${var.name}-2"
  image = "${docker_image.nginx.latest}"
  ports {
    internal = 80
    external = 8081
  }
}

この状態でplanをしてみましょう。nameの部分が変数展開されていることが分かるかと思います。

+ docker_container.nginx_1
.
    name:                      "my-nginx-1"
.
.
+ docker_container.nginx_2
.
    name:                      "my-nginx-2"
.

ちょっと待って:raised_hand:

このコードを見て、プログラマのみなさんならうずうずしてしまう部分があるかと思います。 そう、port指定の80808081、nameのsuffixの-1-2のようなベタ打ちはなるべく避けたいのではないのでしょうか。変数に配列、そしてforやifが使えれば・・・・

terraformでもfor文やif文のような機能がある

手続き型プログラミング言語ではないので素直にforやifと素直にはいかないですが、それと同じことを実現する手段は用意されています。

実際にコードを見てみた方が早いと思います。こちらをご覧ください。

variable "ports" {
  default = [8080, 8081, 8082, 8083]
}

variable "name" {
  default = "my-nginx"
}

resource "docker_container" "nginx" {
  count = "${length(var.ports)}"

  name  = "${count.index % 2 == 0 ? "${var.name}-a-${count.index + 1}" : "${var.name}-b-${count.index + 1}"}"
  image = "${docker_image.nginx.latest}"
  ports {
    internal = 80
    external = "${var.ports[count.index]}"
  }
}

resource "docker_container" "nginx"の下に新たにcountと書かれたところがあります。これは、countに渡した数だけresourceを作ってくれ、これがfor文相当です。 lengthというビルトイン関数を利用して、portsという配列の長さをとってきています。 そして、count.indexで該当のindexにアクセスできます。forのindex相当です。

nameのところで書いているのがif文相当です。if文は書けないので三項演算子が用意されています。この処理の場合は、偶数の場合は、aという文字を、奇数の場合はbという文字を追加しています。

この状態でplanをしてみましょう

出力された結果はnameやportが想定した値となっているでしょうか。このように共通した処理はforやifなどを使ってまとめて書くことができます。

実際は、interpolationというところにもっとビルトイン関数が用意されてます。また、変数のタイプもmapやbooleanなどがあり、variablesにまとまっています。手元のdockerなので、ぶっ壊れても安心なのでいろいろと試してみましょう!

まとめ

Dokerを通してTerraformを気軽に試せる環境について紹介しました。 Providersを見て、Terraformで管理したら便利そうだなと思うものがあれば、自分の遊びプロジェクトでで導入してみるといいかもしれませんね:heart_eyes: 次回は、実践的な環境でTerraformのコードをリファクタリングしていく内容を紹介していこうと思います。リファクタリングの過程を通して実践的な知識を学んでもらえればと思います。題材は検討中・・

Terraform入門 #1 Terraformはいいぞ

前書き

人が書いたterraformのメンテぐらいは見よう見まねでやってるけど、一からやれと言われたらよく分からない。そう思ってた1年前ぐらいの自分を思い出しながら気軽に入門してもらうにはどうすればいいか考えてみました。 Terraformはこわくないしほんとに便利なので、その辺を感じ取ってもらえればと思います。

f:id:masato47744:20170707194146p:plain

Terraformは何であって何でないのか、そしてなぜ必要なのか

そもそも、学習するにあたってTerraformって最高便利というところが分かってないと、なんでやらなあかんねんとなりそうだなと思ったので、まずはなぜ必要かを説明していきます。

Terraformってインフラのコードで書くやつでしょ?

terraformはインフラのリソースをコードで書けて実際に作成まで行ってくれます。この辺はだいたい知ってると思います。 ただ、Terraformはchefとかansibleといったプロビジョニングツールとはちょっとレイヤーが違います

terraformはインフラの土台を作るもの、chefとかはそれに味付けをしていくという役割になります。雑に示すとこんな感じです。

f:id:masato47744:20170707194326p:plain

Terraformは何をしてるのか

terraformは内部的には単にユーザーが書いたインフラの設定を見てAPIを呼んでるだけです。AWSならAWSのインフラの設定を書いて、単に裏側でAWSAPIを呼んでるだけです。

f:id:masato47744:20170707194355p:plain

じゃあなんでわざわざterraformなるものをかませないといけないのか。AWSAPIを呼べばいいじゃんとなりますよね。次からは、実際にインフラを管理していくときに起きる問題点をあげながら、terraformのいいところを見ていきます。

Terraformのいいところ

terraformのいいところは、API呼び出しをしてくれるだけでなく、その状態を保持してくれます。また、リソース同士の依存関係も表現してくれます。それぞれみていきましょう。

インフラの状態を保持する

AWSGUIだと現在の状態が想定しているものなのか、誰かが手動で変更したかなど分かる術はありません。操作ログを見れば分かることは分かりますが現実的じゃありません。

この問題をterraformがどう解決しているかというと、tfstateというjsonファイルに、テキストでインフラのリソースの情報を保存することで状態を記憶するというアプローチをとっています。結構単純です。

リソースを新しく追加したり、削除したり、パラメータを少し変更したい場合は、このtfstateファイルと実際の状況をAPIを呼び出して確認し、必要最低限の差分のみ反映(API呼び出し)をしてくれます。もちろん差分がなければ何もしません。

f:id:masato47744:20170707194424p:plain

依存関係

依存関係については、この辺はAWSとかでいざAPIをたたいてみないと分からないとは思うんですが、何かリソースを作るときには必ず他のリソースの情報が必要になると言えます。

例えば、EC2のインスタンスIPアドレスを使ってDNSレコードを作りたいという場合があったとき、これをAPIでやるとこんな感じで呼び出しが必要です。

f:id:masato47744:20170707194447p:plain

  1. EC2作成APIたたく
  2. 作り終わるのをしばし待つ
  3. 2のIDとかを指定して、EC2の詳細情報取得APIを呼ぶ
  4. IPアドレスjsonから見つけてくる
  5. 4のIPアドレスをRoute53のレコード作成APIたたく

これが複数台ともなるとやってられなくなるでしょう、また、実際はもっと複雑な依存関係を持っています。

terraformなら、こんな感じで書いて1回実行するだけで、terraformが賢くAPI呼び出しをしてくれます。

resource "aws_instance" "web" {
  ami_id        = "ami-123456"
  instance_type = "t2.micro"
}

resource "aws_route53_record" "www" {
  zone_id = "Z12345678"
  name    = "abc.example.com"
  type    = "A"
  ttl     = "300"
  records = ["${aws_instance.web.public_ip}"]
}

上の例で、recordsのところに、aws_instance.web.public_ipという自分で書いたまだ実際に作成されていないリソースのIPアドレスを設定することができています!ここがすごいところで依存関係が記載できていることになります。 ソースの詳細はあまり気にせずここでは雰囲気を感じ取ってください。

複数プロバイダにまたがれる

さっきの例で、例えばだけど、AWSで色々作ってるんだけど、なんかDNSだけは会社の制度で、別のサービスで管理しないといけない。そんなことがあった場合は、依存関係はもっと複雑になります。AWSAPIの知識に加え、その別のサービスのAPIの知識も必要です。 また、呼び出し方も独特の違いがあるでしょう。

こんなときもTerraformは便利で、Terraformにはプロバイダと呼ばれる概念があり、これはAWSGCPなどクラウドプラットフォームなどが主なもので色々用意されています。AWSは用意されているプロバイダの一つに過ぎないのです。 プロバイダは自作することもできますが、公式にあるもので基本的には困らないと思います。

先ほどの例で、DNSだけは、DNSimpleというサービスを使うことになったとしましょう。そんなときは、先ほどのaws_route53_recordの部分の設定をdnsimple_recordに変えて、providerの情報を追加してあげるだけでいいのです。 DNSimpleのAPI呼び出しってどうやるんだろうって調べる必要がないのがすごいところです。

resource "aws_instance" "web" {
  ami_id        = "ami-123456"
  instance_type = "t2.micro"
}

provider "dnsimple" {
  token = "hogehogetoken"
  account = "piyopiyo"
}

resource "dnsimple_record" "www" {
  domain = "example.com"
  name   = "abc"
  value  = "${aws_instance.web.public_ip}"
  type   = "A"
  ttl    = 300
}

まとめ

どうでしょうか、Terraformのありがたみが分かったでしょうか?他のツールじゃなぜダメなんだとか、あれじゃダメなのとか疑問が湧いたら調べたり、質問してみたりしてください。きっと理解が深まると思います。 次回は、Terraformをもっと身近に感じるために気軽にできる環境で説明していこうと思います。

mpon.hatenablog.com

GoogleAnalyticsのiOS SDKをpodspec側のdependencyにすると相性が悪い

GoogleAnalyticsのSDKのラッパーライブラリを作りたい

そのためには、podspec側にdependencyを書いておく必要がある。こんな感じ。

Pod::Spec.new do |s|
  s.name             = 'Example'
  s.version          = '0.1.0'
  s.summary          = 'A short description of Example.'
略
  s.dependency 'Google/Analytics'
end

これでpod installをするとtransitive dependencyのエラーが出てpod installができなくなってしまう。 原因は、GoogleAnalyticsが提供しているライブラリがFramework形式ではなく、.aのstatic libraryのためGoogle様がどうにかしてくれないとどうしようもない。 swiftの場合、use_frameworks!が必要なため、ここで詰まってしまう。

回避策、そしてまた別の問題

Podfile側に下記のworkaroundを入れれば回避可能。 https://github.com/CocoaPods/CocoaPods/issues/3289

pre_install do |installer|
    def installer.verify_no_static_framework_transitive_dependencies; end
end

しかし、pod installはうまくいくけどライブラリはリンクされないため結局ライブラリ側ではGAのSDKが利用できない。 リンクさせるためには、下記のようにpodspec側のxcconfigにFRAMEWORK_SEARCH_PATHSLIBRARY_SEARCH_PATHSなどを追記していかないといけない。実際は、他にも必要だが何が必要かを探して自分で書いていかないといけない。

  s.pod_target_xcconfig = {
    'FRAMEWORK_SEARCH_PATHS' => '"${PODS_ROOT}/Google/Frameworks"'
  }

言語のコミュニティがどうとかどうでもいい

当方、iOSをobjcからやってて、Androidも少し。フロントエンドは、jqueryの頃から、typescriptあたりまでなんとなく。 サーバーは、RailsScala Play frameworkあたりを少々。 今はインフラ周り、AWSGCP、コンテナ周りは、docker、k8s、ECS、Deisなどを、少々かじっております。

で、

Scalaの話でなんかコミュニティがどうこうで揉めてるのを見て、なんかほんと、どうでもいいことで争ってる。言語なんてなんだっていいんだよ。ある言語をわかってる人は、いざやってみたら多分どのパラダイムでも、すぐ理解できる。分からないってなら、多分何やっても分からない。

なんていうか、外野のあーだこーだ、コミュニティがどうこうなんてどうでもいい。第一線の人たちは一般人なんかシカトでいいです。

ほんと、みんなすごい人たちなんだから、一般人がどうこうとか、コミュニティ怖いとかどうでもいい。みなさんは、ソフトウェアを作って欲しい。ぼくたちみたいな一般人なんて相手にしなくていいよ。

日本で有名な人たちは、一般人なんて相手にしなくていいから、日本発、すごいソフトウェアをみんな作ってて欲しい><

外国では次から次へと有名なソフトウェアが生まれて、何も生み出さない自分を悔しく思って。 こんな何もできない自分に比べてもっとすごい人たちが、なんか、しょうもないあーだこーだに巻き込まれてるのはもったいないし、損失だなと。

Objective-Cのallocは何をしてるのか

allocはNSObjectのクラスメソッド

alloc - NSObject | Apple Developer Documentation

+ (instancetype)alloc;

The isa instance variable of the new instance is initialized to a data structure that describes the class; memory for all other instance variables is set to 0.

初期化前にメモリを確保。なのでこの時点で一応インスタンスはできている。でも初期化はされてない。サイズは確保されてない状態ってことだと思う。initして初めてサイズが確保される。なので、allocの返り値の型とinitの返り値の型は同じ。

Swiftの場合、 Hoge() ってやると、[[Hoge alloc] init]; まで呼ばれるのでallocを意識することはない。

allocationの説明

developer.apple.com

isaとは

http://algorithm.com.au/downloads/talks/objective-c-internals/objective-c-internals.pdf

In other words, an NSObject is simply a struct with a single field, named isa (“is a”, as in “a car is a vehicle”) that points to some sort of Class type.