尝试开发Mall系统

4 分钟读完

尝试开发mall系统,简单想法。

1. 动静分离

动静分离是将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问。

  • 静态资源部署至CDN上
    项目中的JavaScript,CSS以及img文件都是存放在CDN服务器上,将HTML文件一起存放到CDN上之后
  • 后端API提供数据
    后端应用提供API,根据前端的请求进行处理,并将处理结果通过JSON格式返回至前端。
  • 前后端域名
    • 相同域名
      用户请求api时可以避免跨域所带来的问题,相对开发更为快速,工作量也相对小一些。
    • 不同域名
      兼容跨域请求的情况,JSONP 或 CORS(需要浏览器支持)
  • 优点
    api接口服务化; 前后端开发并行; 减轻后端服务器压力,提高静态资源访问速度
  • 缺点
    开发量变大 前后端交流成本升高 不利于网站SEO
  • 结论
    小项目,有扩展可能,采用: 相同域名, nginx处理静态,go提供API。
    初始状态:user –> nginx –> mall-api –> mysql
    升级版本:user –> CDN/ haproxy –> nginx(多个) –> mall-api(多个) –> redis集群 –> mysql-proxy —> mysql master/slave(多个)

2.GO实现API

使用beego框架生成api

2.1 生成api

考虑用docker容器安装, 参考 docker笔记 启动mysql 将建表语句文件放在$HOME/docker/mall.sql中,执行建表SYS_MENU_INF, 创建mall-api

docker run -it --link malldb:mysql -v $HOME/docker:/home/ --rm mysql:8.0 sh -c 'exec mysql -h"172.17.0.2" -P3306 -uroot -prootpw mall </home/mall.sql'

cd $GOPATH/src/github.com/zerodollar
bee api mall-api -tables="SYS_MENU_INF" -driver=mysql -conn="root:rootpw@tcp(127.0.0.1:3306)/mall"

生成的文件结构是

mall-api
├── conf
│   └── app.conf
├── controllers
│   └── SYS_MENU_INF.go    对应表Post/GetOne/GetAll/Put/Delete
├── main.go
├── models
│   └── SYS_MENU_INF.go     表对应的结构
├── routers
│   └── router.go           路由 /v1/SYS_MENU_INF
└── tests

2.2 测试访问

插入预置数据到SYS_MENU_INF表中,以bee方式启动,可以监控文件变动自动编译、重启 注意检查conf/app.conf中EnableDocs = true

cd $GOPATH/src/github.com/zerodollar/mall-api
bee run watchall -gendoc=true -downdoc=true

打开浏览器访问http://localhost:8080/v1/SYS_MENU_INF/ , 会以json返回所有记录

2.3测试API文档

访问API文档 http://localhost:8080/swagger/, 如果要支持中文,修改mall-api/swagger/index.html,打开对应的lang注释, 重新访问就是中文了

<script src='lang/translator.js' type='text/javascript'></script>
<script src='lang/zh-cn.js' type='text/javascript'></script>

2.4 生成docker镜像

构建linux运行包生成镜像,但docker hub只支持一个仓库,无法再push

export GOOS=linux
go build 
cp mall-api ~/docker
docker build -f Dockerfile.mall-api -t z29759/mall-api .

文件~/docker/Dockerfile.mall-api

FROM scratch
ADD ./mall-api  /home/mall-api
ADD ./conf/app.conf /home/conf/app.conf
ENTRYPOINT ["/home/mall-api" ]

2.5 启动镜像

启动镜像,访问

export MYSQLIP=`docker inspect malldb|jq ".[0].NetworkSettings.IPAddress"|sed 's/"//g'`
docker run -p 8080:8080   --name mallapi --link malldb:mysql -d z29759/mall-api  -db "root:rootpw@tcp($MYSQLIP:3306)/mall"

3.前端

前台用 Angular2.0+TypeScript 做js框架,使用AdminLTE做css框架

使用angular-cli脚手架

sudo npm config set registry https://registry.npm.taobao.org
sudo npm install -g typescript typings  angular-cli@latest
ng completion 1>> ~/.oh-my-zsh/custom/zjy.zsh
ng new mall-cli  --style less
cd mall-cli
npm start

引入 Admin-LTE

angular-cli.json 的 apps -> scripts ->添加

        "../node_modules/jquery/dist/jquery.js",
        "../node_modules/bootstrap/dist/js/bootstrap.js",
        "../node_modules/admin-lte/dist/js/app.js"

package.json中dependencies增加

"admin-lte": "^2.3.8",
"bootstrap": "^3.3.7",
"jquery": "^3.1.1",
"font-awesome": "^4.7.0",
"angular2-toaster": "^1.0.2",
"ng2-translate": "^4.2.0",
"ionicons": "^3.0.0",

安装依赖插件

npm install

支持用户

用户模型定义/服务定义

ng g class models/user
ng g s services/user

定义currentUser: ReplaySubject ,表示User会缓存

添加转换 Service

引用了use的语言设置,再设置translate

ng g s services/translate

assets/i18n/en.json 多语言 assets/img/ 图片· fonts 字体

添加主页 components

cd  src/app
ng g c  pages/home

app-header 导航条 app-menu-aside 左侧边栏 div中router-outlet 页面内容 app-footer 脚注 app-aside 右侧边栏

设置图标

fa-circle-o 类似的是从这里获取的: http://fontawesome.io/icons/

跨域

参考Stackoverflow

beego.InsertFilter("*", beego.BeforeRouter,cors.Allow(&cors.Options{
 AllowOrigins: []string{"https://*.foo.com"},
 AllowMethods: []string{"PUT", "PATCH"},
 AllowHeaders: []string{"Origin"},
 ExposeHeaders: []string{"Content-Length"},
 AllowCredentials: true,
 }))

参考vue跨域

 func (c *BaseController) AllowCross() {
    c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", "http://localhost:8080")       //允许访问源
    c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS")    //允许post访问
    c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization") //header的类型
    c.Ctx.ResponseWriter.Header().Set("Access-Control-Max-Age", "1728000")
    c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Credentials", "true")
    c.Ctx.ResponseWriter.Header().Set("content-type", "application/json") //返回数据格式是json
}
beego.NSNamespace("/*",
            //Options用于跨域复杂请求预检
            beego.NSRouter("/*", &v1.BaseController{}, "options:Options"),
        ),
        func (c *BaseController) Options() {
    c.AllowCross() //允许跨域
    c.Data["json"] = map[string]interface{}{"status": 200, "message": "ok", "moreinfo": ""}
    c.ServeJSON()
}
  • Refused to set unsafe header “Origin”
    客户端的Header不需要设置Origin

4.MySQL 读写分离

MySQL读写分离

  • 应用层实现
    Sprint JDBC/mhBatis/Hibernate访问数据库时配置多数据源,组件会将请求分流到不同的数据源
    一个MasterDataSource,更新数据时用
    一个SlaveDataSource,查询数据时用,如果有多个从,集成AbstractRoutingDataSource自己实现算法 不需要底层复杂的配置/性能较好,对应用侵入比较强/不利于扩展
  • 代理实现
    应用层和数据库集群间添加一个代理服务。

MySql读写分离,及数据库高可用负载均衡的实现
proxy代理client和mysql服务,根据sql操作路由到master/或slave 实现读写分离的工具有很多,阿里巴巴的cobar/360的atlas/go写的kingshard

  • 1.读写分离。
  • 2.跨节点分表。
  • 3.客户端IP访问控制。
  • 4.平滑上线DB或下线DB,前端应用无感知。

5.各模块启动命令

mysql

cd mysql
docker  build -t zerodollar/mysql .
docker ps |grep malldb|awk '{print $1}'|xargs docker stop
docker ps -a|grep malldb|awk '{print $1}'|xargs docker rm
docker run --name malldb -p 3306:3306 -e MYSQL_ROOT_PASSWORD=rootpw -v `pwd`/malldb_volume:/var/lib/mysql -d zerodollar/mysql
export MYSQLIP=`docker inspect --format  malldb`
docker run -it --link malldb:mysql -v `pwd`:/home/ --rm zerodollar/mysql sh -c "exec mysql -h$MYSQLIP -P3306 -uroot -prootpw </home/mall.sql"

如果有仓库,直接push后run 没有,打包tar czvf mysql.tar.gz --exclude mysql/malldb_volume mysql,上传aws后解压重复上面命令

mall-api

cd mall-api/docker
export GOOS="linux"
go build ..
cp -r ../conf .
docker build -t zerodollar/mall-api .
docker ps |grep mall-api|awk '{print $1}'|xargs docker stop
docker ps -a|grep mall-api|awk '{print $1}'|xargs docker rm
export MYSQLIP=`docker inspect --format  malldb`
export MYHOSTIP=`ifconfig en0|grep -w inet|awk '{print $2}'`
docker run -p 8080:8080  -e GOPATH=/ -e "TRUST_URL=http://$MYHOSTIP" --name mallapi --link malldb:zerodollar/mysql -d zerodollar/mall-api  -db "root:rootpw@tcp($MYSQLIP:3306)/mall"  

如果有仓库,直接push后run 没有,打包tar czvf mall-api.tar.gz docker,上传aws后解压重复上面命令 开发态简单,bee run可以监控代码改动

mall-cli

cd mall-api
rm -fr docker/dist
ng build -prod --aot=true  --output-path docker/dist
cd docker
docker build -t zerodollar/mall-cli .
docker ps |grep mall-cli|awk '{print $1}'|xargs docker stop
docker ps -a|grep mall-cli|awk '{print $1}'|xargs docker rm
docker run -p 80:80 -p 443:443 -d -t --name mall-cli zerodollar/mall-cli

如果有仓库,直接push后run 没有,打包tar czvf mall-cli.tar.gz docker,上传aws后解压重复上面命令 开发态简单,npm start可以监控代码改动

aws

  • 配置默认用户ec2-user使用docker
    通过ssh登陆aws虚拟机,配置ec2-user免sudo使用docker
    ssh -i your_certi.pem  ec2-user@ec2****compute.amazonaws.com
    sudo passwd root    #可以修改root密码
    sudo systemctl  start  docker.service   #root启动docker服务
    sudo usermod -a -G docker  ec2-user     #加入docker组方法1
    sudo gpasswd -a ec2-user docker         #加入docker组方法2
    sudo service docker restart        #重启docker服务
    newgrp - docker                    #切换当前会话组为docker
    groups                             #查看ec2-user用户属于组docker users
    docker ps                          #跨域使用了
    
  • 创建docker仓库
    aws管理台登陆,启用EC2 Container Service,创建存储库 mall-api,按查看推送命令得到具体指导

  • 升级aws cli
    系统自带的aws不支持aws ecr,需要升级
    wget  https://bootstrap.pypa.io/get-pip.py
    sudo python get-pip.py
    sudo python get-pip.py
    sudo pip install --upgrade awscli
    
  • 配置aws cli
    我的安全凭证 > 访问密钥(访问密钥 ID 和私有访问密钥) > 创建访问密钥 ,需要立刻下载,后面不能再查看/下载, 访问密钥(Access Key ID),私有访问密钥(Secret Access Key) 推送命令显示aws ecr get-login --region us-west-2 得到Default region name为us-west-2 参考aws的官方文档,配置客户端:
    aws configure
    aws ecr get-login --region us-west-2  #拷贝输出信息并执行,成功后凭证保存在~/.docker/config.json
    
  • 升级docker版本
    docker 版本低,可能报Error response from daemon: Cannot find child for ..., 升级到最新版本 由于安装的是suse,参考docker官方文档升级
    $ service docker stop
    $ sudo zypper addrepo     https://yum.dockerproject.org/repo/main/opensuse/13.2/     docker-main
    $ sudo  zypper refresh
    $ zypper search -s --match-exact -t package docker-engine
    $ sudo zypper install docker-engine-<VERSION_STRING>
    $ sudo service docker start
    
  • 上传gz包
    由于镜像较大,上传gz报到aws,在其上作镜像非常快 将3个gz包上传aws,sftp -i your_certi.pem ec2-user@ec2****compute.amazonaws.com

  • 导入镜像
    简单docker load

  • 启动
    export AWS=920063008583.dkr.ecr.us-west-2.amazonaws.com
    #启动mysql
    docker run --name malldb -p 3306:3306 -e MYSQL_ROOT_PASSWORD=rootpw -v ~/malldb_volume:/var/lib/mysql -d $AWS/mysql
    export MYSQLIP=`docker inspect --format  malldb`
    docker run -it --link malldb:${AWS}/mysql -v `pwd`:/home/ --rm ${AWS}/mysql sh -c "exec mysql -h$MYSQLIP -P3306 -uroot -prootpw </home/mall.sql"
    export MYSQLIP=`docker inspect --format  malldb`
    docker run -p 8080:8080  -e GOPATH=/  --name mallapi --link malldb:$AWS/mysql -d $AWS/mall-api  -db "root:rootpw@tcp($MYSQLIP:3306)/mall"  
    docker run -p 80:80 -p 443:443 -d -t --name mall-cli $AWS/mall-cli
    

    之后就可以通过http://ec2-<IP>.us-west-2.compute.amazonaws.com/访问了

FAQ

  • 报错:service: no such service docker
    systemctl unmask docker.service
    systemctl unmask docker.socket
    systemctl start docker.service
    

留下评论

您的电子邮箱地址并不会被展示。请填写标记为必须的字段。 *

正在加载...