go言語で作るアドサーバー2 広告を重みづけをして配信する

まず、広告がソースコードべた書きだと管理が大変なのでMySQLに広告テーブルを作ってそこからデータを読みに行くようにする。

まず、ドライバを入れる為にgo getコマンドを使うので、まずGOPATHを設定する
gitが入っていなければgitを入れる

apt-get install git
go get github.com/go-sql-driver/mysql   

mysqlのドライバを入れる


それぞれの広告の広告単価ecpmに応じて広告出現率を変更する。

ecpmの計算は、インプレッション広告だったり、クリック広告だったり、アフィリエイト(成果報酬)広告だったり、DSP(オークション)広告だったりで算出方法とシステムが異なるので、それらは予め計算されてテーブルに入っていることとする。実はここが大変だったりする。ecpmが算出されていれば、あとはそれに応じて広告の表示比率を変えるだけである。

  • 広告テーブルを作る。本当はpublisherのテーブルやら、いろいろ必要だが、ここでは必要最低限のadテーブルのみとする
CREATE TABLE `ad` (
 `ad_id`        bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '広告ID',
 `ad_type`      int(10)    unsigned NOT NULL DEFAULT '0' COMMENT '広告タイプ',
 `ad_text`      text       CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'テキスト',
 `ad_ecpm`      int(11)  NOT NULL DEFAULT '0',
 `ad_create_at` datetime NOT NULL COMMENT '作成日時',
 `ad_update_at` datetime NOT NULL COMMENT '更新日時',
 `ad_delete_at` datetime DEFAULT NULL COMMENT '削除日時',
 `ad_delete_flg` tinyint(4) DEFAULT NULL COMMENT '削除フラグ',
 PRIMARY KEY (`ad_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 COMMENT='広告テーブル'
INSERT INTO  `ad`.`ad` (
`ad_id` ,
`ad_type` ,
`ad_text` ,
`ad_ecpm` ,
`ad_create_at` ,
`ad_update_at` ,
`ad_delete_at` ,
`ad_delete_flg`
) VALUES
 (NULL ,  '0',  '[AD]広告1',  '10', NOW( ) , NOW( ) , NULL ,  '0'),
 (NULL ,  '0',  '[AD]広告2',  '20', NOW( ) , NOW( ) , NULL ,  '0'),
 (NULL ,  '0',  '[AD]広告3',  '30', NOW( ) , NOW( ) , NULL ,  '0')
;
package main

import(
	"fmt"
	"math/rand"
	"time"
	"net/http"
	"runtime"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
)

var (
	adTexts = make([]string,0)
)

func handler(w http.ResponseWriter, r *http.Request) {
	rand.Seed(time.Now().UnixNano())
	fmt.Fprintf(w,adTexts[rand.Intn(len(adTexts))])
}

func main(){
	// DBからデータを読み込み
	db, err := sql.Open("mysql", "root:@unix(/var/run/mysqld/mysqld.sock)/ad")
	if err != nil {
	panic(err.Error())
	}
	defer db.Close()

	rows, err := db.Query("SELECT * FROM ad") 
	if err != nil {
		panic(err.Error())
	}

	columns, err := rows.Columns()
	if err != nil {
		panic(err.Error())
	}

	values := make([]sql.RawBytes, len(columns))

	scanArgs := make([]interface{}, len(values))
	for i := range values {
		scanArgs[i] = &values[i]
	}

	for rows.Next() {
		err = rows.Scan(scanArgs...)
		if err != nil {
			panic(err.Error())
		}

		var value string
		for i, col := range values {
			if col == nil {
				value = "NULL"
			} else {
				value = string(col)
			}
			if columns[i] == "ad_text" {
				adTexts = append(adTexts,value)
			}
			fmt.Println(columns[i], ": ", value)
		}
		fmt.Println("-----------------------------------")
	}

	runtime.GOMAXPROCS(runtime.NumCPU())
	http.HandleFunc("/",handler)
	http.ListenAndServe(":8080",nil)
}
  • my.cnf tcpのポートを閉じる
[mysqld]
skip-networking

go言語でSQLの処理はちょっとしんどい