本周一,著名游戲引擎開發商 Unity 的股價下跌7%,起因是公司董事會拒絕了另一家游戲業巨頭 AppLovin 的收購要約。據了解,Unity 官方對于這次事件的解釋主要歸結于 AppLovin 的200億美元出價不符合 “ Unity 股東的最佳利益”。
據新浪VR了解,AppLovin 上周報出了每股 58.85 美元的收購價,這比當時的收盤價溢價了 18%,但在如日中天的 Unity 眼中,本次收購對公司整體利益而言并非最佳選擇,董事會反而建議其股東同意以 44 億美元收購 AppLoivin 的競爭對手 —— IronSource ,而該提議也于上個月達成了意向。
“通過與 IronSource 的交易,我們會在未來給股東帶來更大的收益。” Unity 首席執行官 John Riccitiello 周一對外公開表示。而根據 AppLovin 的提議,Unity 將不得不放棄對 IronSource 的收購,雖然 Riccitiello 依然會成為合并后新公司的首席執行官。
熟悉此事的消息人士稱,在評估了 AppLovin 提出的報價(該報價將使 Unity 獲得合并后公司 55% 的流通股和 49% 的投票權)后,Unity 及其顧問認為本次交易(被收購)完成后將導致公司未來過度投資廣告技術,并在一定程度上偏離此前的主業。與之相較,收購 IronSource 則有具有極佳的平衡性,從而在穩定基本盤的同時,增加營收途徑。
作為這兩次收購與被收購事件的核心人物,Riccitiello 的態度則非常清晰:“很明顯,AppLovin 的提議并不會帶來更好的規劃,而我們對 IronSource 的收購則更具積極意義,我們可以在本次交易的基礎上更好地服務客戶,并為股東帶來更大的收益。”
值得一提的是,就在本次拒絕收購事件公開后,AppLovin 的股價當日下跌了 4%,IronSource 則飆升約 13.4%。
1.Unity背景資料
Unity 是聞名全球的實時3D互動內容創作和運營平臺。包括游戲開發、美術、建筑、汽車設計、影視在內的所有創作者,均可借助 Unity將創意變成現實。Unity 平臺提供一整套完善的軟件解決方案,可用于創作、運營和變現任何實時互動的 2D 和 3D 內容,支持平臺包括手機、平板電腦、PC、游戲主機、增強現實和虛擬現實設備。
目前,基于 Unity 開發的游戲和體驗月均下載量高達 30 億次 ,并且其在 2019 年的安裝量已超過 370 億次 。全平臺(包括PC/主機/移動設備)所有游戲中有超過一半都是使用 Unity 創作的;在 蘋果應用商店和 Google Play 上排名最靠前的 1000 款游戲中,53% 都是用 Unity 創作的。此外,Unity 還對外提供易用實時平臺,開發者可以在平臺上構建各種 AR 和 VR 互動體驗。
2.Unity 在中國
2022年8月9日,Unity宣布已與合作伙伴達成協議并成立合資企業——Unity中國,阿里巴巴、中國移動、佳都科技以及抖音集團等將參與投資該合資公司,Unity中國的投后估值為10億美元。
3.Unity 發展史(核心部分)
2004年:Unity誕生在荷蘭的阿姆特丹。
2005年:Unity在舊金山設立了自己的總部,并且在此時發布了Unity 1.0版本(應用于WEB項目和VR開發)。
2008年:Unity引擎這個時候可以在Windows平臺開發,并且支持IOS和WII。
2009年:Unity注冊用戶高達3.5萬,在這個時候它在眾多游戲引擎中脫穎而出。
2010年:Unity可以應用在android平臺開發。
2011年:Unity可以支持PS3和XBOX360。
2013年,Unity全球用戶已經超過150萬,全新版本的Unity4.0引擎已經能夠支持包括MAC OS X、安卓、IOS、Windows等在內的十個平臺發布。
2016年7月14日:Unity宣布融資1.81億美元,此輪融資也讓Unity公司的估值達到15億美元左右。
2019年全球最具創新力企業TOP50中,Unity Technologies排名第18 ;
2020年5月9日:Unity宣布收購加拿大技術服務公司Finger Food,拓展工業應用版圖。
2020年6月15日:Unity宣布和騰訊云合作推出Unity游戲云,從在線游戲服務、多人聯網服務和開發者服務三個層次打造一站式聯網游戲開發。
2021年:Unity先后收購3D數據處理軟件Pixyz、植被和自然環境生成軟件SpeedTree、遠程桌面和流媒體供應商Parsec、人工智能音頻聊天分析平臺Oto、影視特效公司Weta Digital等業內主流開發商。
2022年1月24日:Unity宣布收購Ziva Dynamics,后者的核心技術是通過模仿肌肉、脂肪和皮膚等軟組織的物理性質,創造出最逼真的3D角色動態。
2022年8月9日:Unity宣布已與合作伙伴達成協議并成立合資企業——Unity中國,阿里巴巴、中國移動、吉比特、米哈游、OPPO、佳都科技和抖音集團等將參與投資該合資公司,Unity中國的投后估值為10億美元。
2022年8月10日:Unity公開宣布拒絕業內同行 AppLovin的收購要約。
目錄
在這樣的大環境下,傳統的通過配置文件、數據庫等方式已經越來越無法滿足開發人員對配置管理的需求。
配置中心應運而生,目前配置中心有
為什么選擇Apollo?下面是一個對比表
幾個配置中心在功能上的對比
功能點 | 優先級 | spring-cloud-config | ctrip apollo | disconf | 備注 |
靜態配置管理 | 高 | 基于file | 支持 | 支持 | |
動態配置管理 | 高 | 支持 | 支持 | 支持 | |
統一管理 | 高 | 無,需要github | 支持 | 支持 | |
多環境 | 中 | 無,需要github | 支持 | 支持 | |
本地配置緩存 | 高 | 無 | 支持 | 支持 | |
配置鎖 | 中 | 支持 | 不支持 | 不支持 | 不允許動態及遠程更新 |
配置校驗 | 中 | 無 | 無 | 無 | 如:ip地址校驗,配置 |
配置生效時間 | 重啟生效,或手動refresh生效 | 實時 | 實時 | 需要結合熱加載管理, springcloudconfig需要 git webhook+rabbitmq 實時生效 | |
配置更新推送 | 高 | 需要手工觸發 | 支持 | 支持 | |
配置定時拉取 | 高 | 無 | 支持 | 配置更新目前依賴事件驅動, client重啟或者server端推送操作 | |
用戶權限管理 | 中 | 無,需要github | 支持 | 支持 | 現階段可以人工處理 |
授權、審核、審計 | 中 | 無,需要github | 支持 | 無 | 現階段可以人工處理 |
配置版本管理 | 高 | Git做版本管理 | 界面上直接提供發布歷史和回滾按鈕 | 操作記錄有落數據庫,但無查詢接口 | |
配置合規檢測 | 高 | 不支持 | 支持(但還需完善) | ||
實例配置監控 | 高 | 需要結合springadmin | 支持 | 支持,可以查看每個配置在哪些機器上加載 | |
灰度發布 | 中 | 不支持 | 支持 | 不支持部分更新 | 現階段可以人工處理 |
告警通知 | 中 | 不支持 | 支持,郵件方式告警 | 支持,郵件方式告警 | |
依賴關系 | 高 | 不支持 | 不支持 | 不支持 | 配置與系統版本的依賴系統運行時的依賴關系 |
幾個配置中心和其他開發框架的對比
功能點 | 優先級 | spring-cloud-config | ctrip apollo | disconf |
SpringBoot支持 | 高 | 原生支持 | 支持 | 與spring boot無相關 |
SpringCloud支持 | 高 | 原生支持 | 支持 | 與spring cloud無相關 |
客戶端支持 | 低 | Java | Java、.Net | java |
業務系統侵入性 | 高 | 侵入性弱 | 侵入性弱 | 侵入性弱,支持注解及xml方式 |
依賴組件 | 高 | Eureka | Eureka | zookeeper |
功能點 | 優先級 | spring-cloud-config | ctrip apollo | disconf |
單點故障(SPOF) | 高 | 支持HA部署 | 支持HA部署 | 支持HA部署,高可用由zookeeper保證 |
多數據中心部署 | 高 | 支持 | 支持 | 支持 |
配置獲取性能 | 高 | unkown | unkown(官方說比spring快) | |
配置界面 | 中 | 無,需要通過git操作 | 統一界面(ng編寫) | 統一界面 |
綜上,ctrip applo是較好的選擇方案,最終選擇applo。
搭建之前,我們需要了解一下Apollo的設計思想,不至于搭建的時候像一個無頭蒼蠅
既然定位是配置中心,那么直接作用的對象就是應用(Application),應用又可以在幾個維度來觀察
比如運行環境(Environment),開發、測試和生產不同環境的同一個應用的配置是不一樣的
比如機房,或者叫做集群(Cluster),上海機房和北京機房的同一個應用配置也是不同的
比如配置的歸類,某些配置是一些共性應用都需要的,可以集中管理起來,這叫做命名空間(Namespace)
說白了這些概念都是對應用的配置做隔離或者復用!
這是最簡單的一個架構,Apollo 分為AdminService、Portal、ConfigService與Client
V1版架構有一個問題,假設ConfigService掛了,那么客戶端的配置就得不到更新,這個問題可以通過部署多個無狀態的ConfigService來解決,但是引入了多個ConfigService服務發現就成為了一個新問題,客戶端怎么才能知道當前有哪些ConfigService,它們的IP是多少?所以引入了注冊中心Eureka!這樣客戶端就可以去Eureka獲取服務列表!
為啥選擇Eureka?作者給了回答
為什么我們采用Eureka作為服務注冊中心,而不是使用傳統的zk、etcd呢?我大致總結了一下,有以下幾方面的原因:
它提供了完整的Service Registry和Service Discovery實現首先是提供了完整的實現,并且也經受住了Netflix自己的生產環境考驗,相對使用起來會比較省心。和Spring Cloud無縫集成我們的項目本身就使用了Spring Cloud和Spring Boot,同時Spring Cloud還有一套非常完善的開源代碼來整合Eureka,所以使用起來非常方便。另外,Eureka還支持在我們應用自身的容器中啟動,也就是說我們的應用啟動完之后,既充當了Eureka的角色,同時也是服務的提供者。這樣就極大的提高了服務的可用性。這一點是我們選擇Eureka而不是zk、etcd等的主要原因,為了提高配置中心的可用性和降低部署復雜度,我們需要盡可能地減少外部依賴。Open Source最后一點是開源,由于代碼是開源的,所以非常便于我們了解它的實現原理和排查問題。
V2版引入了一個新問題,Eureka是只支持Java客戶端的,那么.NET咋辦?因為攜程一些服務是.NET的,需要考慮了.NET的接入,所以增加了一個MetaServer的角色屏蔽掉,通過HTTP的方式獲取服務列表,還可以增加一個網關用于負載均衡,這樣只用訪問網關就可以了,如下圖
實際上,MetaServer和Eureka在Apollo中都集成在ConfigService中,跑在同一個JVM進程上,端口也是同一個,后面搭建的時候就需要關心到這一點!
采用docker搭建
docker run --name apl-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.24
查看下IP,此處是172.17.0.2
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' apl-mysql
以下操作是在容器內操作,登錄MySQL,給數據庫用戶授權下
grant all privileges on *.* to root@"%" identified by "123456";
導入SQL
登錄MySQL命令行,用source命令導入即可
docker run -dit --name apl-java --privileged centos /usr/sbin/init
查看下IP,此處是172.17.0.3
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' apl-java
以下是在容器內操作,安裝常用軟件工具
yum install -y wget unzip
安裝java環境
yum -y install java-1.8.0-openjdk java-1.8.0-openjdk-devel which
cat > /etc/profile.d/java8.sh <<EOF
export JAVA_HOME=$(dirname $(dirname $(readlink $(readlink $(which javac)))))
export PATH=\$PATH:\$JAVA_HOME/bin
export CLASSPATH=.:\$JAVA_HOME/jre/lib:\$JAVA_HOME/lib:\$JAVA_HOME/lib/tools.jar
EOF
source /etc/profile.d/java8.sh
去github發布頁下載包:https://github.com/ctripcorp/apollo/releases,當前最新版本是1.8.1,我們需要的文件為
下載好解壓到你喜歡的文件夾即可,然后開始配置數據庫
vi config/application-github.properties
注意要把SSL關閉,否則可能連不上MySQL
spring.datasource.url=jdbc:mysql://172.17.0.2:3306/ApolloConfigDB?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
啟動ConfigService,執行命令腳本,主要要在解壓后的當前目錄下,其他幾個也是
./scripts/startup.sh
啟動日志文件在:/opt/logs/100003171/apollo-configservice.log,中間的數字可能不一樣,以實際為準
啟動成功后默認跑在8080端口,打開瀏覽器看一下是否能訪問注冊中心
提示:
由于是在容器里面,容器的端口不一定能被外部訪問到,可以添加iptables DNAT規則
iptables -t nat -A DOCKER -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.3:8080
這句話的意思就是把172.17.0.3:8080端口和宿主機的8080端口映射起來,這樣在外部才能訪問,需要刪除此條規則可以將-A換成-D即可
可以看到ConfigService已經注冊好了
vi config/application-github.properties
啟動AdminService,執行命令腳本,主要要在解壓后的當前目錄下,其他幾個也是
./scripts/startup.sh
啟動成功后默認跑在8090端口,可以在Eureka看到
vi config/application-github.properties
注意,Portal需要配置環境,文件位置在:config/apollo-env.properties,我們就配個開發環境,指向Eureka(上面解釋過ConfigService和Eureka在一個JVM進程上),其他注釋掉即可
#local.meta=http://localhost:8080
dev.meta=http://172.17.0.3:8080
#fat.meta=http://fill-in-fat-meta-server:8080
#uat.meta=http://fill-in-uat-meta-server:8080
#lpt.meta=${lpt_meta}
#pro.meta=http://fill-in-pro-meta-server:8080
這里解釋下這個環境是什么意思,一個Portal可以管理多套環境,此處我們設置dev.meta標識這是開發環境。
環境的標識通過以下幾種方式(針對客戶端而言)
Environment可以通過以下3種方式的任意一個配置:
通過Java System Property可以通過Java的System Property env來指定環境在Java程序啟動腳本中,可以指定-Denv=YOUR-ENVIRONMENT如果是運行jar文件,需要注意格式是java -Denv=YOUR-ENVIRONMENT -jar xxx.jar注意key為全小寫通過操作系統的System Environment還可以通過操作系統的System Environment ENV來指定注意key為全大寫通過配置文件最后一個推薦的方式是通過配置文件來指定env=YOUR-ENVIRONMENT對于Mac/Linux,文件位置為/opt/settings/server.properties對于Windows,文件位置為C:\opt\settings\server.properties
文件內容形如:
env=DEV
目前,env支持以下幾個值(大小寫不敏感):
DEVDevelopment environmentFATFeature Acceptance Test environmentUATUser Acceptance Test environmentPROProduction environment
啟動AdminService,執行命令腳本,主要要在解壓后的當前目錄下,其他幾個也是
./scripts/startup.sh
啟動成功后默認跑在8070端口,同樣訪問不了指定下DNAT規則
iptables -t nat -A DOCKER -p tcp --dport 8070 -j DNAT --to-destination 172.17.0.3:8070
訪問http://{虛擬機IP}:8070,默認登錄用戶名為apollo,密碼為admin
此處以Java客戶端為例,需要引入Apollo Client依賴(以Maven構建)
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.1.0</version>
</dependency>`
這兩個指定的配置文件為/META-INF/app.properties
一個最簡單的Apollo客戶端如下
文末有代碼清單
將項目打包并執行,注意設置環境為DEV
mkdir -p /opt/settings/
echo 'env=DEV' > /opt/settings/server.properties
然后訪問一下
curl 'http://127.0.0.1:9000/apollo/getConfig'
值默認為default,下面我們通過Apollo,看這個值會不會動態改變
登錄Portal,新增一個應用,注意AppId要和配置的一樣
點擊提交后,進入剛才新建的應用,有一個默認的application的命名空間,然后點擊右邊新增配置,新增一個
點擊提交后再點擊發布
再訪問一下
curl 'http://127.0.0.1:9000/apollo/getConfig'
如果返回的是測試變量說明動態更改成功!
再看看SpringBoot的日志
也打印出了相關提示
@RestController
public class ApolloController {
//冒號后面的是默認值
@Value("${configValue:default}")
private String configValue;
@RequestMapping("/apollo/getConfig")
public String getConfig() {
return configValue;
}
}
@SpringBootApplication
//開啟apollo配置
@EnableApolloConfig
public class SpringBootApolloClientApplication {
private static Logger logger=LoggerFactory.getLogger(SpringBootApolloClientApplication.class);
public static void main(String[] args) {
SpringApplication.run(SpringBootApolloClientApplication.class, args);
logger.info("=============================="+ SpringBootApolloClientApplication.class.getSimpleName()+" started==============================");
}
}
# 應用的唯一標識,后面創建工程需要用到
app.id=apollo-demo
apollo.meta=http://172.17.0.3:8080
server:
port: 9000
spring:
application:
name: springboot-apollo-client
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.scriptwang</groupId>
<artifactId>springboot-apollo-client</artifactId>
<version>1.0-SNAPSHOT</version>
<!--spring boot parent 最小依賴(parent)-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
</parent>
<dependencies>
<!--最小依賴(Spring MVC Tomcat等)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>